Edge Ingress Gateway: Nginx Proxy Manager (NPM), Wildcard DNS-01 ACME & mTLS-Zugriffslisten
Erstellt: 06.11.2026 Aktualisiert: 06.11.2026
Management Summary: Selbst gehostete Container-Dienste ohne zentrale TLS-Terminierung, HTTP/3-Unterstützung und strikte Zugangskontrollen direkt ins Internet freizugeben, führt zwangsläufig zu Sicherheitsrisiken. Dieser Leitfaden beschreibt das Produktiv-Deployment von Nginx Proxy Manager (NPM). NPM kombiniert die bewährte C-basierte OpenResty/Nginx-Event-Schleife mit einer intuitiven Verwaltungsebene zur Orchestrierung von Let's Encrypt Wildcard-Zertifikaten (
DNS-01), WebSocket-/gRPC-Proxying, Real-IP-Wiederherstellung (ngx_http_realip_module) und kryptografischer Mutual TLS (mTLS) Client-Authentifizierung.
-
Zero-Port-80 DNS-01 Wildcards
Bezieht Wildcard-Zertifikate (
*.lan.nejat-hakan.de) über ACME-DNS-01-APIs, ohne jemals Port 80 oder 443 ins öffentliche Internet öffnen zu müssen. -
Dedizierte Docker Ingress Bridge
Isoliert Backend-Dienste in einem internen Bridge-Netzwerk (
proxy_net), sodass keinerlei Backend-Ports (8080,3000,9000) auf der Host-NIC gebunden werden. -
Security-Header & mTLS
Erzwingt HSTS Preload, CSP,
X-Frame-Optionsund Client-Zertifikatsvalidierung (ssl_verify_client on) über wiederverwendbare Nginx-Snippets. -
Strukturierte JSON-Access-Logs
Erfasst Upstream-Latenzen (
$upstream_response_time) und reale Client-IPs (CF-Connecting-IP/X-Forwarded-For) zur Analyse mit CrowdSec und Fail2ban.
1. Architektur: Isoliertes Container-Ingress & Split-Horizon TLS
In einer gehärteten Self-Hosting-Umgebung binden interne Anwendungen niemals Ports auf 0.0.0.0. Stattdessen dient Nginx Proxy Manager als zentrales Ingress-Gateway im Docker-Netzwerk proxy_net und leitet Anfragen über interne Docker-DNS-Namen weiter (http://immich-server:2283, http://vaultwarden:80).
%%{init: {'flowchart': {'wrappingWidth': 600, 'subGraphTitleMargin': {'top': 15, 'bottom': 15}}}}%%
flowchart TB
subgraph Clients["Externe & LAN Clients"]
Browser["HTTPS / HTTP3 Client<br/>*.nejat-hakan.de"]
ACME["Let's Encrypt CA<br/>DNS-01 API Challenge"]
end
subgraph IngressGateway["Nginx Proxy Manager (proxy_net)"]
NginxCore["OpenResty / Nginx Engine<br/>TLS 1.3 + HTTP/2 + HTTP/3"]
Certbot["Embedded Certbot<br/>DNS-01 Wildcard-Erneuerung"]
AccessList["Access Lists & mTLS<br/>IP Allowlist / Client-Zertifikat"]
end
subgraph InternalBackends["Isolierte Backend-Container (Keine Host-Ports)"]
Vault["Vaultwarden<br/>vaultwarden:80"]
Nextcloud["Nextcloud App<br/>nextcloud:80"]
Jellyfin["Jellyfin Media<br/>jellyfin:8096"]
end
Browser -->|"TCP/UDP 443 (SNI)"| NginxCore
Certbot <-->|"TXT _acme-challenge"| ACME
NginxCore --> AccessList
AccessList -->|"WebSocket + Proxy"| Vault
AccessList -->|"FastCGI / HTTP"| Nextcloud
AccessList -->|"Streaming Puffer aus"| Jellyfin
2. Produktiv-Stack (NPM + Externes Ingress-Netzwerk)
Erstellen Sie zunächst das isolierte Ingress-Netzwerk:
docker network create --driver=bridge --subnet=172.28.0.0/16 proxy_net
services:
npm:
image: jc21/nginx-proxy-manager:latest
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- "80:80/tcp"
- "443:443/tcp"
- "443:443/udp"
- "127.0.0.1:81:81/tcp"
environment:
TZ: "Europe/Berlin"
DISABLE_IPV6: "false"
PUID: 1000
PGID: 1000
volumes:
- ./data:/data:Z
- ./letsencrypt:/etc/letsencrypt:Z
networks:
- proxy_net
networks:
proxy_net:
external: true
Admin-Port 81 niemals auf 0.0.0.0 binden
Binden Sie Port 81 stets ausschließlich an Loopback (127.0.0.1:81:81/tcp). Greifen Sie auf die NPM-Weboberfläche entweder via SSH-Portforwarding (ssh -L 8181:127.0.0.1:81 user@host) zu oder erstellen Sie einen internen Proxy-Host (npm.lan.nejat-hakan.de → http://127.0.0.1:81), der durch eine LAN-Zugriffsliste abgesichert ist.
3. Wiederverwendbare Nginx-Härtungs-Snippets (/data/nginx/custom/)
NPM bindet benutzerdefinierte Konfigurationsdateien aus /data/nginx/custom/ automatisch ein:
http_top.conf: Wird am Anfang deshttp {}-Blocks geladen.server_proxy.conf: Wird in jeden generierten Proxy-Host-server {}-Block injiziert.
# Versionsnummern im Server-Header und auf Fehlerseiten ausblenden
server_tokens off;
# TLS 1.3 / 1.2 elliptische Kurven härten
ssl_ecdh_curve X25519:secp384r1;
ssl_session_tickets off;
# Lokales WireGuard-VPN und Docker-Subnetz für X-Forwarded-For vertrauen
set_real_ip_from 172.28.0.0/16;
set_real_ip_from 10.88.0.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# HSTS & moderne Browser-Isolations-Header erzwingen
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "accelerometer=(), camera=(), geolocation=(), microphone=(), payment=(), usb=()" always;
# Standard-Proxy-Puffer für große OIDC/JWT-Header vergrößern
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
4. Mutual TLS (mTLS) Client-Zertifikatsauthentifizierung
Für sensible administrative Oberflächen (Proxmox, Portainer) bietet Mutual TLS (mTLS) maximale Sicherheit: Nginx bricht den TLS-Handshake bereits auf Layer 4/7 ab, bevor auch nur ein einziges HTTP-Byte an das Backend gelangt, falls der Client kein gültiges Zertifikat der internen CA vorlegt.
mkdir -p /opt/npm/data/mtls && cd /opt/npm/data/mtls
# 1. Privaten Root-CA-Schlüssel und Zertifikat generieren (10 Jahre Gültigkeit)
openssl genpkey -algorithm ED25519 -out ca.key
openssl req -x509 -new -key ca.key -sha256 -days 3650 -out ca.crt \
-subj "/CN=Sovereign Infrastructure mTLS Root CA/O=NejatHakan"
# 2. Client-Schlüssel und Zertifikatsanforderung erzeugen und signieren
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out client.key
openssl req -new -key client.key -out client.csr -subj "/CN=nejat-workstation/O=Engineering"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 825 -sha256
# 3. PKCS#12 (.p12) Bundle für Browser-/Mobilgeräte-Import exportieren
openssl pkcs12 -export -out nejat-client.p12 -inkey client.key -in client.crt -certfile ca.crt
Fügen Sie im Reiter Advanced des gewünschten Proxy-Hosts in NPM folgende Zeilen ein:
ssl_client_certificate /data/mtls/ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;
5. Verifikation & Log-Audit
Konfigurationsintegrität im laufenden Container prüfen und Latenzen auswerten:
# 1. Generierte Nginx-Dateien im Container syntaktisch prüfen
docker exec nginx-proxy-manager nginx -t
# 2. Worker-Prozesse ohne Verbindungsabbruch neu laden
docker exec nginx-proxy-manager nginx -s reload
# 3. Statuscodes und Antwortzeiten in Echtzeit analysieren
tail -f /opt/npm/data/logs/proxy-host-*_access.log