Skip to content

Commit 7683958

Browse files
authored
Initial commit
1 parent 93a6352 commit 7683958

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

acme-cert-renewal/README.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# acme certificate renewal
2+
3+
When using [acme-client(1)](https://man.openbsd.org/acme-client) it is seemingly very easy to renew certificates: Just call `acme-client <domain>` on a regular bases, such as from `/etc/daily.local` or from a [cron(8)](https://man.openbsd.org/cron) job.
4+
5+
While not incorrect this does not solve the problem of getting running services to use the updated certificates. Doing this on a host that use a number of services and a number of different certifictaes gets tedious quickly. Also you might reload e.g. a web server several times when multiple certificates are updated which is unnecessary. And you may want to be notified when certificates change or when something goes wrong.
6+
7+
The shell script snippet is meant to be added to or included from `/etc/daily.local`. It reduces the custom code for each certificate to one line which specifies the hostname and the affected services. For example:
8+
```
9+
handleDomain www.example.com 'HTTPD'
10+
handleDomain mail.example.com 'NO_HTTPD' 'NO_APACHE' 'SMTPD' 'DOVECOT'
11+
```
12+
13+
The script snippet will also log what it does to the email sent by the [daily(8)](https://man.openbsd.org/daily) mechanism and to `/var/log/daily.out`.
14+
15+
Adding additional services should be fairly easy. Just follow the pattern of the example services provided in the code.
+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Copyright (c)2021-2022 by fiwswe
2+
#
3+
# Insert this into /etc/daily.local or include it from there.
4+
# Or you could add the #!/bin/sh line at the top and start the script via cron(8). But
5+
# you might need to check whether logging and mail notifications work as expected then.
6+
#
7+
8+
#
9+
# Renew the Let's Encrypt certificates on this server (if necessary):
10+
#
11+
12+
DO_ACTION=1
13+
NO_ACTION=0
14+
15+
NEED_HTTPD_RESTART=$NO_ACTION
16+
NEED_APACHE_RESTART=$NO_ACTION
17+
NEED_DOVECOT_RESTART=$NO_ACTION
18+
NEED_SMTPD_RESTART=$NO_ACTION
19+
NEED_POSTFIX_RESTART=$NO_ACTION
20+
ERROR_DOMAINS=''
21+
22+
# Parameters:
23+
# domain The main domain for the certificate.
24+
function addErrorDomain
25+
{
26+
if [ $# -ge 1 ];then
27+
if [ -z "$ERROR_DOMAINS" ]; then
28+
ERROR_DOMAINS="$1"
29+
else
30+
ERROR_DOMAINS="${ERROR_DOMAINS}, $1"
31+
fi
32+
fi
33+
}
34+
35+
# Parameters:
36+
# domain The main domain for the certificate.
37+
# needHttpd 'HTTPD' if OpenBSD httpd depends on the certificate.
38+
# needApache 'APACHE' if Apache depends on the certificate.
39+
# needHttpd 'HTTPD' if OpenBSD httpd depends on the certificate.
40+
# needDovecot 'DOVECOT' if Dovecot depends on the certificate.
41+
# needSMTPd 'SMTPD' if smtpd depends on the certificate.
42+
# needPostfix 'POSTFIX' if Postfix depends on the certificate.
43+
# Note: Unneeded parameters can be omitted from the end but if e.g.
44+
# 'DOVECOT' is present then placeholders for 'APACHE' and 'HTTPD'
45+
# must also be present (with different values).
46+
# Examples:
47+
# handleDomain example.com 'HTTPD' 'NO_APACHE'
48+
# handleDomain example.com 'NO_HTTPD' 'NO_APACHE' 'DOVECOT'
49+
# handleDomain example.com 'HTTPD'
50+
function handleDomain
51+
{
52+
if [ $# -ge 1 ];then
53+
/usr/sbin/acme-client "$1"
54+
case "$?" in
55+
0) echo "Certificate for $1 was renewed."
56+
if [ $# -ge 2 -a "$2" = 'HTTPD' ];then
57+
NEED_HTTPD_RESTART=$DO_ACTION
58+
fi
59+
if [ $# -ge 3 -a "$3" = 'APACHE' ];then
60+
NEED_APACHE_RESTART=$DO_ACTION
61+
fi
62+
if [ $# -ge 4 -a "$4" = 'DOVECOT' ];then
63+
NEED_DOVECOT_RESTART=$DO_ACTION
64+
fi
65+
if [ $# -ge 5 -a "$5" = 'SMTPD' ];then
66+
NEED_SMTPD_RESTART=$DO_ACTION
67+
fi
68+
if [ $# -ge 6 -a "$6" = 'POSTFIX' ];then
69+
NEED_POSTFIX_RESTART=$DO_ACTION
70+
fi
71+
;;
72+
1) addErrorDomain "$1"
73+
;;
74+
2) echo "Certificate for $1 does not need to be renewed."
75+
;;
76+
*) echo "Unknown error ($?) while trying to renew certificate for $1!"
77+
addErrorDomain "$1"
78+
;;
79+
esac
80+
else
81+
echo 'ERROR: No domain for certificate renewal check!'
82+
fi
83+
}
84+
85+
86+
#
87+
# Handle the certificates:
88+
#
89+
90+
handleDomain mail.example.com 'NO_HTTPD' 'NO_APACHE' 'DOVECOT' 'SMTPD'
91+
92+
handleDomain www.example.com 'NO_HTTPD' 'APACHE'
93+
94+
handleDomain wiki.example.com 'HTTPD'
95+
96+
97+
#
98+
# Now do any needed actions (only once, even if triggered more than once above):
99+
#
100+
101+
# Handle httpd(8):
102+
if [ $NEED_HTTPD_RESTART -ne $NO_ACTION ]; then
103+
/usr/sbin/rcctl restart httpd
104+
fi
105+
106+
# Handle Apache httpd2(8):
107+
if [ $NEED_APACHE_RESTART -ne $NO_ACTION ]; then
108+
/usr/local/sbin/apachectl restart
109+
# As an example, deal with failures: Sometimes restarting the Apache httpd fails for some reason. Try again…
110+
if [ $? -ne 0 ]; then
111+
sleep 1
112+
/usr/local/sbin/apachectl restart
113+
if [ $? -ne 0 ]; then
114+
echo 'ERROR: Could not restart Apache after certificate update! (Tried and failed twice...)'|mail -s '`hostname` Apache restart failure' root
115+
fi
116+
fi
117+
fi
118+
119+
# Handle dovecot(1):
120+
if [ $NEED_DOVECOT_RESTART -ne $NO_ACTION ]; then
121+
/usr/sbin/rcctl restart dovecot
122+
fi
123+
124+
# Handle smtpd(8):
125+
if [ $NEED_SMTPD_RESTART -ne $NO_ACTION ]; then
126+
/usr/sbin/rcctl restart smtpd
127+
fi
128+
129+
# Handle postfix(1):
130+
if [ $NEED_POSTFIX_RESTART -ne $NO_ACTION ]; then
131+
/usr/sbin/rcctl restart postfix
132+
fi
133+
134+
if [ -n "$ERROR_DOMAINS" ]; then
135+
echo "ERROR updating certificates for ${ERROR_DOMAINS}!"
136+
echo "ERROR updating certificates for ${ERROR_DOMAINS}!"|mail -s "`hostname` Certificate renewal errors" root
137+
fi
138+
139+
140+
#
141+
# Done with the Let's Encrypt certificate renewal.
142+
#

0 commit comments

Comments
 (0)