Last updated on 17. August 2025
Voraussetzung: Teil 1 ist erledigt (FQDN + PTR stehen stabil, Hostname fix, Basis-Installation mit Nginx). Siehe: Teil 1 – Saubere FQDN/PTR-Konfiguration & Grundinstallation von ISPConfig mit Nginx.
Teil 1 Link: Teil 1 — Saubere FQDN/PTR-Konfiguration & Grundinstallation von ISPConfig (mit NGINX)
Zielbild
- Öffentlich nur Port 443 am Hostnamen
server.example.com - ISPConfig (Backend) weiter auf
https://127.0.0.1:8080 - phpMyAdmin (optional) auf
https://127.0.0.1:8081/phpmyadmin - Rettungszugang auf Port 4443 (nur per IP & Self-Signed, damit HSTS/Cache dich nicht aussperrt)
Ersetze im Folgenden:
server.example.com→ dein Panel-Hostname<DEINE_IPV4>/<DEINE_IPV6>→ deine Server-IP(s)
1) Rettungszugang auf 4443 (Self-Signed, SAN=IP)
1.1 Self-Signed Zertifikat für die IP erzeugen
sudo mkdir -p /etc/nginx/selfsigned sudo tee /etc/nginx/selfsigned/rescue-openssl.cnf >/dev/null <<'EOF' [req] distinguished_name = dn x509_extensions = v3_req prompt = no [dn] CN = <DEINE_IPV4> [v3_req] subjectAltName = @alt_names [alt_names] IP.1 = <DEINE_IPV4> # Falls IPv6: # IP.2 = <DEINE_IPV6> EOF sudo openssl req -x509 -newkey rsa:2048 -nodes -days 7 \ -keyout /etc/nginx/selfsigned/rescue.key \ -out /etc/nginx/selfsigned/rescue.crt \ -config /etc/nginx/selfsigned/rescue-openssl.cnf # Prüfen: openssl x509 -in /etc/nginx/selfsigned/rescue.crt -noout -subject -ext subjectAltName
1.3 Test
sudo ss -ltnp | grep ':4443' openssl s_client -connect <DEINE_IPV4>:4443 </dev/null | openssl x509 -noout -subject -ext subjectAltName curl -vkI https://<DEINE_IPV4>:4443/
Im Browser: https://<DEINE_IPV4>:4443/ → Self-Signed Warnung bestätigen → Anmeldeseite von ISPConfig sehen.
2) Produktiv-VHost für 80/443 (Host: server.example.com)
2.1 ACME-Pfad (HTTP-01) & Redirect
sudo tee /etc/nginx/sites-available/server-panel.conf >/dev/null <<'EOF'
# :80 → Redirect auf :443 + ACME http-01
server {
listen <DEINE_IPV4>:80;
listen [::]:80;
server_name server.example.com;
# ACME http-01 ohne Auth
location ^~ /.well-known/acme-challenge/ {
auth_basic off;
root /var/www/letsencrypt;
default_type text/plain;
try_files $uri =404;
}
return 301 https://$host$request_uri;
}
# :443 → Reverse Proxy auf ISPConfig / phpMyAdmin
server {
listen <DEINE_IPV4>:443 ssl http2;
# listen [<DEINE_IPV6>]:443 ssl http2;
server_name server.example.com;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_certificate /etc/letsencrypt/live/server.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/server.example.com/privkey.pem;
# Security-Header (HSTS erst später aktivieren)
# add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# globales Basic Auth (ACME ausgenommen)
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
location ^~ /.well-known/acme-challenge/ {
auth_basic off;
root /var/www/letsencrypt;
default_type text/plain;
try_files $uri =404;
}
# ISPConfig (Backend)
location / {
proxy_pass https://127.0.0.1:8080/;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_read_timeout 120s;
}
# phpMyAdmin (optional)
location ^~ /phpmyadmin/ {
proxy_pass https://127.0.0.1:8081/phpmyadmin/;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
EOF
sudo ln -sf /etc/nginx/sites-available/server-panel.conf /etc/nginx/sites-enabled/server-panel.conf
sudo nginx -t && sudo systemctl reload nginx
Tipp: Falls du Cloudflare nutzt, setze den DNS-Eintrag
server.example.comfür die Ausstellung zunächst auf “DNS only” (Graue Wolke). Nach erfolgreichem Zertifikat kannst du ggf. wieder “Proxy” (Orange) aktivieren.
2.2 Zertifikat ausstellen / prüfen
Wenn noch kein Zertifikat existiert:
# Webroot muss mit dem ACME-Block übereinstimmen sudo mkdir -p /var/www/letsencrypt sudo certbot certonly --webroot -w /var/www/letsencrypt -d server.example.com # Dry-Run der Erneuerung sudo certbot renew --dry-run
Prüfen, ob der richtige Zertifikatsname ausgeliefert wird:
openssl s_client -connect <DEINE_IPV4>:443 -servername server.example.com </dev/null \ | openssl x509 -noout -subject -ext subjectAltName
3) Direktzugang abdichten (Ports 8080/8081 nur intern)
Laufen dürfen 8080/8081 weiterhin – aber nur lokal erreichbar.
# Wenn UFW aktiv ist (Beispiel): sudo ufw deny in proto tcp to any port 8080 sudo ufw deny in proto tcp to any port 8081 # Lauschen prüfen: sudo ss -ltnp | egrep ':443|:8080|:8081'
4) HSTS & Monitoring
4.1 HSTS erst aktivieren, wenn alles stabil
# im :443-Serverblock ergänzen (und Nginx neu laden) add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
Achtung: Mit includeSubDomains zwingst du alle Subdomains auf HTTPS. Nur aktivieren, wenn du das willst.
Header prüfen:
curl -sI https://server.example.com | grep -i strict-transport-security
4.2 Kleines Fingerprint-Monitoring (Frühwarnung)
FPR_EXPECTED=$(openssl x509 -in /etc/letsencrypt/live/server.example.com/cert.pem -noout -fingerprint -sha256|cut -d= -f2) FPR_LIVE=$(openssl s_client -connect <DEINE_IPV4>:443 -servername server.example.com </dev/null 2>/dev/null \ | openssl x509 -noout -fingerprint -sha256 | cut -d= -f2) [ "$FPR_EXPECTED" = "$FPR_LIVE" ] || echo "ALERT: TLS mismatch" | mail -s "server.example.com TLS" admin@example.com
Als Cronjob (z. B. stündlich) eintragen.
5) (Optional) Cloudflare richtig setzen
- Für die Zertifikatsausstellung
server.example.comDNS only. - Danach ggf. Proxy aktivieren und im CF-Dashboard SSL/TLS = Full (Strict) wählen.
- Falls du Cloudflare häufig nutzt: Real-IP im Nginx sauber konfigurieren (siehe Teil 1/ggf. eigener Artikel).
6) Aufräumen: Rescue wieder schließen
Wenn alles sauber läuft:
sudo ufw delete allow 4443/tcp sudo rm -f /etc/nginx/sites-enabled/000-rescue-4443.conf sudo rm -f /etc/nginx/sites-available/000-rescue-4443.conf sudo rm -f /etc/nginx/selfsigned/rescue.crt /etc/nginx/selfsigned/rescue.key /etc/nginx/selfsigned/rescue-openssl.cnf sudo nginx -t && sudo systemctl reload nginx
7) Troubleshooting (häufige Stolpersteine)
7.1 Falsches Zertifikat wird ausgeliefert
- Mehrere
server_name server.example.comin unterschiedlichen VHosts.
→ Mitsudo nginx -T | grep -n "server_name server.example.com"prüfen und Duplikate entfernen. - Ein anderer VHost lauscht auf
listen 443als default_server oder auf0.0.0.0:443und matched zuerst.
→ Produktiv-VHost an die konkrete IP binden (listen <DEINE_IPV4>:443 ssl http2;).
7.2 ACME schlägt fehl (404 im Challenge-Pfad)
/.well-known/acme-challenge/muss ohne Basic Auth erreichbar sein.root /var/www/letsencrypt;stimmt? Datei percurltestweise abrufen.
7.3 HSTS sperrt dich aus
- Nutze den Rescue-Port 4443 per IP (Self-Signed) – kein HSTS, keine Host-Caches.
- Danach Ursache beseitigen (siehe 7.1) und normal über Hostname testen.
7.4 Werkzeuge für die Diagnose
# Vollständige geladene Nginx-Konfiguration sudo nginx -T # Zertifikatsdetails via SNI openssl s_client -connect <DEINE_IPV4>:443 -servername server.example.com </dev/null \ | openssl x509 -noout -subject -issuer -dates -ext subjectAltName # DNS umgehen und Hostname → IP erzwingen curl -vk --resolve server.example.com:443:<DEINE_IPV4> https://server.example.com/ -I
8) Zertifikate automatisch erneuern (Certbot/Timer)
- Prüfen:
systemctl status certbot.timer sudo certbot certificates sudo certbot renew --dry-run
- Alte/obsolet gewordene Zertifikate entfernen (z. B. ehemaliges
panel.example.com):
sudo certbot delete --cert-name panel.example.com
Fazit
Mit diesem Setup hängt ISPConfig sicher hinter Nginx auf Port 443, direkte Backend-Ports bleiben intern, HSTS schützt (auf Wunsch) Browser-Clients und über den IP-Rescue-Port 4443 kommst du im Notfall jederzeit wieder ins Panel.
Wenn du willst, erstelle ich dir noch Meta-Title/Description & Tags für Teil 2 – oder passe den Text an deinen Stil an.
Weiterführende Quellen
- Nginx Doku: Server names & SNI
- Nginx Doku: HTTP Proxy (Reverse Proxy)
- Certbot Doku: Webroot-Plugin & Erneuerung
- RFC 6797: HTTP Strict Transport Security (HSTS)
- HowToForge: ISPConfig Autoinstall (Hintergrund)
Hinweis:: Wenn dir dieser Beitrag gefallen oder geholfen hat, kannst du mich gerne mit einer kleinen Unterstützung motivieren 😊
₿/Ξ: Donate with Bitcoin
Address: bc1qt7wc6jfth4t2szc2hp6340sqp3y0pa9r3ywgrr
Schreib den ersten Kommentar