Let’s Encrypt SSH

This post is based on this post “Containerized WordPress, Migration, and SSL”. I found it a hassle to install and refresh certificates every year (now it’s 90 days!).

I want to set up an automated job, which requests to a root CA and installs certs automatically.

Let’s encrypt is a free trusted CA. This post demonstrates how to integrate it with my blog.

getssl

Suggested by https://letsencrypt.org/getting-started/#with-shell-access, when website maintainers have access to shell, certbot is the recommended way to use Let’s Encrypt. However, certbot requires snap to install itself and snap requires systemd managed system. My website unfortunately is not based on systemd. Thus, I used getssl.

root@6e856df8f83c:/# cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

root@6e856df8f83c:/var/www/html# service --status-all
 [ - ]  apache-htcacheclean
 [ + ]  apache2
 [ - ]  apparmor
 [ - ]  dbus
 [ ? ]  hwclock.sh
 [ - ]  procps
 [ - ]  redis-server
 [ + ]  udev
# install getssl
root@6e856df8f83c:/# apt-get install dnsutils

root@6e856df8f83c:/# curl --silent https://raw.githubusercontent.com/srvrco/getssl/latest/getssl > getssl ; chmod 700 getssl

root@6e856df8f83c:/# ./getssl -c nanzhou.cc
creating main config file /root/.getssl/getssl.cfgMaking
domain directory - /root/.getssl/nanzhou.cc
creating domain config file in /root/.getssl/nanzhou.cc/getssl.cfg
Adding SANS=www.nanzhou.cc from certificate installed on nanzhou.cc to new configuration file
created domain config file in /root/.getssl/nanzhou.cc/getssl.cfg

Then set up the getssl configs, /root/.getssl/getssl.cfg and /root/.getssl/nanzhou.cc/getssl.cfg

root@b889a5cfe9ea:/# cat /root/.getssl/getssl.cfg 
# vim: filetype=sh
#
# This file is read first and is common to all domains
#
# Uncomment and modify any variables you need
# see https://github.com/srvrco/getssl/wiki/Config-variables for details
#
# The staging server is best for testing (hence set as default)
# CA="https://acme-staging-v02.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
CA="https://acme-v02.api.letsencrypt.org"

# The agreement that must be signed with the CA, if not defined the default agreement will be used
#AGREEMENT=""

# Set an email address associated with your account - generally set at account level rather than domain.
#ACCOUNT_EMAIL="me@example.com"
ACCOUNT_KEY_LENGTH=4096
ACCOUNT_KEY="/root/.getssl/account.key"

# Account key and private key types - can be rsa, prime256v1, secp384r1 or secp521r1
#ACCOUNT_KEY_TYPE="rsa"
PRIVATE_KEY_ALG="rsa"
#REUSE_PRIVATE_KEY="true"

# Preferred Chain - use an different certificate root from the default
# This uses wildcard matching so requesting "X1" returns the correct certificate - may need to escape characters
# Staging options are: "(STAGING) Doctored Durian Root CA X3" and "(STAGING) Pretend Pear X1"
# Production options are: "ISRG Root X1" and "ISRG Root X2"
#PREFERRED_CHAIN="\(STAGING\) Pretend Pear X1"

# Uncomment this if you need the full chain file to include the root certificate (Java keystores, Nutanix Prism)
#FULL_CHAIN_INCLUDE_ROOT="true"

# The command needed to reload apache / nginx or whatever you use.
# Several (ssh) commands may be given using a bash array:
# RELOAD_CMD=('ssh:sshuserid@server5:systemctl reload httpd' 'logger getssl for server5 efficient.')
#RELOAD_CMD=""

# The time period within which you want to allow renewal of a certificate
#  this prevents hitting some of the rate limits.
# Creating a file called FORCE_RENEWAL in the domain directory allows one-off overrides
# of this setting
RENEW_ALLOW="30"

# Define the server type. This can be https, ftp, ftpi, imap, imaps, pop3, pop3s, smtp,
# smtps_deprecated, smtps, smtp_submission, xmpp, xmpps, ldaps or a port number which
# will be checked for certificate expiry and also will be checked after
# an update to confirm correct certificate is running (if CHECK_REMOTE) is set to true
SERVER_TYPE="https"
CHECK_REMOTE="true"

# Use the following 3 variables if you want to validate via DNS
#VALIDATE_VIA_DNS="true"
#DNS_ADD_COMMAND=
#DNS_DEL_COMMAND=

# Unusual configurations (especially split views) may require these.
# If you have a mixture, these can go in the per-domain getssl.cfg.
#
# If you must use an external DNS Server (e.g. due to split views)
# Specify it here.  Otherwise, the default is to find the zone master.
# The default will usually work.
# PUBLIC_DNS_SERVER="8.8.8.8"

# If getssl is unable to determine the authoritative nameserver for a domain
# it will as you to enter AUTH_DNS_SERVER.  This is a server that
# can answer queries for the zone - a master or a slave, not a recursive server.
# AUTH_DNS_SERVER="10.0.0.14"
root@b889a5cfe9ea:/# cat /root/.getssl/nanzhou.cc/getssl.cfg
# vim: filetype=sh
#
# This file is read second (and per domain if running with the -a option)
# and overwrites any settings from the first file
#
# Uncomment and modify any variables you need
# see https://github.com/srvrco/getssl/wiki/Config-variables for details
# see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs
#
# The staging server is best for testing
# CA="https://acme-staging-v02.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
CA="https://acme-v02.api.letsencrypt.org"

# Private key types - can be rsa, prime256v1, secp384r1 or secp521r1
#PRIVATE_KEY_ALG="rsa"

