add project files: docker-compose, env example, README, ufw setup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8c8befc827
commit
59dd9a6350
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Datenbank Passwörter - BITTE ÄNDERN!
|
||||||
|
MYSQL_ROOT_PASSWORD=root_password_changeme
|
||||||
|
MYSQL_PASSWORD=npm_password_changeme
|
||||||
|
|
||||||
|
# Datenbank Einstellungen
|
||||||
|
MYSQL_DATABASE=npm
|
||||||
|
MYSQL_USER=npm
|
||||||
|
MYSQL_HOST=npm-db
|
||||||
|
MYSQL_PORT=3306
|
||||||
|
|
||||||
|
# Ports
|
||||||
|
HTTP_PORT=80
|
||||||
|
HTTPS_PORT=443
|
||||||
|
WEBUI_PORT=81
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Nginx Proxy Manager
|
||||||
|
|
||||||
|
## Verzeichnisstruktur
|
||||||
|
```
|
||||||
|
npm/
|
||||||
|
├── docker-compose.yml
|
||||||
|
├── .env
|
||||||
|
├── data/ # NPM Konfiguration (auto-erstellt)
|
||||||
|
├── letsencrypt/ # SSL Zertifikate (auto-erstellt)
|
||||||
|
└── mysql/ # Datenbank (auto-erstellt)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. Passwörter in `.env` anpassen
|
||||||
|
2. Starten:
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Web-UI aufrufen: http://<server-ip>:81
|
||||||
|
|
||||||
|
## Standard Login (SOFORT ÄNDERN!)
|
||||||
|
- Email: admin@example.com
|
||||||
|
- Passwort: changeme
|
||||||
|
|
||||||
|
## Ports
|
||||||
|
- 80 → HTTP (Weiterleitungen + Let's Encrypt Challenge)
|
||||||
|
- 443 → HTTPS
|
||||||
|
- 81 → NPM Web-UI
|
||||||
|
|
||||||
|
## Neue Domain einrichten
|
||||||
|
1. "Proxy Hosts" → "Add Proxy Host"
|
||||||
|
2. Domain eintragen z.B. nextcloud.example.de
|
||||||
|
3. Ziel-IP + Port eintragen
|
||||||
|
4. Tab "SSL" → Let's Encrypt Zertifikat anfordern
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
npm:
|
||||||
|
image: jc21/nginx-proxy-manager:latest
|
||||||
|
container_name: nginx-proxy-manager
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${HTTP_PORT}:80" # HTTP
|
||||||
|
- "${HTTPS_PORT}:443" # HTTPS
|
||||||
|
- "${WEBUI_PORT}:81" # NPM Web-UI
|
||||||
|
environment:
|
||||||
|
DB_MYSQL_HOST: "${MYSQL_HOST}"
|
||||||
|
DB_MYSQL_PORT: ${MYSQL_PORT}
|
||||||
|
DB_MYSQL_USER: "${MYSQL_USER}"
|
||||||
|
DB_MYSQL_PASSWORD: "${MYSQL_PASSWORD}"
|
||||||
|
DB_MYSQL_NAME: "${MYSQL_DATABASE}"
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./letsencrypt:/etc/letsencrypt
|
||||||
|
depends_on:
|
||||||
|
- npm-db
|
||||||
|
networks:
|
||||||
|
- npm-network
|
||||||
|
|
||||||
|
npm-db:
|
||||||
|
image: jc21/mariadb-aria:latest
|
||||||
|
container_name: nginx-proxy-manager-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD}"
|
||||||
|
MYSQL_DATABASE: "${MYSQL_DATABASE}"
|
||||||
|
MYSQL_USER: "${MYSQL_USER}"
|
||||||
|
MYSQL_PASSWORD: "${MYSQL_PASSWORD}"
|
||||||
|
volumes:
|
||||||
|
- ./mysql:/var/lib/mysql
|
||||||
|
networks:
|
||||||
|
- npm-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
npm-network:
|
||||||
|
driver: bridge
|
||||||
|
|
@ -0,0 +1,214 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# =============================================================================
|
||||||
|
# UFW Firewall Setup + Docker DOCKER-USER Chain
|
||||||
|
# =============================================================================
|
||||||
|
# wg0 = öffentliches Interface (getunnelte öffentliche IP)
|
||||||
|
# → Nur Port 80 + 443 für Docker Container erlaubt
|
||||||
|
# Internes Interface (eth0/ens*) = lokales Netz
|
||||||
|
# → Alles erlaubt (SSH, WireGuard, etc.)
|
||||||
|
#
|
||||||
|
# Ansatz: DOCKER-USER Chain statt "iptables: false"
|
||||||
|
# → Docker Networking bleibt intakt (Container können kommunizieren)
|
||||||
|
# → UFW kontrolliert welche Ports extern erreichbar sind
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Farben
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
log() { echo -e "${GREEN}[✓]${NC} $1"; }
|
||||||
|
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
||||||
|
error() { echo -e "${RED}[✗]${NC} $1"; exit 1; }
|
||||||
|
info() { echo -e "${BLUE}[i]${NC} $1"; }
|
||||||
|
|
||||||
|
# Root check
|
||||||
|
[ "$EUID" -ne 0 ] && error "Bitte als root ausführen: sudo $0"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Interfaces ermitteln
|
||||||
|
# =============================================================================
|
||||||
|
INTERNAL_IF=$(ip route show default 2>/dev/null | grep -oP 'dev \K\S+' | head -1)
|
||||||
|
[ -z "$INTERNAL_IF" ] && error "Konnte internes Interface nicht ermitteln"
|
||||||
|
PUBLIC_IF="wg0"
|
||||||
|
|
||||||
|
info "Öffentliches Interface (WireGuard): ${PUBLIC_IF}"
|
||||||
|
info "Internes Interface: ${INTERNAL_IF}"
|
||||||
|
|
||||||
|
# Prüfen ob wg0 existiert
|
||||||
|
if ! ip link show wg0 &>/dev/null; then
|
||||||
|
warn "wg0 existiert noch nicht - Regeln werden trotzdem gesetzt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
warn "Dieses Script wird UFW neu konfigurieren und Docker anpassen."
|
||||||
|
warn "Bestehende UFW Regeln werden GELÖSCHT."
|
||||||
|
read -p "Fortfahren? (j/N): " confirm
|
||||||
|
[[ "$confirm" != "j" && "$confirm" != "J" ]] && { info "Abgebrochen."; exit 0; }
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# TEIL 1: Docker iptables reaktivieren
|
||||||
|
# =============================================================================
|
||||||
|
echo ""
|
||||||
|
info "=== TEIL 1: Docker iptables reaktivieren ==="
|
||||||
|
|
||||||
|
if systemctl is-active --quiet docker; then
|
||||||
|
warn "Stoppe Docker kurz..."
|
||||||
|
systemctl stop docker
|
||||||
|
DOCKER_WAS_RUNNING=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOCKER_DAEMON=/etc/docker/daemon.json
|
||||||
|
|
||||||
|
if [ -f "$DOCKER_DAEMON" ] && grep -q '"iptables".*false' "$DOCKER_DAEMON"; then
|
||||||
|
cp "$DOCKER_DAEMON" "${DOCKER_DAEMON}.bak.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
python3 -c "
|
||||||
|
import json
|
||||||
|
with open('$DOCKER_DAEMON', 'r') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
config.pop('iptables', None)
|
||||||
|
with open('$DOCKER_DAEMON', 'w') as f:
|
||||||
|
json.dump(config, f, indent=2)
|
||||||
|
"
|
||||||
|
log "iptables: false aus daemon.json entfernt"
|
||||||
|
else
|
||||||
|
log "Docker iptables bereits aktiv"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# TEIL 2: UFW Grundkonfiguration
|
||||||
|
# =============================================================================
|
||||||
|
echo ""
|
||||||
|
info "=== TEIL 2: UFW Konfiguration ==="
|
||||||
|
|
||||||
|
ufw --force reset
|
||||||
|
log "UFW zurückgesetzt"
|
||||||
|
|
||||||
|
ufw default deny incoming
|
||||||
|
ufw default allow outgoing
|
||||||
|
log "Default Policy: deny incoming, allow outgoing"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# TEIL 3: Regeln für wg0 (öffentliches Interface)
|
||||||
|
# =============================================================================
|
||||||
|
echo ""
|
||||||
|
info "=== TEIL 3: Regeln für ${PUBLIC_IF} (öffentlich) ==="
|
||||||
|
|
||||||
|
# Nur HTTP + HTTPS auf wg0
|
||||||
|
ufw allow in on "$PUBLIC_IF" to any port 80 proto tcp comment 'HTTP public (wg0)'
|
||||||
|
ufw allow in on "$PUBLIC_IF" to any port 443 proto tcp comment 'HTTPS public (wg0)'
|
||||||
|
log "Port 80+443 (HTTP/HTTPS) auf ${PUBLIC_IF} geöffnet"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# TEIL 4: Regeln für internes Interface
|
||||||
|
# =============================================================================
|
||||||
|
echo ""
|
||||||
|
info "=== TEIL 4: Regeln für ${INTERNAL_IF} (intern) ==="
|
||||||
|
|
||||||
|
ufw allow in on "$INTERNAL_IF" comment 'Internes Netz - alles erlaubt'
|
||||||
|
log "Alles auf ${INTERNAL_IF} erlaubt (SSH, WireGuard, etc.)"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# TEIL 5: DOCKER-USER Chain (Docker Port-Kontrolle)
|
||||||
|
# =============================================================================
|
||||||
|
echo ""
|
||||||
|
info "=== TEIL 5: DOCKER-USER Chain ==="
|
||||||
|
|
||||||
|
AFTER_RULES=/etc/ufw/after.rules
|
||||||
|
cp "$AFTER_RULES" "${AFTER_RULES}.bak.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
|
||||||
|
# Alte Docker-Fixes aus before.rules entfernen (falls vorhanden)
|
||||||
|
BEFORE_RULES=/etc/ufw/before.rules
|
||||||
|
if grep -q "DOCKER-UFW-FIX" "$BEFORE_RULES"; then
|
||||||
|
cp "$BEFORE_RULES" "${BEFORE_RULES}.bak.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
TMPFILE=$(mktemp)
|
||||||
|
awk '/# DOCKER-UFW-FIX/{skip=1} skip && /^COMMIT/{skip=0; next} !skip' "$BEFORE_RULES" > "$TMPFILE"
|
||||||
|
mv "$TMPFILE" "$BEFORE_RULES"
|
||||||
|
warn "Alte Docker-Fixes aus before.rules entfernt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# DOCKER-USER Regeln in after.rules einfügen
|
||||||
|
if grep -q "DOCKER-USER-FIX" "$AFTER_RULES"; then
|
||||||
|
warn "DOCKER-USER Regeln bereits vorhanden - überspringe"
|
||||||
|
else
|
||||||
|
cat >> "$AFTER_RULES" << EOF
|
||||||
|
|
||||||
|
# DOCKER-USER-FIX - Docker Container Port-Kontrolle
|
||||||
|
# Kontrolliert welcher externe Traffic Docker Container erreicht
|
||||||
|
# Docker Networking bleibt intakt, nur der Zugang von aussen wird gefiltert
|
||||||
|
*filter
|
||||||
|
:DOCKER-USER - [0:0]
|
||||||
|
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
|
||||||
|
-A DOCKER-USER -j RETURN -m conntrack --ctstate RELATED,ESTABLISHED
|
||||||
|
-A DOCKER-USER -p tcp -m tcp --dport 80 -i ${PUBLIC_IF} -j RETURN
|
||||||
|
-A DOCKER-USER -p tcp -m tcp --dport 443 -i ${PUBLIC_IF} -j RETURN
|
||||||
|
-A DOCKER-USER -i ${INTERNAL_IF} -j RETURN
|
||||||
|
-A DOCKER-USER -j DROP
|
||||||
|
COMMIT
|
||||||
|
EOF
|
||||||
|
log "DOCKER-USER Regeln in after.rules eingefügt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# TEIL 6: IP Forwarding aktivieren
|
||||||
|
# =============================================================================
|
||||||
|
echo ""
|
||||||
|
info "=== TEIL 6: IP Forwarding ==="
|
||||||
|
|
||||||
|
SYSCTL_CONF=/etc/ufw/sysctl.conf
|
||||||
|
if grep -q "^net/ipv4/ip_forward=1" "$SYSCTL_CONF" 2>/dev/null; then
|
||||||
|
log "IP Forwarding bereits aktiv"
|
||||||
|
else
|
||||||
|
sed -i 's/#net\/ipv4\/ip_forward=1/net\/ipv4\/ip_forward=1/' "$SYSCTL_CONF"
|
||||||
|
grep -q "net/ipv4/ip_forward=1" "$SYSCTL_CONF" || echo "net/ipv4/ip_forward=1" >> "$SYSCTL_CONF"
|
||||||
|
log "IP Forwarding aktiviert"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q "net.ipv4.ip_forward = 1" /etc/sysctl.conf; then
|
||||||
|
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
|
||||||
|
fi
|
||||||
|
sysctl -p /etc/sysctl.conf > /dev/null 2>&1
|
||||||
|
log "sysctl neu geladen"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# TEIL 7: UFW aktivieren und Docker neu starten
|
||||||
|
# =============================================================================
|
||||||
|
echo ""
|
||||||
|
info "=== TEIL 7: Aktivierung ==="
|
||||||
|
|
||||||
|
ufw --force enable
|
||||||
|
log "UFW aktiviert"
|
||||||
|
|
||||||
|
if [ "$DOCKER_WAS_RUNNING" = true ]; then
|
||||||
|
systemctl start docker
|
||||||
|
sleep 3
|
||||||
|
log "Docker neu gestartet"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# ZUSAMMENFASSUNG
|
||||||
|
# =============================================================================
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
echo -e "${GREEN} UFW Setup abgeschlossen!${NC}"
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
echo ""
|
||||||
|
info "Ansatz: DOCKER-USER Chain (Docker Networking intakt)"
|
||||||
|
echo ""
|
||||||
|
info "Interface-Zuordnung:"
|
||||||
|
info " ${PUBLIC_IF} (öffentlich) → nur Port 80 + 443"
|
||||||
|
info " ${INTERNAL_IF} (intern) → alles erlaubt"
|
||||||
|
echo ""
|
||||||
|
info "Docker Container:"
|
||||||
|
info " Extern (${PUBLIC_IF}) → nur Port 80 + 443 erreichbar"
|
||||||
|
info " Intern (${INTERNAL_IF}) → alle Ports erreichbar"
|
||||||
|
echo ""
|
||||||
|
info "Aktive Regeln:"
|
||||||
|
ufw status verbose
|
||||||
|
echo ""
|
||||||
|
warn "WICHTIG: Teste SSH Verbindung in einem NEUEN Terminal bevor du dieses schließt!"
|
||||||
|
warn "Falls Docker Container kein Internet haben: 'docker restart <container>'"
|
||||||
Loading…
Reference in New Issue