Sign nginx website and dovecot imap server on debian with let’s encrypt

If you have a setup with a single server with multiple services (web, IMAP etc.), and one CNAME per service (www.somedomain.com, imap.somedomain.com), and you would like to get the services signed in a manner that doesn’t give warnings or errors in browsers  (especially browsers in phones and tablets with iOS and Android), then this article may be of interest.

Self-signed certificates is a nuisance and the cacert.org initiative has been losing support. Let’s encrypt offers the possibility of having free (as in both cost and feedom) SSL certificates that don’t give warnings in web browsers. The only problem the threshold of taking the time to figure out how to use it.

It turned out there wasn’t much figuring to do: on a debian jessie GNU/linux system, the certbot program from eff.org takes care of everything, including keeping the certificates automatically updated (the .deb package for certbot sets up a cronjob that does the right thing).

The way certbot works is that it requires that each server you wish to sign must be accessible on http (port 80) and the local path “/.well-known/” on each server must be accessible and map to a file area that certbot can put files in.

The certbot program works by contacting let’s encrypt saying that it wants a certificate for a DNS name,  and let’s encrypt will then access the HTTP URL to verify that certbot is indeed running on a server that can be found using that DNS name.

This means that, for certbot to work:

  1. Even if your HTTP server responds only on HTTPS and/or requires authentication, you will need to make a plain HTTP connection available and have the local path “/.well-known/” map to a part of the file system, and be available without authentication
  2. Even if you’re making a certificate for a non-HTTP service (e.g. an IMAP server), you will need to make a plain http (port 80) server responding to that DNS CNAME that can serve the local parth “/.well-known/” from the local

This article explains how to set up free SSL certificates signed with let’s encrypt on an nginx web server and a dovecot IMAP server, on a debian jessie GNU/linux system.

The certbot instructions takes you part of the way, but it has some holes and not a lot of explanation, which is why I wrote this article.

The steps are:

  1. Add jessie-backports to APT (click the link and follow the instructions)
  2. Install certbot from jessie-backports:
    1. Open a command shell as root and give the following command:
      apt-get install certbot -t jessie-backports
      
  3. Disable the default nginx site
    1. Edit the /etc/nginx/sites-available/default file to have the following content:
      server {
              listen 80 default_server;
              listen [::]:80 default_server;
      
              root /var/www/html;
      
              server_name _;
      
              location / {
                      deny all;
              }
      }
      
    2. Run the following command in the command shell openes as root
      systemctl reload nginx
      
  4. Add DNS CNAME-records for the virtual hosts you are going to sign.
    In the examples used in this procedure, the host is hostname.somedomain.com and it has two CNAME aliases: http://www.somedomain.com and imap.somedomain.com.
  5. Add a http://www.mydomain.com nginx site
    1. Create a file /etc/nginx/available-sites/www with the following contents:
      server {
              listen 80;
              listen [::]:80;
      
              server_name www.mydomain.com;
      
              root /var/www/html;
      
              index index.html index.htm index.nginx-debian.html;
      
              location / {
                      allow all;
              }
      }
      
    2. Give the following commands in the command shell opened as root:
      cd /etc/nginx/enabled-sites/
      ln -s /etc/nginx/available-sites/www .
      systemctl reload nginx
      
  6. Add an imap.mydomain.com nginx site
    Note! This isn’t a real website but it is necessary to give HTTP access to a web server listening to this CNAME alias so that the certbot program can create and auto-update the certificate that dovecot uses.

    1. Create a file /etc/nginx/available-sites/imap with the following contents:
      # The port 80 listener only gives access to certbot
      server {
              listen 80;
              listen [::]:80;
      
              server_name imap.bang.priv.no;
      
              root /var/www-imap/;
      
              location /.well-known/ {
                      allow all;
              }
      
              location / {
                      deny all;
              }
      }
      
    2. Give the following commands in the command shell opened as root:
      cd /etc/nginx/enabled-sites/
      ln -s /etc/nginx/available-sites/imap .
      systemctl reload nginx
      
  7. Add a certificate for http://www.mydomain.com
    1. Give the following command in the command shell opened as root:
      certbot certonly --webroot -w /var/www/html -d www.mydomain.com
      
  8. Configure certificates for the http://www.mydomain.com nginx web site
    1. Change the /etc/nginx/available-sites/www file to the following:
      server {
              listen 80;
              listen [::]:80;
      
              server_name www.mydomain.com;
      
              # SSL configuration
              #
              listen 443 ssl default_server;
              listen [::]:443 ssl default_server;
              ssl_certificate     /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
              ssl_certificate_key /etc/letsencrypt/live/www.mydomain.com/privkey.pem;
      
              root /var/www/html;
      
              location / {
                      allow all;
              }
      }
      
    2. Give the following command in the command shell opened as root
      certbot certonly --webroot -w /var/www-imap -d imap.mydomain.com
      
    3. Open the https://www.somedomain.com server (replace with your actual URL) and observe that the browser reports it as secure with a valid certificate
  9. Add a certificate for imap.mydomain.com
    1. Give the following command in the command shell opened as root:
      certbot certonly --webroot -w /var/www-imap -d imap.mydomain.com
      
  10. Configure dovecot to use the imap.mydomain.com certificate
    1. Change/modify the following lines in the /etc/dovecot/conf.d/10-ssl.conf file:
      # SSL/TLS support: yes, no, required. 
      ssl = yes
      
      # PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
      # dropping root privileges, so keep the key file unreadable by anyone but
      # root. Included doc/mkcert.sh can be used to easily generate self-signed
      # certificate, just make sure to update the domains in dovecot-openssl.cnf
      ssl_cert = </etc/letsencrypt/live/imap.bang.priv.no/fullchain.pem
      ssl_key = </etc/letsencrypt/live/imap.bang.priv.no/privkey.pem
      
    2. Give the following command in the command shell opened as root:
      /etc/init.d/dovecot reload
      

The certificates have a 90 day lifetime, but as mentioned earlier, the certificates will be automatically updated by certbot when they have 30 days valid time remaining. The certbot deb package installs a cronjob that runs twice every day at random second in the hour following 00:00 and 12:00 and checks if certificates needs to be updated and updates the ones that are ready for updating.

One thought on “Sign nginx website and dovecot imap server on debian with let’s encrypt”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.