Qmail renewal script


#1

Hi,

I wrote a bash script for qmail cert renewal that can be used with the current deploy system of letsencrypt.

Simply copy it to your qmail control directory, make it executable, and follow the instructions in the comment at the start of the script file. That includes instructions to get the initial cert for your mail domain. You can find it here:

https://scara.com/install_le_cert.sh

It’s been working for me for the last few months. Feedback appreciated.


How to use certs in non-root services?
Use on non-web servers?
#2

Since I got a separate qmail topic now (thanks, @jsha), I’ll paste the script here (in case my server goes down).

#!/bin/sh
# 2018-02-19 Christian Wolff

#######################################
# Script to provide TLS CERT to qmail #
#######################################
# 
# Initial one-time action: Get CERT from Let's Encrypt
# 
# - Substitute your domain name instead of 'domain.com', and adjust the server aliases and email address.
# - Make sure the first name after -d matches the entry in /var/qmail/control/me
# 
# - See https://letsencrypt.org/ for details, but basically:
# 
#   apt-get update
#   apt-get install software-properties-common
#   add-apt-repository ppa:certbot/certbot
#   apt-get update
#   apt-get install python-certbot-apache
# 
# - With an HTTP server already running on port 80:
# 
#   certbot --email admin@domain.com --agree-tos certonly --webroot -w /path/to/http/directory/ \
#     -d mail.domain.com,smtp.domain.com,qmtp.domain.com,pop.domain.com,imap.domain.com
# 
# - Without an HTTP server (this will start its own temporary server on port 80, make sure it's accessible):
# 
#   certbot --email admin@domain.com --agree-tos certonly --standalone \
#     -d mail.domain.com,smtp.domain.com,qmtp.domain.com,pop.domain.com,imap.domain.com
# 
# - Then, add a deploy hook to the CERT renewal cronjob, by linking this script:
# 
#   ln -s /var/qmail/control/install_le_cert.sh /etc/letsencrypt/renewal-hooks/deploy/qmail.sh
#
# - When all is done, check certificate. End by entering QUIT.
# 
#   openssl s_client -CApath /etc/ssl/certs -starttls smtp -crlf -connect mail.domain.com:25
#

QMAILDIR="/var/qmail/control"
CERTBACKUP="cert_archive"
SERVER=`cat ${QMAILDIR}/me`

CERTNAME="servercert"
CERTEXT=".pem"
NEWEXT=".new"
CERT="${CERTNAME}${CERTEXT}"

# To test, or call locally, uncomment the following lines:
#RENEWED_DOMAINS="${SERVER}"
#RENEWED_LINEAGE="/etc/letsencrypt/live/${SERVER}"

echo "*** QMail CERT renewal for ${SERVER} ***"
echo "Available domains: ${RENEWED_DOMAINS}; in '${RENEWED_LINEAGE}'"

for domain in $RENEWED_DOMAINS; do
	case $domain in
	${SERVER})
		
		# Make sure the certificate and private key files are
		# never world readable, even just for an instant while
		# we're copying them into daemon_cert_root.
		umask 077
		
		# Assemble combined CERT
		cat ${RENEWED_LINEAGE}/privkey.pem \
			${RENEWED_LINEAGE}/fullchain.pem \
			> ${QMAILDIR}/${CERT}${NEWEXT}
		
		# Check if CERT was renewed
		diff -q ${QMAILDIR}/${CERT} ${QMAILDIR}/${CERT}${NEWEXT}
		if [ $? -ne 0 ]
		then
			
			echo "Updating CERT for ${SERVER}"
			
			# Fix permissions
			chmod 640 ${QMAILDIR}/${CERT}${NEWEXT}
			chown qmaild.qmail ${QMAILDIR}/${CERT}${NEWEXT}
			
			# Move into place
			mv -b ${QMAILDIR}/${CERT}${NEWEXT} ${QMAILDIR}/${CERT}
			
			# (Re-)create links
			ln -sf ${CERT} ${QMAILDIR}/clientcert.pem
			ln -sf ${CERT} ${QMAILDIR}/tlsclientciphers
			ln -sf ${CERT} ${QMAILDIR}/tlsserverciphers
			
			# Keep a history of dated copies
			mkdir -p ${QMAILDIR}/${CERTBACKUP}
			cp -a ${QMAILDIR}/${CERT} ${QMAILDIR}/${CERTBACKUP}/${CERTNAME}_${SERVER}_`date '+%Y-%m-%d'`${CERTEXT}
			
			# Restart qmail
			/usr/local/bin/svc -d /service/qmail-send
			/usr/local/bin/svc -d /service/popd
			/usr/local/bin/svc -d /service/pop3ssl
			/usr/local/bin/svc -d /service/smtpd/
			/usr/local/bin/svc -d /service/smtpssl
			/usr/local/bin/svc -u /service/qmail-send
			/usr/local/bin/svc -u /service/popd
			/usr/local/bin/svc -u /service/pop3ssl
			/usr/local/bin/svc -u /service/smtpd/
			/usr/local/bin/svc -u /service/smtpssl
			
		else
			
			echo "CERT for ${SERVER} unchanged"
			
			# Clean up
			rm ${QMAILDIR}/${CERT}${NEWEXT}
			
		fi
		
	esac
done

#3

I have some suggestions, more about qmail and daemontools than about letsencrypt…

  • You can use “svc -t” instead of having to do “svc -d” followed by “svc -u”.

  • If you put all of the service directory names on a single command, svc will perform the requested operation on all of them at once. For example, “svc -t /service/pop3ssl /service/smtpssl”.

    The service names on my own servers are all “/service/qmail-something”, so if I need to restart everything involving qmail, I can use a single “svc -t /service/qmail-*” command.

  • When you change SSL key/cert files, only the SSL-enabled SMTP, IMAP, and POP3 services need to be restarted. The others, including qmail-send, don’t need to be restarted, because they don’t do anything with encryption.

Hope this helps.


#4

Thank you, yes, that helps. I’ll update the script and make it more clear that the restart section has to be customized.

    # Restart mail services.
    # This should be customized to all the services you are running (imap, pop, smtp, qmtp), both SSL and TLS ports
    /usr/local/bin/svc -t /service/pop* /service/smtp*
    /etc/init.d/courier-imap restart
    /etc/init.d/courier-imap-ssl restart