Update 2024-08-29: Rolling over a certificate in Sympl doesn’t seem to work without also changing the set name, so I have updated the
deploy-cert
script to rename the set on each renewal. I’ve also added a section to remind you to automate the renewal with cron.
Based heavily on the SSL setup in my forgejo instructions (coming soon), these instructions should setup Sympl.io with DNS-based SSL certificates. This is useful for servers behind a firewall, such as a corporate network or homelab, where LetsEncrypt can’t do http-based domain validation.
Sympl doesn’t currently support DNS-based domain validation for SSL out of the box, so I’m using Dehydrated to validate and generate the SSL certificates, which are then manually installed into Sympl afterwards.
Generating SSL certificates
First setup Dehydrated to fetch SSL certificates with DNS validation using most of MythicBeasts’ guide, but read the whole of this section first as we skip some of their steps.
While it should be simple for dehydrated
to handle both certificate generation, and the reloading of the apache2 service through sympl, we need another library to enable having multiple hook scripts.
MythicBeasts’s documentation, above, configures the HOOK
ENV variable to point to their script, however we need both their DNS script and our sympl reloading scripts.
- Follow their guide up until the
HOOK
andHOOK_CHAIN
setup steps - Skip the
HOOK
andHOOK_CHAIN
setup in their documentation (you do need to setupCHALLENGETYPE
as per their guide). - Run the script below
- Then continue their docs.
Setup the ability to stack multiple hooks in dehydrated
cd /etc/dehydrated
git clone https://github.com/mythic-beasts/dehydrated-code-rack.git
for d in common clean-challenge deploy-challenge; do
mkdir -p /etc/dehydrated/hooks/$d
ln -s /etc/dehydrated/dehydrated-mythic-dns01/$d/mythic-dns01 /etc/dehydrated/hooks/$d
done
mkdir -p /etc/dehydrated/hooks/deploy-cert
ln -s /etc/dehydrated/dehydrated-code-rack/code-rack /etc/dehydrated/hooks/code-rack
ln -s /etc/dehydrated/dehydrated-code-rack/code-rack.sh /etc/dehydrated/conf.d/code-rack.sh
cd /etc/dehydrated
(inspired by the instructions at the bottom of https://github.com/mythic-beasts/dehydrated-mythic-dns01)
Also, because the current version of sympl-ssl
only supports RSA private keys, we need to configure dehydrated to only generate RSA keys.
cat > /etc/dehydrated/conf.d/sympl-ssl.sh <<EOF
# sympl-ssl doesn't support `KEY_ALGO=secp384r1`
# Supported: rsa, prime256v1 and secp384r1
# https://github.com/dehydrated-io/dehydrated/blob/master/docs/examples/config
KEY_ALGO=rsa
EOF
You can now test the certificate generation works by running dehydrated -c
. It will output something like:
# INFO: Using main config file /etc/dehydrated/config
# INFO: Using additional config file /etc/dehydrated/conf.d/code-rack.sh
# INFO: Using additional config file /etc/dehydrated/conf.d/hook.sh
# INFO: Using additional config file /etc/dehydrated/conf.d/mail.sh
# INFO: Using additional config file /etc/dehydrated/conf.d/sympl-ssl.sh
Unknown hook: this_hookscript_is_broken__dehydrated_is_working_fine__please_ignore_unknown_hooks_in_your_script
Processing example.com with alternative names: www.example.com
Unknown hook: this_hookscript_is_broken__dehydrated_is_working_fine__please_ignore_unknown_hooks_in_your_script
+ Signing domains...
+ Generating private key...
+ Generating signing request...
+ Requesting new certificate order from CA...
+ Received 2 authorizations URLs from the CA
+ Handling authorization for example.com
+ Found valid authorization for example.com
+ Handling authorization for www.example.com
+ Found valid authorization for www.example.com
+ 0 pending challenge(s)
+ Requesting certificate...
+ Checking certificate...
+ Done!
+ Creating fullchain.pem...
+ Done!
Automate SSL certificate installation into Sympl
Once you’ve got certificates being correctly issues with DNS-based validation, it’s time to move on to integrating them into Sympl.
We’ll setup sympl-ssl
to install the certificate manually upon renewal
cat > /etc/dehydrated/hooks/deploy-cert/sympl <<EOF
#!/bin/sh
echo 'false' > /srv/\$DOMAIN/config/ssl-provider
SET_NAME=dehydrated-\$(date --rfc-3339=date)
mkdir -p /srv/\$DOMAIN/config/ssl/sets/\$SET_NAME
cat "\${CERTFILE}" > /srv/\$DOMAIN/config/ssl/sets/\$SET_NAME/ssl.crt
cat "\${CHAINFILE}" > /srv/\$DOMAIN/config/ssl/sets/\$SET_NAME/ssl.bundle
cat "\${KEYFILE}" > /srv/\$DOMAIN/config/ssl/sets/\$SET_NAME/ssl.key
cat "\${FULLCHAINFILE}" "\${KEYFILE}" > /srv/\$DOMAIN/config/ssl/sets/\$SET_NAME/ssl.combined
sympl-ssl \$DOMAIN --verbose --select \$SET_NAME
EOF
chmod 0700 /etc/dehydrated/hooks/deploy-cert/sympl
Note, rolling over a certificate in sympl doesn’t seem to work without also changing the set name. I have updated the scripts above to rename the set on each renewal
Also, it is normal that Sympl doesn’t currently clear out old SSL certificate sets. They are small enough that they can safely be ignored in almost all hosting environments. This may be addressed in a future version of Sympl.
You can test this deployment script works by forcefully renewing the certificates (though bear in mind LetsEncrypt rate limits you if you do this a lot, see the note below) with dehydrated -c -x
(where -x
is force renew).
You’ll notice this extra section near the end of the dehydrated command output showing sympl now selecting and successfully activating these certificates.
...
Certificate sets for example.com:
SSL set dehydrated-2024-04-29: signed by /C=US/O=Let's Encrypt/CN=R11, expires 2024-07-29 18:10:22 UTC
No current SSL set
Rolling over from set no set to dehydrated-2024-04-29
Rolled over to SSL set dehydrated-2024-04-29
Current SSL set now: dehydrated-2024-04-29
If you have any problems and need to run this multiple times to debug, or want to alter the scripts and need to test them, make sure you add
--ca letsencrypt-test
to the dehydrated command, or change your config, to use the Staging LetsEncrypt servers so you avoid hitting the rate limits. Be aware that any certificates from the staging servers are not trusted, thus no good for using on the web, so change your config back and force renew one last time once you’re happy the scripts work.
Check and renew certificates daily
Now you need add dehydrated to cron so that it automatically checks and renews your certificates before they expire.
cat > /etc/cron.daily/dehydrated <<EOF
#!/bin/sh
exec /usr/bin/dehydrated -c >> /var/log/dehydrated-cron.log 2>&1
EOF
chmod 0755 /etc/cron.daily/dehydrated
cat > /etc/logrotate.d/dehydrated <<EOF
/var/log/dehydrated-cron.log
{
rotate 12
monthly
missingok
notifempty
delaycompress
compress
}
EOF
You can safely run this every day even through the certificates don’t need to be updated more than once every 3 months. Dehydrated will check the expiry date of the existing certificate and skip any which don’t need renewing yet, so run this check regularly. If there is an issue with renewing or a revocation of one of your existing certificates, such as a LetsEncrypt incident or outage, this ensures there are plenty of renewal attempts left before the existing certificates expire.