There are two current approaches to maintaining TLS certificates:

  1. uacme
  2. tlstunnel

Presently the latter is only used for pages.sr.ht.

uacme

The configuration we use for uacme is a fucking nightmare, but it does work and is pretty reliable. In the future it might be nice to switch to tlstunnel for everything or at least put some more work into the uacme setup.

Set up

We have a bunch of shell commands that sets up uacme on a server:

doas apk add uacme openssl moreutils
doas useradd -md /var/lib/acme -s /sbin/nologin acme
doas mkdir -p /etc/ssl/uacme/private /var/www/.well-known/acme-challenge
doas chown acme:acme /etc/ssl/uacme /etc/ssl/uacme/private
doas chmod g+rX /etc/ssl/uacme /etc/ssl/uacme/private
doas chown acme:acme /var/www/.well-known/acme-challenge
doas touch /var/log/acme.log
doas chown acme:acme /var/log/acme.log
doas vim /usr/local/bin/acme-update-certs

Contents of acme-update-certs, edit as necessary:

#!/bin/sh
exec >>/var/log/acme.log 2>&1
date

stats() {
    cert="/etc/ssl/uacme/$1/cert.pem"
    if ! [ -e "$cert" ]
    then
        return
    fi
    expiration=$(date -d"$(openssl x509 -enddate -noout -in "$cert" \
        | cut -d= -f2)" -D'%b %d %H:%M:%S %Y GMT' +'%s')
    printf '# TYPE certificate_expiration gauge\n'
    printf '# HELP certificate_expiration Timestamp when SSL certificate will expire\n'
    printf 'certificate_expiration{instance="%s"} %s\n' "$1" "$expiration"
}

acme() {
    site=$1
    shift
    /usr/bin/uacme -v -h /usr/share/uacme/uacme.sh issue $site $* || true
    stats $site | curl --data-binary @- https://push.metrics.srht.network/metrics/job/$site
}

acme DOMAIN SUBDOMAIN...
doas nginx -s reload
doas chmod +x /usr/local/bin/acme-update-certs
doas usermod -aG acme nginx
doas -u acme uacme new sir@cmpwn.com
doas -u acme crontab -e

Contents of crontab:

MAILTO=sir@cmpwn.com
0 0 * * * chronic /usr/local/bin/acme-update-certs

Then update the nginx configuration, commenting out the includes for port443.conf and *-ssl.conf.

doas -u acme /usr/local/bin/acme-update-certs
cat /var/log/acme.log

Verify that acme.log looks okay, then uncomment the relevant parts of the nginx configuration.

doas chmod -R g+rX /etc/ssl/uacme /etc/ssl/uacme/private
doas nginx -s reload
# verify TLS configuration

Note: wildcard certificates are possible with uacme, but it's a bloody nightmare so if you want this it's best to go with tlstunnel instead.

Monitoring

TLS certificate expiration and renewal is monitored by metrics.srht.network:

Graph

The acme update script pushes the expiration date to push.metrics.srht.network whenever the cronjob runs. If any certificate's expiration date falls below 1 week, the "SSL expiration" alarm is raised.

tlstunnel

tlstunnel automatically adds zero-configuration TLS to arbitrary TCP sockets using SNI and the PROXY protocol. It is currently used for pages.sr.ht.

Monitoring

Presently none; see https://todo.sr.ht/~emersion/tlstunnel/24

About this wiki

commit 96d1f5b90650f055dfc866f4d341b03bf9d20c40
Author: Rens Oliemans <hallo@rensoliemans.nl>
Date:   2025-01-15T15:05:17+01:00

git.sr.ht/index: fix hut link
Clone this wiki
https://git.sr.ht/~sircmpwn/sr.ht-docs (read-only)
git@git.sr.ht:~sircmpwn/sr.ht-docs (read/write)