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 using /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 delete non-existent ones.