Skip to content

Instantly share code, notes, and snippets.

@broedli
Last active December 20, 2021 14:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save broedli/11ab45860fb10b31a94934e82bea2c25 to your computer and use it in GitHub Desktop.
Save broedli/11ab45860fb10b31a94934e82bea2c25 to your computer and use it in GitHub Desktop.
tut on dehydrated

Installing dehydrated for Let's Encrypt certificates

This tutorial will show you how to install the Let's Encrypt ACME client dehydrated.

Installing dehydrated

To install dehydrated we simply clone it's repository:

git clone https://github.com/lukas2511/dehydrated.git /opt/dehydrated

Since dehydrated will be looking for it's config file in /etc/dehydrated we should copy the provided examples to this location:

mkdir /etc/dehydrated
cp /opt/dehydrated/docs/examples/{config,domains.txt} /etc/dehydrated

I would advise to creating a symling to /usr/local/sbin/dehydrated since it makes it easier to call dehydrated in your shell or cronjob.

Configure dehydrated

In the /etc/dehydrated/config we may provide our default configuration for a simple(r) call of dehydrated. (i.e. dehydrated --cron instead of dehydrated --domain domain1.tld --domain domain2.tld --hook /path/to/your/hook ...)

The example config of dehydrated comes with lot's of comments so it actually should be self explanatory. But never the less here are some configuration settings that might be helpful:

  • CA="": There are two possible options for this one. The first is the production CA (https://acme-v01.api.letsencrypt.org/directory) which provides you with a trusted / valid certificate but is subject to rate limits.

    The second one (https://acme-staging.api.letsencrypt.org/directory) is for testing purposes and doesn't provide a trusted / valid certificate but isn't subject to the rate limits mentioned above.

    You should use the acme-staging CA until you are certain that your setup is correct!

  • CHALLENGETYPE="": There are currently two types of challenge types. The first one is dns-01, it gives you the option to verify ownership of a domain via DNS entries. Some DNS providers provide API's which could be used. The second one would be http-01 which provides the challenge inside of the webroot directory of an already running webserver.

  • CERTDIR="": If you want your certificates to be in a specific path you may provide it here. The default would create a directory called certs inside of /etc/dehydrated.

  • HOOK="": Hooks are used to perform certain actions throughout the process of acquiring certificates. For example you would probably want one if you want to use the dns-01 method but this could also be handy to perform certain actions on i.e. a failed renewal or a successfull renewal like sending a mail and / or restarting certain services, linking or copying the cert to a certain folder, etc. For more details you may take a look at the provided example in /opt/dehydrated/docs/examples/hook.sh.

    Please be aware, that dehydrated only allows for one (!) hook to be called.

Domains.txt

If you want to acquire multiple certificates and / or a certificate with multiple SAN you may use the domains.txt inside of /etc/dehydrated. This file may also be defined in your config file via DOMAINS_TXT="". Every line in this file represents a single certificate and may contain multiple (sub-)domains:

# This will create a certificate for multiple domains:
domain1.tld sub.domain1.tld domain2.tld sub.domain2.tld ...
# This will create a certificate for a single domain:
domain3.tld

In a mailcow context, what domains do I need a certificate for?

  • You should get a certificate for the hostname (fqdn) your postfix instance runs on.
  • If you want your clients to connect to hostnames like imap.domain1.tld, smtp.domain1.tld, ... you should include those in the same certificate.
  • If your MX records differ from your hostname (i.e. mx.domain1.tld) you need to include those as well.
  • If you want to provide a seperate (sub-)domain to serve your webmail instance you may include those as well. Though this is not needed, since you can specify a different certificate and key pair for each VHOST.

Webchallenge (http-01)

With the http-01 challenge type the ACME-protocol is checking if you are in control of a domain by accessing a verification file (token) on an URL similar to http://domain1.tld/.well-known/acme-challenge/some-token. This will be done for every domain specified in your domains.txt or inside the command (dehydrated ... --domain domain1.tld ...)

NOTE: The DNS A record for each (sub-)domain in domains.txt must point to the server you are running dehydrated on!

Dehydrated provides this token to the path specified in the config variable WELLKNOWN="". The default in dehydrated is /var/www/dehydrated, so we need to create this directory:

mkdir /var/www/dehydrated

Now we need to configure our webserver to serve requests to http://domain1.tld/.well-kown/acme-challenge/....

Nginx example:

server {
[...]
    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/dehydrated/;
        default_type text/plain;
    }
[...]
}

Apache example:

Alias /.well-known/acme-challenge /var/www/dehydrated
<Directory /var/www/dehydrated>
        Options None
        AllowOverride None
        # Apache 2.x
        <IfModule !mod_authz_core.c>
                Order allow,deny
                Allow from all
        </IfModule>
        # Apache 2.4
        <IfModule mod_authz_core.c>
                Require all granted
        </IfModule>
</Directory>

NOTE: Don't forget to restart your webserver after you configured your VHOSTs.

DNS Challenge (dns-01)

For this type of verification you'll need a hook, that supports your DNS provider and deploys the challenges automatically via API calls. (For a not complete list of available hooks have a look here.)

If your DNS provider has no API support you could do this manually by creating or using a manual hook, which prints the challenges into your shell so you can update the records manually. The records should look something like this:

# For domain1.tld
_acme-challenge IN TXT <YOUR_TOKEN>
# For sub.domain.tld
_acme-challenge.sub IN TXT <YOUR_TOKEN>

First run of dehydrated

Now that we have configured everything we're set to run the command for the first time. This will create your account with Let's Encrypt, generate a private key and create all the certificates with their respective keys specified in your domains.txt.

dehydrated -c

Certificates

When the command completed successfull you should find your certificates and keys in the path defined in your config under CERTDIR="". The default would be /etc/dehydrated/certs/<DOMAIN1.TLD>/fullchain.pem and /etc/dehydrated/certs/<DOMAIN1.TLD/privkey.pem. Where <DOMAIN1.TLD> is always the first entry of every line in your domains.txt.

Renewal

Since Let's Encrypt only provides us with a certificate that is valid for 90 days we need to setup a CRON job that renews our certificates automaticly. Let's Encrypt allows a renewal 30 days before a certificate expires, so it should be sufficient to call our CRON job once a week:

crontab -e
@weekly dehydrated -c && systemctl reload nginx.service && systemctl restart postfix.service && systemctl restart dovecot.service
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment