SSL/TLS Certificates§
The /certificates
section of the
control API
handles TLS certificates that are used with Unit’s
listeners.
To set up SSL/TLS for a listener,
upload a .pem
file with your certificate chain and private key to Unit
and name the uploaded bundle in the listener’s configuration;
next, the listener can be accessed via SSL/TLS.
Note
For the details of certificate issuance and renewal in Unit, see an example in TLS with Certbot.
First, create a .pem
file with your certificate chain and private key:
$ cat cert.pem ca.pem key.pem > bundle.pem
Usually, your website’s certificate (optionally followed by the intermediate CA certificate) is enough to build a certificate chain. If you add more certificates to your chain, order them leaf to root.
Upload the resulting bundle file to Unit’s certificate storage
under a suitable name
(in this case, bundle
):
# curl -X PUT --data-binary @bundle.pem --unix-socket \
/path/to/control.unit.sock http://localhost/certificates/bundle
{
"success": "Certificate chain uploaded."
}
Warning
Don’t use -d
for file upload with curl;
this option damages .pem
files.
Use the --data-binary
option
when uploading file-based data
to avoid data corruption.
Internally, Unit stores the uploaded certificate bundles
along with other configuration data
in its state
subdirectory;
the
control API
exposes some of their properties
as GET
-table JSON via /certificates
:
{
"certificates": {
"bundle": {
"key": "RSA (4096 bits)",
"chain": [
{
"subject": {
"common_name": "example.com",
"alt_names": [
"example.com",
"www.example.com"
],
"country": "US",
"state_or_province": "CA",
"organization": "Acme, Inc."
},
"issuer": {
"common_name": "intermediate.ca.example.com",
"country": "US",
"state_or_province": "CA",
"organization": "Acme Certification Authority"
},
"validity": {
"since": "Sep 18 19:46:19 2022 GMT",
"until": "Jun 15 19:46:19 2025 GMT"
}
},
{
"subject": {
"common_name": "intermediate.ca.example.com",
"country": "US",
"state_or_province": "CA",
"organization": "Acme Certification Authority"
},
"issuer": {
"common_name": "root.ca.example.com",
"country": "US",
"state_or_province": "CA",
"organization": "Acme Root Certification Authority"
},
"validity": {
"since": "Feb 22 22:45:55 2023 GMT",
"until": "Feb 21 22:45:55 2026 GMT"
}
}
]
}
}
}
Note
Access array items, such as individual certificates in a chain, and their properties by indexing:
# curl -X GET --unix-socket /path/to/control.unit.sock \
http://localhost/certificates/bundle/chain/0/
# curl -X GET --unix-socket /path/to/control.unit.sock \
http://localhost/certificates/bundle/chain/0/subject/alt_names/0/
Next, add the uploaded bundle to a listener; the resulting control API configuration may look like this:
{
"certificates": {
"bundle": {
"key": "<key type>",
"chain": [
"<certificate chain, omitted for brevity>"
]
}
},
"config": {
"listeners": {
"*:443": {
"pass": "applications/wsgi-app",
"tls": {
"certificate": "bundle"
}
}
},
"applications": {
"wsgi-app": {
"type": "python",
"module": "wsgi",
"path": "/usr/www/wsgi-app/"
}
}
}
}
All done; the application is now accessible via SSL/TLS:
$ curl -v https://127.0.0.1
...
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / AES256-GCM-SHA384
...
Finally, you can DELETE
a certificate bundle
that you don’t need anymore
from the storage:
# curl -X DELETE --unix-socket /path/to/control.unit.sock \
http://localhost/certificates/bundle
{
"success": "Certificate deleted."
}
Note
You can’t delete certificate bundles still referenced in your
configuration, overwrite existing bundles using PUT
, or (obviously)
delete non-existent ones.