If you are running servers in your private network that need SSL, you can use LetsEncrypt and Certbot to automatically obtain and renew certificates for free. Even if your machines are not accessible from the internet.

What you need:

  • A static IP in your internal network for the server, like 192.168.1.2
  • Own a domain like “example.com” In this post I assume the server is accessed using server.example.com
  • Certbot’s support for the nameserver of the domain. Even if you purchased your domain at some unupported provider, its usually no cost to change to a supported nameserver. In this post I am using Cloudflare

How to set it all up:

  1. Log in to your Cloudflare account and create an A record for ‘myserver’ with address 192.168.1.2
  2. Get a global API key from Cloudflare and remember it.
  3. Login to the private server.
  4. Create /root/.secrets/cloudflare.ini and put the following content into it:

    dns_cloudflare_email = "<mailadres of your cloudflare account>"
    dns_cloudflare_api_key = "<the api key you remembered earlier>"
    

  5. Ensure only root can read the directory and file

    sudo sudo chmod 0700 /root/.secrets/
    sudo chmod 0400 /root/.secrets/cloudflare.ini
    

  6. Install Certbot and the plugins it needs to talk to Cloudflare. For my environment this boiled down to:

    sudo apt-get install certbot -t stretch-backports
    sudo apt-get install python3-certbot-dns-cloudflare -t stretch-backports
    

  7. Tell Certbot to obtain a free certificate for server.example.com

    sudo /usr/bin/certbot certonly \
        --dns-cloudflare \
        --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
        -d server.example.com \
        --preferCed-challenges dns-01
    

  8. Voila! You now have a certificate stored in /etc/letsencrypt/live/server.example.com/fullchain.pem

Dealing with renewals:


  1. Certificates from LetsEncrypt have a short expiry time, so we need to renew it before it expires. We don’t want to have to think about doing this, we want this to be automatic. A simple crontab entry solves that.

    14 5    * * *   root    /usr/bin/certbot renew --quiet > /dev/null 2>&1
    


Doing something with the SSL Certificate:


  1. After Certbot has obtained or renewed a certificate it executes scripts located in /etc/letsencrypt/renewal-hooks/post/
    In my case I am running Ubiquity’s Unifi controller software and use this script to deal with the renewal:

    #!/bin/sh
    DOMAIN=unifi.example.com
    
    # Backup previous keystore
    cp /var/lib/unifi/keystore /var/lib/unifi/keystore.backup.$(date +%F_%R)
    
    # Convert to PKCS12 format
    openssl pkcs12 -export \
        -inkey /etc/letsencrypt/live/${DOMAIN}/privkey.pem \
        -in /etc/letsencrypt/live/${DOMAIN}/fullchain.pem \
        -out /etc/letsencrypt/live/${DOMAIN}/fullchain.p12 \
        -name unifi \
        -password pass:unifi
    
    # Install certificate
    keytool -importkeystore \
        -deststorepass aircontrolenterprise \
        -destkeypass aircontrolenterprise \
        -destkeystore /var/lib/unifi/keystore \
        -srckeystore /etc/letsencrypt/live/${DOMAIN}/fullchain.p12 \
        -srcstoretype PKCS12 \
        -srcstorepass unifi \
        -alias unifi \
        -noprompt
    
    #Restart UniFi controller
    service unifi restart