dehydrated, nginx and letsencrypt

dehydrated is a letsencrypt/ACME client implementation in currently about 2500 lines of bash code. It’s relatively easy on the dependencies and should run on most Linux systems out of the box. It provides a easy and huzzle-free alternative to certbot for automatic certificate retrieval on ACME servers, e.g. letsencrypt. In this tutorial I’m giving you a quickstart guide on how you can use dehydrated to setup a letsencrypt certificate for your own webserver.

This tutorial works on a openSUSE Linux server (Leap or Tumbleweed and derivatives) and assumes you are using the nginx webserver. It should be relatively simple though to adjust to other webservers e.g. apache2 or lighthttpd.

Installation

 zypper in dehydrated

Yes, it’s that simple. dehydrated comes with the actual script, configuration files in /etc/dehydrated and a handy systemd service timer, the dehydrated.timer for automatic certification renewal.

Configuration

To get letsencrypt running you need to do three things:

  1. Add your domain to /etc/dehydrated/domains.txt

This is really just a text file containing all of your domains, one domain per line.

  1. Optional: Adjust the configuration in /etc/dehydrated.config to your needs

But the defaults should already work out of the box. I recommend to set CA="letsencrypt-test" before going in production to check the configuration first.

  1. Add the challenge directory to your nginx configuration, e.g.
server {
	listen 80;
	listen [::]:80;
	server_name my-awesome-dehydrated.server;
	
	location /.well-known/acme-challenge {
		alias /var/lib/acme-challenge;
	}
	
	...
}

That’s it. Now you should be ready to go!

Running dehydrated / Obtaining your certificates

First display, read and accept the TOS:

# dehydrated --display-terms
# dehydrated --register --accept-terms

And then run dehydrated to create new certificated

# dehydrated --cron

This should create your certificates in domain subfolders located in /etc/dehydrated/certs/, e.g.

/etc/dehydrated/certs/feldspaten.org/
├── cert.csr
├── cert.pem
├── chain.pem
├── fullchain.pem
└── privkey.pem
...

Configure nginx to use the certificates

As last step AFTER you were able to obtain the certificates is to configure nginx to use those certificates for a tls connection.

As first optional step, I want to ensure that only secure ciphers are used by defining a common tls options file in /etc/nginx/options-tls-nginx.conf. This is similar to the approach that cert-bot is doing. Here is my current file as template:

# /etc/nginx/options-ssl-nginx.conf
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;

ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

Next, also as optional step, is to generate Diffie-Hellman parameters for additional security on your tls connections. /etc/nginx/dhparam.pem appears to me as a good location and I create them with 4096 bits. 2048 is fine too, but don’t go lower:

openssl dhparam -out /etc/nginx/dhparam.pem 4096            # this might take a bit
chmod 0400 /etc/nginx/dhparam.pem                           # ensure nobody else can access them

Finally we add the following instructions to our server block in the nginx virtual hosts file to enable tls:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl ipv6only=on http2;
    server_name m1.feldspaten.org;
    
    ssl_certificate /etc/dehydrated/certs/feldspaten.org/fullchain.pem;
    ssl_certificate_key /etc/dehydrated/certs/feldspaten.org/privkey.pem;
    include /etc/nginx/options-tls-nginx.conf;        # optional but recommended
    ssl_dhparam /etc/nginx/dhparam.pem;               # optional but recommended
    
    ...
}

Now, check if the configuration is ok, and if so, restart/reload your nginx server and you’re good to go:

# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# systemctl restart nginx

Enable certificate auto-update

To enable the automatic update of your certificates, simply use the dehydrated.timer timer:

systemctl enable --now dehydrated.timer

Check if everything is alright:

# systemctl status dehydrated.timer 
● dehydrated.timer - Run Certificate Update Runner for Dehydrated
     Loaded: loaded (/usr/lib/systemd/system/dehydrated.timer; enabled; vendor preset: disabled)
     Active: active (waiting) since Thu 2022-06-30 09:01:32 CEST; 1 day 1h ago
    Trigger: Sat 2022-07-02 00:59:15 CEST; 14h left
   Triggers: ● dehydrated.service

And you’re good to go.


Congratulations! You have your letsencrypt certificate process setup and automated using dehydrated and you’re awesome 🚀