NGINX Unit
v. 1.20.0

TLS with Certbot§

To set up SSL/TLS access in Unit, you need certificate bundles. Although you can use self-signed certificates, it’s generally advisable to obtain certificates for your website from a certificate authority (CA). For this purpose, you may employ EFF’s Certbot that issues free certificates signed by Let’s Encrypt, a non-profit CA.

Generating Certificates§

  1. Install Unit on your website’s server.

  2. Install Certbot on the same server, choosing None of the above in the Software dropdown list and the server’s OS in the System dropdown list at EFF’s website.

  3. Run certbot and follow its instructions to generate the certificate bundle. You will be prompted to enter the domain name of the website and validate domain ownership; the latter can be done differently.

    To use a temporary server for authentication, stop any process listening on port 80 and run:

    # certbot certonly --standalone
    

    After the certificate bundle is successfully saved, restart the process that was listening on port 80.

    If you can’t run the temporary server for some reason, use DNS records to validate your domain:

    # certbot certonly --manual --preferred-challenges dns
    

    Note

    You must be able to edit the server’s DNS entries to use the second method. Certbot offers other domain validation methods (authenticators) as well, but they’re not discussed here for brevity.

    Both commands above store the resulting .pem files as follows:

    /etc/letsencrypt/
    └── live/
        └── www.example.com
            ├── cert.pem
            ├── chain.pem
            ├── fullchain.pem
            └── privkey.pem
    
  4. Create a certificate bundle fit for Unit and upload it to the certificates section of Unit’s control API:

    # cat /etc/letsencrypt/live/www.example.com/fullchain.pem  \
          /etc/letsencrypt/live/www.example.com/privkey.pem > bundle1.pem
    
    # curl -X PUT --data-binary @bundle1.pem --unix-socket  \
           /path/to/control.unit.sock  \
           http://localhost/certificates/certbot1
    
           {
               "success": "Certificate chain uploaded."
           }
    
  5. Create or update a listener to use the uploaded bundle in Unit:

    # curl -X PUT --data-binary  \
          '{"pass": "applications/ssl_app", "tls": {"certificate": "certbot1"}}'  \
          --unix-socket /path/to/control.unit.sock  \
          'http://localhost/config/listeners/*:443'
    
  6. Try accessing your website via HTTPS:

    $ curl https://www.example.com -v
    
          ...
          * TLSv1.3 (OUT), TLS handshake, Client hello (1):
          * TLSv1.3 (IN), TLS handshake, Server hello (2):
          * TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (IN), TLS handshake, Unknown (8):
          * TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (IN), TLS handshake, Certificate (11):
          * TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (IN), TLS handshake, CERT verify (15):
          * TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (IN), TLS handshake, Finished (20):
          * TLSv1.3 (OUT), TLS change cipher, Client hello (1):
          * TLSv1.3 (OUT), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (OUT), TLS handshake, Finished (20):
          * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
          * ALPN, server did not agree to a protocol
          * Server certificate:
          *  subject: CN=www.example.com
          *  start date: Sep 21 22:10:42 2020 GMT
          *  expire date: Dec 20 22:10:42 2020 GMT
          ...
    

Renewing Certificates§

Certbot enables renewing the certificates manually or automatically. For manual renewal and rollover:

  1. Repeat the steps above to renew the certificates and upload the new bundle under a different name:

    # certbot certonly --standalone
    
          What would you like to do?
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          1: Keep the existing certificate for now
          2: Renew & replace the cert (may be subject to CA rate limits)
    
    # cat /etc/letsencrypt/live/www.example.com/fullchain.pem  \
          /etc/letsencrypt/live/www.example.com/privkey.pem > bundle2.pem
    
    # curl -X PUT --data-binary @bundle2.pem --unix-socket  \
           /path/to/control.unit.sock  \
           http://localhost/certificates/certbot2
    
           {
               "success": "Certificate chain uploaded."
           }
    

    Now you have two certificate bundles uploaded; Unit knows them as certbot1 and certbot2. Optionally query the certificates section to review common details such as expiry dates, subjects, or issuers:

    # curl --unix-socket /path/to/control.unit.sock  \
          'http://localhost/certificates'
    
  2. Update the listener, switching it to the renewed certificate bundle:

    # curl -X PUT --data-binary 'certbot2' --unix-socket  \
          /path/to/control.unit.sock  \
          'http://localhost/config/listeners/*:443/tls/certificate'
    

    Note

    There’s no need to shut Unit down; your server can stay online during the rollover.

  3. Delete the expired bundle:

    # curl -X DELETE --unix-socket /path/to/control.unit.sock  \
          'http://localhost/certificates/certbot1'
    
          {
              "success": "Certificate deleted."
          }
    

Note

Currently, Certbot doesn’t have installer plugins that enable automatic certificate rollover in Unit. However, you can set up Certbot’s hooks using the commands above to the same effect.