ViaThinkSoft CodeLib
Dieser Artikel befindet sich in der Kategorie:
CodeLib → HowTos → Apache
Revision: 20. November 2024
Dieses Beispiel zeigt auf, wie man Let's Encrypt verwenden kann, um Zertifikate mit einer individuellen Automatik zu erstellen, anstelle sich auf die 100% Automatik von Let's Encrypt zu verlassen. Sie behalten somit stets die volle Kontrolle über Ihre Webserver-Konfiguration und die Zertifikate und müssen sich nicht sorgen, dass ein fremdes Programm Ihre Konfigurationen des Webservers stört. Das Verwenden der Zertifikate für andere Dienste (MySQL, FTP, IMAP, SMTP etc) ist dadurch einfach zu bewerkstelligen.
Diese Anleitung erfordert, dass Sie bereits übere eine fertig eingerichtete Apache-Installation verfügen, und sich mit SSL auskennen. Diese Anleitung spricht insbesondere Webmaster an, die von einer bestehenden CA zu Let's Encrypt wechseln wollen.
In unserem Beispiel speichern wir unsere Zertifikats-Relevanten Daten in /daten/ssl/letsencrypt . Alle hier gezeigten Verzeichnis-Namen und Einstellungen sind selbstverständlich nur Beispiele und können abgeändert werden.
Schritt 1: Einrichten von Certbot, Apache und dem Cronjob (einmalig)
1.1. Anlegen der relevanten Ordner
1.2. Installieren und Einrichten von Apache2-Modulen:
Führen Sie folgende Befehle aus:
1.3. Einrichten einiger Macros in Apache. Erstellen Sie hierfür /etc/apache2/sites-available/000--macros.conf
Achtung! Es handelt sich hierbei um zwei Bindestriche. "000--macros.conf" muss nämlich vor "000-default.conf" einsortiert/geladen werden.
1.4. Aktivieren Sie die Konfigurationsdatei:
1.5. OCSP-Stapling in Apache aktivieren
Die /etc/apache2/mods-enabled/ssl.conf editieren und folgendes ans Ende anhängen:
1.6. Fügen Sie die folgende Zeile in jedem <VirtualHost> Block in Ihren Webseiten-Konfigurationen (/etc/apache2/sites-available/*.conf) ein:
Sollte die Validierung der Domain im späteren Prozess fehlschlagen, könnte eventuell eine Rewrite-Rule dies verhindern. In diesem Fall muss folgende Zeile dem jeweiligen Rewrite-Abschnitt hinzugefügt werden:
1.7. Neustarten von Apache:
1.8. Erstellen Sie folgendes Script: /daten/ssl/letsencrypt/renew-all.sh (mit Ausführungs-Berechtigungen per chmod +x renew-all.sh)
1.9. Fügen Sie einen Cronjob für den Benutzer root hinzu, um die Zertifikats-Erneuerung regelmäßig durchzuführen:
Und fügen Sie folgende Zeile an:
1.10. Installieren von Certbot:
Sofern das Paket "certbot" in Ihrer Linux-Konfiguration nicht verfügbar ist, dann führen Sie die folgenden Befehle durch:
1.11. Einrichten der Linux-Benutzer:
Schritt 2: Einrichten der Scripts für eine neue Webseite, hier im Beispiel "website1":
2.1. Erstellen Sie die Verzeichnisse /daten/ssl/letsencrypt/website1/ und /daten/ssl/letsencrypt/website1/old/
2.2. Erstellen Sie /daten/ssl/letsencrypt/website1/openssl.cnf und ersetzen Sie die Domain-Namen.
2.3. Erstellen Sie /daten/ssl/letsencrypt/website1/config und tragen Sie Ihre E-Mail-Adresse ein:
2.4. Erstellen Sie /daten/ssl/letsencrypt/website1/renew.sh (mit Ausführungs-Berechtigungen per chmod +x renew.sh)
2.5. (Optional) Erstellen Sie folgendes Script /daten/ssl/letsencrypt/website1/recover_cert.sh, das im Notfall aufgerufen werden kann, um ein Zertifikat samt privatem Schlüssel wiederherzustellen (mit Ausführungs-Berechtigungen per chmod +x recover_cert.sh)
2.6. Editieren Sie die jeweiligen Einstellungen der jeweiligen Webseite z.B. in /etc/apache2/sites-available/website.conf .
Falls Sie nur einen <VirtualHost> Block haben (für Port 80), duplizieren Sie diesen Block, sodass Sie einen Block für Port 80 (HTTP) und einen Block für Port 443 (HTTPS) haben.
Im HTTPS Block fügen Sie den folgenden Befehl ein um die Let's Encrypt-Zertifikate zu aktivieren. (Falls Sie mehrere Port 443 Blöcke haben, fügen Sie die Zeile zu jedem Block hinzu)
Schritt 3: Testen
Rufen Sie /daten/ssl/letsencrypt/renew-all.sh das erste Mal manuell auf und folgen den Bildschirm-Anweisungen bzw. achten auf etwaige Fehlermeldungen.
Unter anderem müssen Sie einmalig den Regeln zustimmen und angeben, ob Sie in die EFF-Mailingliste aufgenommen werden möchten.
Ersetzen Sie in den config-Dateien "acme-v02" durch "acme-staging-v02", um die Zertifikate von einer Test-CA zu erhalten. Dadurch wird das Erstellen unnötiger Test-Zertifikate verhindert.
Mögliche Fehlerquellen
Tritt ein Timeout auf, obwohl die Webseite öffentlich erreichbar sein kann, so kann es sein, dass IPv6 gestört ist. Let's Encrypt bevorzugt IPv6 (AAAA) DNS-Records.
Wenn Apache nicht startet, können folgende Befehle helfen, den Fehler zu finden:
Dieses Beispiel zeigt auf, wie man Let's Encrypt verwenden kann, um Zertifikate mit einer individuellen Automatik zu erstellen, anstelle sich auf die 100% Automatik von Let's Encrypt zu verlassen. Sie behalten somit stets die volle Kontrolle über Ihre Webserver-Konfiguration und die Zertifikate und müssen sich nicht sorgen, dass ein fremdes Programm Ihre Konfigurationen des Webservers stört. Das Verwenden der Zertifikate für andere Dienste (MySQL, FTP, IMAP, SMTP etc) ist dadurch einfach zu bewerkstelligen.
Diese Anleitung erfordert, dass Sie bereits übere eine fertig eingerichtete Apache-Installation verfügen, und sich mit SSL auskennen. Diese Anleitung spricht insbesondere Webmaster an, die von einer bestehenden CA zu Let's Encrypt wechseln wollen.
In unserem Beispiel speichern wir unsere Zertifikats-Relevanten Daten in /daten/ssl/letsencrypt . Alle hier gezeigten Verzeichnis-Namen und Einstellungen sind selbstverständlich nur Beispiele und können abgeändert werden.
Schritt 1: Einrichten von Certbot, Apache und dem Cronjob (einmalig)
1.1. Anlegen der relevanten Ordner
sudo mkdir /daten
sudo mkdir /daten/ssl
sudo mkdir /daten/ssl/letsencrypt
1.2. Installieren und Einrichten von Apache2-Modulen:
Führen Sie folgende Befehle aus:
sudo a2enmod macro
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod ssl
1.3. Einrichten einiger Macros in Apache. Erstellen Sie hierfür /etc/apache2/sites-available/000--macros.conf
Achtung! Es handelt sich hierbei um zwei Bindestriche. "000--macros.conf" muss nämlich vor "000-default.conf" einsortiert/geladen werden.
<Macro LetsEncryptProxy>
<IfModule mod_proxy.c>
ProxyPass "/.well-known/acme-challenge/" "http://127.0.0.1:999/.well-known/acme-challenge/" retry=1
ProxyPassReverse "/.well-known/acme-challenge/" "http://127.0.0.1:999/.well-known/acme-challenge/"
<Location "/.well-known/acme-challenge/">
ProxyPreserveHost On
Order allow,deny
Allow from all
Require all granted
</Location>
</IfModule>
</Macro>
<Macro LetsEncryptSSL $sitedirname $ssl_log>
SSLEngine on
SSLCertificateFile "/daten/ssl/letsencrypt/$sitedirname/certificate.pem"
SSLCertificateKeyFile "/daten/ssl/letsencrypt/$sitedirname/private.key"
SSLCertificateChainFile "/daten/ssl/letsencrypt/$sitedirname/intermediate_ca.pem"
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
CustomLog "$ssl_log" "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</Macro>
1.4. Aktivieren Sie die Konfigurationsdatei:
cd /etc/apache2/sites-enabled/
ln -s ../sites-available/000--macros.conf
1.5. OCSP-Stapling in Apache aktivieren
Die /etc/apache2/mods-enabled/ssl.conf editieren und folgendes ans Ende anhängen:
SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
1.6. Fügen Sie die folgende Zeile in jedem <VirtualHost> Block in Ihren Webseiten-Konfigurationen (/etc/apache2/sites-available/*.conf) ein:
Use LetsEncryptProxy
Sollte die Validierung der Domain im späteren Prozess fehlschlagen, könnte eventuell eine Rewrite-Rule dies verhindern. In diesem Fall muss folgende Zeile dem jeweiligen Rewrite-Abschnitt hinzugefügt werden:
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
1.7. Neustarten von Apache:
sudo service apache2 restart
1.8. Erstellen Sie folgendes Script: /daten/ssl/letsencrypt/renew-all.sh (mit Ausführungs-Berechtigungen per chmod +x renew-all.sh)
#!/bin/bash
DIR=$( dirname "$0" )
TOTALRES=0
for subdir in "$DIR"/*/; do
if [ -f "${subdir}renew.sh" ]; then
"${subdir}renew.sh"
if [ $? -ne 0 ]; then
TOTALRES=1
fi
sleep 1
fi
done
service apache2 restart
# Falls Sie eines der Zertifikate für andere Dienste verwenden, aktivieren Sie bitte die jeweiligen Einträge durch Entfernen der Raute:
#service vsftpd restart
#service postfix restart
#service cyrus-imapd restart
#service mysql restart
# ...
exit $TOTALRES
1.9. Fügen Sie einen Cronjob für den Benutzer root hinzu, um die Zertifikats-Erneuerung regelmäßig durchzuführen:
sudo crontab -e
Und fügen Sie folgende Zeile an:
0 0 1 * * /daten/ssl/letsencrypt/renew-all.sh
1.10. Installieren von Certbot:
sudo aptitude update
sudo aptitude install certbot
Sofern das Paket "certbot" in Ihrer Linux-Konfiguration nicht verfügbar ist, dann führen Sie die folgenden Befehle durch:
sudo aptitude update
sudo aptitude install git
cd /daten/ssl/letsencrypt/
git clone https://github.com/letsencrypt/letsencrypt
mv letsencrypt _certbot
1.11. Einrichten der Linux-Benutzer:
groupadd ssl
usermod -a -G ssl www-data
chown -R root:ssl /daten/ssl/
Schritt 2: Einrichten der Scripts für eine neue Webseite, hier im Beispiel "website1":
2.1. Erstellen Sie die Verzeichnisse /daten/ssl/letsencrypt/website1/ und /daten/ssl/letsencrypt/website1/old/
2.2. Erstellen Sie /daten/ssl/letsencrypt/website1/openssl.cnf und ersetzen Sie die Domain-Namen.
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = www.domain1.de
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
# Extention "Must Staple"
# Remove this line if you want to use the certificate with services that do not support OCSP-Must-Staple (e.g. Postfix)
1.3.6.1.5.5.7.1.24 = DER:30:03:02:01:05
[alt_names]
DNS.1 = domain1.de
DNS.2 = www.domain2.de
DNS.3 = domain2.de
...
2.3. Erstellen Sie /daten/ssl/letsencrypt/website1/config und tragen Sie Ihre E-Mail-Adresse ein:
EMAIL="..."
ECCURVE=secp384r1
#RSASIZE=4096
SERVER="https://acme-v02.api.letsencrypt.org/directory"
#SERVER="https://acme-staging-v02.api.letsencrypt.org/directory"
## If WILDCARD_APITOKEN is missing, reverse proxy method will be used, otherwise DNS method.
## Wildcard DNS method requires the scripts wildcard_authenticator.sh and wildcard_cleanup.sh
## which must be prepared for your domain provider
#WILDCARD_APITOKEN=""
2.4. Erstellen Sie /daten/ssl/letsencrypt/website1/renew.sh (mit Ausführungs-Berechtigungen per chmod +x renew.sh)
#!/bin/bash
# --- Initialization
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
DIR=$( dirname "$0" )
cd "$DIR"
if [ ! -f openssl.cnf ]; then
echo "Bitte das Script im jeweiligen Verzeichnis aufrufen." >&2
exit 2
fi
if [ ! -d "old/" ]; then
mkdir old
fi
. config
# --- Clean up
rm -f *_pkcs12.p12 2> /dev/null
rm -f *_private.key 2> /dev/null
rm -f *_cert.pem 2> /dev/null
rm -f *_chain.pem 2> /dev/null
rm -f *_req.csr 2> /dev/null
rm -f certbot.log 2> /dev/null
rm -f letsencrypt.log 2> /dev/null
# --- Create private key
if [ "$ECCURVE" != "" ]; then
openssl ecparam -name "$ECCURVE" -genkey -out 0000_priv.key
else
openssl genrsa -out 0000_priv.key $RSASIZE
fi
if [ $? -ne 0 ]; then
echo "FAILED TO CREATE PRIVATE KEY" >&2
exit 1
fi
chown root:ssl 0000_priv.key
chmod 640 0000_priv.key
# --- Create certificate request
openssl req -new -batch -sha256 \
-key 0000_priv.key \
-config openssl.cnf \
-out 0000_req.csr
if [ $? -ne 0 ]; then
echo "FAILED TO CREATE CERTIFICATE REQUEST" >&2
exit 1
fi
# --- Ask server to sign the certificate
#if [ -f ../_certbot/certbot-auto ]; then
# EX="../_certbot/certbot-auto"
#else
EX="certbot"
#fi
if [ "$WILDCARD_APITOKEN" == "" ]; then
$EX certonly \
--authenticator standalone \
--preferred-challenges http-01 --http-01-port 999 \
--server $SERVER \
--text \
--email $EMAIL \
--agree-tos \
--must-staple \
--staple-ocsp \
--csr 0000_req.csr
RES=$?
else
$EX certonly \
--manual --manual-auth-hook "$SELF_PATH/wildcard_authenticator.sh" --manual-cleanup-hook "$SELF_PATH/wildcard_cleanup.sh" \
--preferred-challenges dns \
--server $SERVER \
--text \
--email $EMAIL \
--agree-tos \
--must-staple \
--staple-ocsp \
--csr 0000_req.csr
RES=$?
fi
if [ -f /var/log/letsencrypt/letsencrypt.log ]; then
cp /var/log/letsencrypt/letsencrypt.log letsencrypt.log
fi
if [ $RES -ne 0 ]; then
echo "CERTBOT FAILED WITH EXIT CODE $RES ($DIR)" >&2
exit 1
fi
# --- Security check: check if certificate and private key are matching
if [ "$ECCURVE" != "" ]; then
# Extract the public key from the certificate
a=$( openssl x509 -in 0000_cert.pem -pubkey -noout 2>/dev/null | openssl ec -pubin -outform der 2>/dev/null | openssl dgst -sha256 )
# Derive the public key from the private key
b=$( openssl ec -in 0000_priv.key -pubout -outform der 2>/dev/null | openssl dgst -sha256 )
else
a=$( openssl x509 -noout -modulus -in 0000_cert.pem | openssl sha256 )
b=$( openssl rsa -noout -modulus -in 0000_priv.key | openssl sha256 )
fi
if [ "$a" != "$b" ]
then
echo "FEHLER: Zertifikat stimmt nicht mit privatem Schlüssel überein!" >&2
exit 1
fi
# --- PKCS#12 erstellen
# TODO: add $PREVDIR to the name
openssl pkcs12 -export -in 0000_cert.pem -inkey 0000_priv.key -certfile 0000_chain.pem -name "Server Certificate" -out 0000_pkcs12.p12 -passout pass:
if [ $? -ne 0 ]
then
echo "FEHLER bei PCKS#12-Erstellung!" >&2
if [ -f 0000_pkcs12.p12 ]
then
chmod 600 0000_pkcs12.p12
rm 0000_pkcs12.p12
fi
exit 1
fi
if [ ! -f 0000_pkcs12.p12 ]
then
echo "FEHLER! PCKS#12 konnte nicht erstellt werden!" >&2
exit 1
fi
chmod 600 0000_pkcs12.p12
if [ -f precreate.sh ]; then
./precreate.sh
fi
# --- Activate certs
# Files created by certbot:
# 0000_cert.pem = cert.pem (i.e., the server certificate)
# 0000_chain.pem = chain.pem (i.e., the intermediate certificate)
# 0001_chain.pem = fullchain.pem (i.e., a concatenation of cert.pem + chain.pem in one file).
mv -f 0000_pkcs12.p12 "old/$(date +%s).p12"
mv -f 0000_priv.key private.key
mv -f 0000_cert.pem certificate.pem
mv -f 0000_chain.pem intermediate_ca.pem
rm -f 0000_req.csr
rm -f certbot.log 2> /dev/null
rm -f 0001_chain.pem
# --- Delete expired archived certificates
FILES=old/*.p12
for f in $FILES
do
# TODO: das ist nicht sauber, denn wenn ein anderer fehler im zertifikat vorliegt, dann würde auch $?=1 sein
openssl pkcs12 -in "$f" -clcerts -nokeys -passin pass: | openssl x509 -noout -checkend 0 > /dev/null
if [ $? -eq 1 ]; then
echo "$f has expired. Deleting."
rm -f "$f"
fi
done
# --- Post create: Restart servers etc.
if [ -f postcreate.sh ]; then
./postcreate.sh
fi
2.5. (Optional) Erstellen Sie folgendes Script /daten/ssl/letsencrypt/website1/recover_cert.sh, das im Notfall aufgerufen werden kann, um ein Zertifikat samt privatem Schlüssel wiederherzustellen (mit Ausführungs-Berechtigungen per chmod +x recover_cert.sh)
#!/bin/bash
DIR=$( dirname "$0" )
cd "$DIR"
if [ "$1" == "--help" ]; then
echo "Syntax: $0 <p12file>"
exit 2
fi
if [ ! -f "$1" ]; then
echo "ERROR: File '$1' does not exist" >&2
exit 1
fi
openssl pkcs12 -in "$1" -nocerts -out tmp_priv.key -passin pass: -nodes
if [ $? -ne 0 ]; then
echo "ERROR recovering the private key" >&2
rm tmp_priv.key 2> /dev/null
rm tmp_cert.pem 2> /dev/null
rm tmp_ca.pem 2> /dev/null
exit 1
fi
openssl pkcs12 -in "$1" -clcerts -nokeys -out tmp_cert.pem -passin pass:
if [ $? -ne 0 ]; then
echo "ERROR recovering the certificate" >&2
rm tmp_priv.key 2> /dev/null
rm tmp_cert.pem 2> /dev/null
rm tmp_ca.pem 2> /dev/null
exit 1
fi
openssl pkcs12 -in "$1" -cacerts -nokeys -out tmp_ca.pem -passin pass:
if [ $? -ne 0 ]; then
echo "ERROR recovering the intermediate certificate" >&2
rm tmp_priv.key 2> /dev/null
rm tmp_cert.pem 2> /dev/null
rm tmp_ca.pem 2> /dev/null
exit 1
fi
mv -f tmp_priv.key private.key
if [ $? -ne 0 ]; then
echo "ERROR moving the private key" >&2
exit 1
fi
mv -f tmp_cert.pem certificate.pem
if [ $? -ne 0 ]; then
echo "ERROR moving the certificate" >&2
exit 1
fi
mv -f tmp_ca.pem intermediate_ca.pem
if [ $? -ne 0 ]; then
echo "ERROR moving the intermediate certificate" >&2
exit 1
fi
echo "Certificate $1 recovered."
2.6. Editieren Sie die jeweiligen Einstellungen der jeweiligen Webseite z.B. in /etc/apache2/sites-available/website.conf .
Falls Sie nur einen <VirtualHost> Block haben (für Port 80), duplizieren Sie diesen Block, sodass Sie einen Block für Port 80 (HTTP) und einen Block für Port 443 (HTTPS) haben.
Im HTTPS Block fügen Sie den folgenden Befehl ein um die Let's Encrypt-Zertifikate zu aktivieren. (Falls Sie mehrere Port 443 Blöcke haben, fügen Sie die Zeile zu jedem Block hinzu)
Use LetsEncryptSSL website1 /var/log/.../website1/ssl_request.log
Schritt 3: Testen
Rufen Sie /daten/ssl/letsencrypt/renew-all.sh das erste Mal manuell auf und folgen den Bildschirm-Anweisungen bzw. achten auf etwaige Fehlermeldungen.
Unter anderem müssen Sie einmalig den Regeln zustimmen und angeben, ob Sie in die EFF-Mailingliste aufgenommen werden möchten.
Ersetzen Sie in den config-Dateien "acme-v02" durch "acme-staging-v02", um die Zertifikate von einer Test-CA zu erhalten. Dadurch wird das Erstellen unnötiger Test-Zertifikate verhindert.
Mögliche Fehlerquellen
Tritt ein Timeout auf, obwohl die Webseite öffentlich erreichbar sein kann, so kann es sein, dass IPv6 gestört ist. Let's Encrypt bevorzugt IPv6 (AAAA) DNS-Records.
Wenn Apache nicht startet, können folgende Befehle helfen, den Fehler zu finden:
- apachectl configtest
- journalctl -u apache2.service
- systemctl status apache2.service
- journalctl -xe
Daniel Marschall
ViaThinkSoft Mitbegründer
ViaThinkSoft Mitbegründer