# Additional domains - this could be multiple domains / subdomains in a comma separated list
# Note: this is Additional domains - so should not include the primary domain.
SANS="75.119.134.73"

# Acme Challenge Location. The first line for the domain, the following ones for each additional domain.
# If these start with ssh: then the next variable is assumed to be the hostname and the rest the location.
# An ssh key will be needed to provide you with access to the remote server.
# Optionally, you can specify a different userid for ssh/scp to use on the remote server before the @ sign.
# If left blank, the username on the local server will be used to authenticate against the remote server.
# If these start with ftp:/ftpes:/ftps: then the next variables are ftpuserid:ftppassword:servername:ACL_location
# These should be of the form "/path/to/your/website/folder/.well-known/acme-challenge"
# where "/path/to/your/website/folder/" is the path, on your web server, to the web root for your domain.
# ftp: uses regular ftp; ftpes: ftp over explicit TLS (port 21); ftps: ftp over implicit TLS (port 990).
# ftps/ftpes support FTPS_OPTIONS, e.g. to add "--insecure" to the curl command for hosts with self-signed certificates.
# You can also user WebDAV over HTTPS as transport mechanism. To do so, start with davs: followed by username,
# password, host, port (explicitly needed even if using default port 443) and path on the server.
# Multiple locations can be defined for a file by separating the locations with a semi-colon.
ACL=('/var/www/html/.well-known/acme-challenge')
#     'ssh:server5:/var/www/nanzhou.cc/web/.well-known/acme-challenge'
#     'ssh:sshuserid@server5:/var/www/nanzhou.cc/web/.well-known/acme-challenge'
#     'ftp:ftpuserid:ftppassword:nanzhou.cc:/web/.well-known/acme-challenge'
#     'davs:davsuserid:davspassword:{DOMAIN}:443:/web/.well-known/acme-challenge'
#     'ftps:ftpuserid:ftppassword:nanzhou.cc:/web/.well-known/acme-challenge'
#     'ftpes:ftpuserid:ftppassword:nanzhou.cc:/web/.well-known/acme-challenge')
#ACL=('/var/www/web/.well-known/acme-challenge')

# Specify SSH options, e.g. non standard port in SSH_OPTS
# (Can also use SCP_OPTS and SFTP_OPTS)
# SSH_OPTS=-p 12345

# Set USE_SINGLE_ACL="true" to use a single ACL for all checks
USE_SINGLE_ACL="true"

# Preferred Chain - use an different certificate root from the default
# This uses wildcard matching so requesting "X1" returns the correct certificate - may need to escape characters
# Staging options are: "(STAGING) Doctored Durian Root CA X3" and "(STAGING) Pretend Pear X1"
# Production options are: "ISRG Root X1" and "ISRG Root X2"
#PREFERRED_CHAIN="\(STAGING\) Pretend Pear X1"

# Uncomment this if you need the full chain file to include the root certificate (Java keystores, Nutanix Prism)
#FULL_CHAIN_INCLUDE_ROOT="true"

# Location for all your certs, these can either be on the server (full path name)
# or using ssh /sftp as for the ACL
DOMAIN_CERT_LOCATION="/etc/ssl/nanzhou.cc.crt" # this is domain cert
DOMAIN_KEY_LOCATION="/etc/ssl/nanzhou.cc.key" # this is domain key
CA_CERT_LOCATION="/etc/ssl/chain.crt" # this is CA cert
#DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert
#DOMAIN_PEM_LOCATION="" # this is the domain key, domain cert and CA cert

# The command needed to reload apache / nginx or whatever you use.
# Several (ssh) commands may be given using a bash array:
# RELOAD_CMD=('ssh:sshuserid@server5:systemctl reload httpd' 'logger getssl for server5 efficient.')
RELOAD_CMD="service apache2 reload"

# Uncomment the following line to prevent non-interactive renewals of certificates
#PREVENT_NON_INTERACTIVE_RENEWAL="true"

# Define the server type. This can be https, ftp, ftpi, imap, imaps, pop3, pop3s, smtp,
# smtps_deprecated, smtps, smtp_submission, xmpp, xmpps, ldaps or a port number which
# will be checked for certificate expiry and also will be checked after
# an update to confirm correct certificate is running (if CHECK_REMOTE) is set to true
SERVER_TYPE="https"
CHECK_REMOTE="true"
#CHECK_REMOTE_WAIT="2" # wait 2 seconds before checking the remote server

Finally run getssl

root@b889a5cfe9ea:/# ./getssl nanzhou.cc
The current repository has no releases or is improperly tagged; can't check for upgrades: ''
Registering account
Verify each domain
Verifying nanzhou.cc
nanzhou.cc is already validated
Verifying www.nanzhou.cc
www.nanzhou.cc is already validated
Verification completed, obtaining certificate.
Requesting Finalize Link
Requesting Order Link
ACME server still Processing certificates
Requesting certificate
Certificate saved in /root/.getssl/nanzhou.cc/nanzhou.cc.crt
copying domain certificate to /etc/ssl/nanzhou.cc.crt
copying private key to /etc/ssl/nanzhou.cc.key
copying CA certificate to /etc/ssl/chain.crt
reloading SSL services
Restarting Apache httpd web server: apache2

At this moment, you should see the website is starting using the new issued credentials.

Cron Job

Use cron to schedule refresh regularly.

root@b889a5cfe9ea:/# crontab -l
# Edit this file to introduce tasks to be run by cron.
# 
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# 
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
# 
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# 
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# 
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# 
# For more information see the manual pages of crontab(5) and cron(8)
# 
# m h  dom mon dow   command
0 0 * * * /getssl nanzhou.cc

Leave a Reply

Your email address will not be published. Required fields are marked *