NPM Docker Setup mit NetBird
Diese Anleitung beschreibt die Einrichtung von Nginx Proxy Manager (NPM) in Docker auf sowohl dem externen VPS als auch dem Heimserver, verbunden über einen sicheren NetBird-Tunnel. NPM bietet eine benutzerfreundliche Web-Oberfläche zur Verwaltung von Reverse Proxies und SSL-Zertifikaten.
Anpassbare Werte in dieser Anleitung:
luna→ Dein Benutzername226→ Dein SSH-Port100.64.0.1→ NetBird-IP des Heimservers100.64.0.2→ NetBird-IP des VPSdeine-domain.de→ Deine Domain
Architektur-Überblick
┌─────────────────────────────────────────────────────────────────────────────┐
│ INTERNET │
│ │ │
│ ▼ │
│ ┌───────────────────┐ │
│ │ VPS │ │
│ │ (Hetzner etc.) │ │
│ │ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Docker │ │ │
│ │ │ ┌───────┐ │ │ │
│ Port 80/443 ──┼──┼─►│ NPM │ │ │ ← SSL-Terminierung │
│ │ │ └───┬───┘ │ │ │
│ │ └─────┼───────┘ │ │
│ │ │ │ │
│ │ ┌─────▼───────┐ │ │
│ │ │ NetBird │ │ │
│ │ │ 100.64.0.2 │ │ │
│ │ └─────┬───────┘ │ │
│ └────────┼──────────┘ │
│ │ │
│ ══════════════╪══════════════ │
│ Verschlüsselter NetBird-Tunnel │
│ ══════════════╪══════════════ │
│ │ │
│ ┌────────────────────────────────┼─────────────────────────────────────┐ │
│ │ HEIMNETZ │ │
│ │ │ │ │
│ │ ┌──────────▼──────────┐ │ │
│ │ │ Heimserver │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────┐ │ │ │
│ │ │ │ NetBird │ │ │ │
│ │ │ │ 100.64.0.1 │ │ │ │
│ │ │ └─────┬───────┘ │ │ │
│ │ │ │ │ │ │
│ │ │ ┌─────▼───────┐ │ │ │
│ │ │ │ Docker │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌─────────┐ │ │ │ │
│ │ │ │ │NPM (opt)│ │ │ ← Lokale Verwaltung │ │
│ │ │ │ └────┬────┘ │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ ┌────▼────┐ │ │ │ │
│ │ │ │ │ Dienste │ │ │ │ │
│ │ │ │ │Wiki,Git,│ │ │ │ │
│ │ │ │ │Vaultw...│ │ │ │ │
│ │ │ │ └─────────┘ │ │ │ │
│ │ │ └─────────────┘ │ │ │
│ │ └─────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
Zwei Setup-Varianten
| Variante | Beschreibung | Empfohlen für |
|---|---|---|
| A: NPM nur auf VPS | VPS hat NPM, leitet direkt zu Heimserver-Diensten | Einfaches Setup, wenige Dienste |
| B: NPM auf beiden | VPS-NPM → Heimserver-NPM → Dienste | Viele Dienste, lokale Verwaltung gewünscht |
Teil 1: Voraussetzungen
Docker & Docker Compose installieren
Auf beiden Systemen (VPS und Heimserver) ausführen:
# Docker installieren
curl -fsSL https://get.docker.com | sudo sh
# User zur Docker-Gruppe hinzufügen (logout/login nötig)
sudo usermod -aG docker $USER
# Docker Compose ist bei aktuellen Docker-Versionen integriert
docker compose version
NetBird installieren
Auf beiden Systemen:
# NetBird installieren
curl -fsSL https://pkgs.netbird.io/install.sh | sudo sh
# Mit Account verbinden
sudo netbird up --setup-key DEIN-SETUP-KEY
# Status prüfen
sudo netbird status
Wichtig: Notiere die NetBird-IPs beider Systeme (z.B. 100.64.0.1 für Heimserver, 100.64.0.2 für VPS).
Teil 2: Variante A – NPM nur auf VPS
Einfachste Variante: NPM läuft nur auf dem VPS und leitet Traffic direkt an die Dienste auf dem Heimserver weiter.
NPM auf dem VPS einrichten
# Verzeichnis erstellen
mkdir -p ~/nginx-proxy-manager && cd ~/nginx-proxy-manager
# Docker Compose Datei erstellen
nano docker-compose.yml
version: '3.8'
services:
npm:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- '80:80' # HTTP (öffentlich)
- '443:443' # HTTPS (öffentlich)
- '127.0.0.1:81:81' # Admin-UI (nur localhost)
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
environment:
- TZ=Europe/Berlin
networks:
- proxy
# Wichtig: NetBird-Netzwerk muss erreichbar sein
extra_hosts:
- "heimserver:100.64.0.1" # ← Heimserver NetBird-IP anpassen
networks:
proxy:
name: proxy
driver: bridge
# Container starten
docker compose up -d
# Logs prüfen
docker compose logs -f
Zugang zur Admin-Oberfläche
Da Port 81 nur auf localhost hört, Zugriff via SSH-Tunnel:
# Vom lokalen PC:
ssh -L 8181:127.0.0.1:81 luna@VPS-IP -p 226
# Dann im Browser öffnen:
# http://localhost:8181
Standard-Login:
- E-Mail:
admin@example.com - Passwort:
changeme
Beim ersten Login wirst du aufgefordert, beides zu ändern.
Firewall auf dem VPS
# UFW konfigurieren
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
# Port 81 NICHT öffnen (bleibt nur lokal erreichbar)
sudo ufw reload
Dienste auf dem Heimserver
Beispiel: BookStack, Vaultwarden und Gitea als Docker-Container:
# Verzeichnis erstellen
mkdir -p ~/services && cd ~/services
nano docker-compose.yml
version: '3.8'
services:
# ══════════════════════════════════════════════════════════════
# BookStack Wiki
# ══════════════════════════════════════════════════════════════
bookstack:
image: lscr.io/linuxserver/bookstack:latest
container_name: bookstack
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Berlin
- APP_URL=https://wiki.deine-domain.de
- DB_HOST=bookstack-db
- DB_USER=bookstack
- DB_PASS=sicheres-passwort # ← Anpassen!
- DB_DATABASE=bookstack
volumes:
- ./bookstack/config:/config
ports:
- "100.64.0.1:3000:80" # ← Nur auf NetBird-IP
depends_on:
- bookstack-db
networks:
- internal
bookstack-db:
image: mariadb:10
container_name: bookstack-db
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=root-passwort # ← Anpassen!
- MYSQL_DATABASE=bookstack
- MYSQL_USER=bookstack
- MYSQL_PASSWORD=sicheres-passwort # ← Anpassen!
volumes:
- ./bookstack/db:/var/lib/mysql
networks:
- internal
# ══════════════════════════════════════════════════════════════
# Vaultwarden (Bitwarden-Alternative)
# ══════════════════════════════════════════════════════════════
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
- TZ=Europe/Berlin
- DOMAIN=https://vault.deine-domain.de
- SIGNUPS_ALLOWED=false
- ADMIN_TOKEN=admin-token-hier # ← Generieren mit: openssl rand -base64 48
volumes:
- ./vaultwarden:/data
ports:
- "100.64.0.1:8080:80" # ← Nur auf NetBird-IP
networks:
- internal
# ══════════════════════════════════════════════════════════════
# Gitea (Git-Server)
# ══════════════════════════════════════════════════════════════
gitea:
image: gitea/gitea:latest
container_name: gitea
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__server__DOMAIN=git.deine-domain.de
- GITEA__server__ROOT_URL=https://git.deine-domain.de/
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "100.64.0.1:3001:3000" # ← Nur auf NetBird-IP
- "100.64.0.1:2222:22" # ← Git SSH (optional)
networks:
- internal
networks:
internal:
name: services-internal
# Starten
docker compose up -d
Wichtig: Die Dienste sind an 100.64.0.1 (NetBird-IP) gebunden – sie sind nur über den NetBird-Tunnel erreichbar, nicht aus dem lokalen Netzwerk oder Internet!
Dienste auch lokal erreichbar machen (optional)
Falls du die Dienste auch im lokalen Netzwerk nutzen willst:
ports:
- "100.64.0.1:3000:80" # NetBird
- "192.168.1.50:3000:80" # Lokales Netzwerk (IP anpassen)
# ODER einfach:
- "3000:80" # Alle Interfaces (weniger sicher)
Proxy Hosts in NPM konfigurieren
In der NPM Web-Oberfläche (http://localhost:8181 via SSH-Tunnel):
1. SSL-Zertifikate einrichten
- SSL Certificates → Add SSL Certificate
- Let's Encrypt auswählen
- Domain:
*.deine-domain.de(Wildcard) oder einzeln - E-Mail eingeben
- DNS Challenge aktivieren (für Wildcard erforderlich)
2. Proxy Host für Wiki
- Hosts → Proxy Hosts → Add Proxy Host
- Details:
- Domain Names:
wiki.deine-domain.de - Scheme:
http - Forward Hostname/IP:
100.64.0.1 - Forward Port:
3000 - ☑ Block Common Exploits
- ☑ Websockets Support
- Domain Names:
- SSL:
- SSL Certificate: (dein Zertifikat auswählen)
- ☑ Force SSL
- ☑ HTTP/2 Support
- ☑ HSTS Enabled
- Save
3. Proxy Host für Vaultwarden
- Domain:
vault.deine-domain.de - Forward Hostname/IP:
100.64.0.1 - Forward Port:
8080 - Websockets aktivieren (wichtig für Vaultwarden!)
4. Proxy Host für Gitea
- Domain:
git.deine-domain.de - Forward Hostname/IP:
100.64.0.1 - Forward Port:
3001
DNS konfigurieren
Bei deinem DNS-Provider:
| Typ | Name | Wert | TTL |
|---|---|---|---|
| A | wiki | VPS-IPv4 | 3600 |
| AAAA | wiki | VPS-IPv6 | 3600 |
| A | vault | VPS-IPv4 | 3600 |
| A | git | VPS-IPv4 | 3600 |
Teil 3: Variante B – NPM auf beiden Systemen
Komplexeres Setup mit NPM auf beiden Seiten – nützlich wenn du viele Dienste hast und diese lokal verwalten willst.
NPM auf dem Heimserver
mkdir -p ~/nginx-proxy-manager && cd ~/nginx-proxy-manager
nano docker-compose.yml
version: '3.8'
services:
npm:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- '100.64.0.1:80:80' # HTTP auf NetBird-IP
- '100.64.0.1:443:443' # HTTPS auf NetBird-IP
- '192.168.1.50:81:81' # Admin-UI im lokalen Netz (IP anpassen!)
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
environment:
- TZ=Europe/Berlin
networks:
- proxy
networks:
proxy:
name: proxy
driver: bridge
docker compose up -d
Dienste auf dem Heimserver (Variante B)
Dienste binden jetzt an 127.0.0.1, NPM leitet lokal weiter:
version: '3.8'
services:
bookstack:
image: lscr.io/linuxserver/bookstack:latest
container_name: bookstack
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Berlin
- APP_URL=https://wiki.deine-domain.de
- DB_HOST=bookstack-db
- DB_USER=bookstack
- DB_PASS=sicheres-passwort
- DB_DATABASE=bookstack
volumes:
- ./bookstack/config:/config
expose:
- "80" # Nur intern erreichbar
depends_on:
- bookstack-db
networks:
- proxy
- internal
bookstack-db:
image: mariadb:10
container_name: bookstack-db
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=root-passwort
- MYSQL_DATABASE=bookstack
- MYSQL_USER=bookstack
- MYSQL_PASSWORD=sicheres-passwort
volumes:
- ./bookstack/db:/var/lib/mysql
networks:
- internal
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
- TZ=Europe/Berlin
- DOMAIN=https://vault.deine-domain.de
volumes:
- ./vaultwarden:/data
expose:
- "80"
networks:
- proxy
networks:
proxy:
external: true
name: proxy
internal:
name: services-internal
NPM auf Heimserver konfigurieren
Proxy Hosts im lokalen NPM (Port 81):
| Domain/Hostname | Forward To | Port |
|---|---|---|
wiki (interner Name) |
bookstack |
80 |
vault |
vaultwarden |
80 |
Hinweis: Im gleichen Docker-Netzwerk können Container über ihren Namen erreicht werden.
NPM auf VPS (Variante B)
version: '3.8'
services:
npm:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '127.0.0.1:81:81'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
environment:
- TZ=Europe/Berlin
extra_hosts:
- "heimserver:100.64.0.1"
NPM auf VPS konfigurieren (Variante B)
Leitet zum Heimserver-NPM weiter:
| Domain | Forward To | Port | SSL |
|---|---|---|---|
wiki.deine-domain.de |
100.64.0.1 |
80 oder 443 | Auf VPS terminieren |
vault.deine-domain.de |
100.64.0.1 |
80 oder 443 | Auf VPS terminieren |
Teil 4: Erweiterte Konfiguration
Custom Nginx-Konfiguration in NPM
Für spezielle Anforderungen kannst du in NPM unter Advanced eigene Nginx-Direktiven hinzufügen:
Security Headers
# Im "Advanced" Tab des Proxy Hosts:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
Rate Limiting
# Benötigt Anpassung der nginx.conf im Container
# Einfacher: Fail2ban auf Host-Ebene nutzen
Größere Uploads erlauben
# Im "Advanced" Tab:
client_max_body_size 100M;
Access Lists (IP-Beschränkung)
NPM hat eingebaute Access Lists:
- Access Lists → Add Access List
- Name eingeben
- Access Tab:
- Satisfy: Any/All
- Allow: IP-Bereiche die zugreifen dürfen
- Deny: Alles andere
- Beim Proxy Host diese Access List auswählen
HTTP Basic Auth
Für zusätzlichen Schutz sensibler Dienste:
- Access Lists → Add Access List
- Authorization Tab:
- Username und Passwort hinzufügen
- Beim Proxy Host zuweisen
Wildcard SSL-Zertifikate
Für alle Subdomains ein Zertifikat:
- SSL Certificates → Add SSL Certificate → Let's Encrypt
- Domain Names:
*.deine-domain.deunddeine-domain.de - ☑ Use a DNS Challenge
- DNS Provider auswählen (z.B. Cloudflare, Hetzner DNS, etc.)
- API-Credentials eingeben
Hetzner DNS API-Beispiel
# In NPM unter DNS Provider:
Provider: Hetzner
API Token: dein-hetzner-dns-api-token
Teil 5: Backup und Wartung
NPM-Daten sichern
# Backup erstellen
cd ~/nginx-proxy-manager
docker compose stop
tar -czvf npm-backup-$(date +%Y%m%d).tar.gz data letsencrypt
docker compose start
NPM aktualisieren
cd ~/nginx-proxy-manager
# Neues Image holen
docker compose pull
# Container neu starten
docker compose up -d
# Alte Images aufräumen
docker image prune -f
Logs prüfen
# NPM-Logs
docker compose logs -f npm
# Nur Fehler
docker compose logs npm | grep -i error
# Access-Logs
docker exec nginx-proxy-manager tail -f /data/logs/proxy-host-1_access.log
Teil 6: Troubleshooting
Häufige Probleme
| Problem | Ursache | Lösung |
|---|---|---|
| 502 Bad Gateway | Backend nicht erreichbar | NetBird-Verbindung prüfen: ping 100.64.0.1 |
| SSL-Fehler | Zertifikat nicht ausgestellt | DNS prüfen, Port 80 offen? |
| 504 Gateway Timeout | Backend antwortet zu langsam | Timeout in Advanced erhöhen |
| Admin-UI nicht erreichbar | Port 81 nicht weitergeleitet | SSH-Tunnel prüfen |
| Container startet nicht | Port bereits belegt | sudo lsof -i :80 |
| DNS Challenge fehlgeschlagen | API-Token falsch | Token und Provider prüfen |
NetBird-Verbindung debuggen
# Status
sudo netbird status
# Detailliert
sudo netbird status -d
# Neuverbinden
sudo netbird down && sudo netbird up
# Logs
sudo journalctl -u netbird -f
Container debuggen
# In Container einloggen
docker exec -it nginx-proxy-manager /bin/bash
# Nginx-Config testen
docker exec nginx-proxy-manager nginx -t
# Nginx neu laden (ohne Neustart)
docker exec nginx-proxy-manager nginx -s reload
Zusammenfassung: Checkliste
VPS
- ☐ Docker & Docker Compose installiert
- ☐ NetBird installiert und verbunden
- ☐ NPM Container läuft
- ☐ Firewall: Port 80, 443 offen
- ☐ Admin-UI nur via SSH-Tunnel erreichbar
- ☐ Proxy Hosts konfiguriert
- ☐ SSL-Zertifikate aktiv
Heimserver
- ☐ Docker & Docker Compose installiert
- ☐ NetBird installiert und verbunden
- ☐ Dienste-Container laufen
- ☐ Dienste nur auf NetBird-IP gebunden
- ☐ (Optional) Lokaler NPM für Verwaltung
DNS
- ☐ A/AAAA-Records zeigen auf VPS-IP
- ☐ DNS-Propagation abgeschlossen
Testen
- ☐
ping 100.64.0.1vom VPS funktioniert - ☐
curl http://100.64.0.1:3000vom VPS funktioniert - ☐ HTTPS-Aufruf der Domain funktioniert
- ☐ SSL-Zertifikat gültig (Browser-Check)
Letzte Aktualisierung: 2025