Proxmox Infrastruktur - Vollstaendige Konfiguration

Enthaelt:
- Docker Compose mit allen Services (Nextcloud, Vaultwarden, n8n, etc.)
- nginx Reverse Proxy Konfiguration mit Rate Limiting
- WireGuard VPN Template
- Backup und Health-Check Scripts
- Deployment Script
- Ausfuehrliche Dokumentation und Troubleshooting Guide

Services:
- Isolierte Netzwerke pro Service
- Resource Limits (CPU/Memory)
- Health Checks
- Logging Konfiguration

Sicherheit:
- .env Template ohne Secrets
- Rate Limiting auf nginx
- TLS 1.2+ only
- Security Headers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Martin Eckardt
2025-12-28 17:12:43 +01:00
commit 364e058b8c
11 changed files with 1686 additions and 0 deletions

187
README.md Normal file
View File

@@ -0,0 +1,187 @@
# Proxmox Infrastruktur
Self-Hosted Services auf Proxmox VE mit Docker.
## Architektur
```
Internet
|
v
[Windows VPS: 217.154.65.205]
- nginx Reverse Proxy
- SSL (Let's Encrypt via win-acme)
- WireGuard Server
|
| WireGuard Tunnel (10.0.0.0/24)
v
[Proxmox: 192.168.178.111 / 10.0.0.2]
- Docker Host
- Alle Services als Container
```
## Services
| Service | Port | URL (Extern) | Beschreibung |
|---------|------|--------------|--------------|
| Nextcloud | 8081 | eckardt-cloud.duckdns.org | Cloud Storage |
| Vaultwarden | 8083 | eckardt-vault.duckdns.org/vault/ | Passwort Manager |
| n8n | 5678 | eckardt-vault.duckdns.org/n8n/ | Workflow Automation |
| Gitea | 3000 | eckardt-git.duckdns.org | Git Repository |
| Websites | 8082 | eckardt-vault.duckdns.org | Statische Websites |
| API | 8000 | eckardt-vault.duckdns.org/api/ | FastAPI Backend |
| Audiobookshelf | 13378 | (intern) | Audiobook Server |
## Quick Start
### Voraussetzungen
- Proxmox VE oder Debian/Ubuntu mit Docker
- WireGuard fuer externen Zugriff
- Min. 4GB RAM, 50GB Speicher
### Installation
```bash
# Repository klonen
git clone https://eckardt-git.duckdns.org/Martin/proxmox-infrastruktur.git
cd proxmox-infrastruktur
# Environment-Variablen konfigurieren
cp docker/.env.template docker/.env
nano docker/.env # Passwoerter anpassen!
# Deployment starten
sudo ./scripts/deploy.sh
```
## Verzeichnisstruktur
```
proxmox-infrastruktur/
├── docker/
│ ├── docker-compose.yml # Haupt-Konfiguration
│ ├── .env.template # Environment Template
│ └── .gitignore # Secrets ausschliessen
├── configs/
│ ├── nginx/
│ │ └── nginx.conf # VPS Reverse Proxy
│ └── wireguard/
│ └── wg0.conf.template # WireGuard Template
├── scripts/
│ ├── deploy.sh # Installations-Script
│ ├── backup.sh # Backup-Script
│ └── health-check.sh # Health-Check Script
├── docs/
│ ├── INSTALL.md # Detaillierte Installation
│ └── TROUBLESHOOTING.md # Problemloesungen
└── README.md # Diese Datei
```
## Wartung
### Health Check
```bash
# Alle Services pruefen
/opt/scripts/health-check.sh
# Einzelnen Container pruefen
docker inspect --format='{{.State.Health.Status}}' nextcloud
```
### Backup
```bash
# Vollstaendiges Backup
/opt/scripts/backup.sh all
# Einzelner Service
/opt/scripts/backup.sh nextcloud
# Automatisches Backup (crontab -e)
0 3 * * * /opt/scripts/backup.sh all >> /var/log/backup.log 2>&1
```
### Updates
```bash
cd /opt/docker
# Alle Container aktualisieren
docker compose pull
docker compose up -d
# Einzelnen Container aktualisieren
docker compose pull nextcloud
docker compose up -d nextcloud
```
### Logs
```bash
# Alle Container
docker compose logs -f
# Einzelner Container
docker logs -f nextcloud
# Letzte 100 Zeilen
docker logs --tail 100 nextcloud
```
## Sicherheit
### Implementierte Massnahmen
- **Isolierte Netzwerke**: Jeder Service hat sein eigenes Docker-Netzwerk
- **Resource Limits**: CPU und Memory Limits pro Container
- **Health Checks**: Automatische Ueberwachung aller Services
- **Rate Limiting**: nginx begrenzt Anfragen pro IP
- **TLS 1.2+**: Nur sichere Verschluesselung
- **Security Headers**: X-Frame-Options, X-Content-Type-Options, etc.
### Zu beachten
- `.env` Datei NIEMALS committen
- Admin-Tokens regelmaessig rotieren
- Backups extern speichern
- Updates zeitnah einspielen
## Netzwerk
### WireGuard Tunnel
```
VPS (Server) Proxmox (Client)
10.0.0.1 <--> 10.0.0.2
217.154.65.205 192.168.178.111
```
### Ports
| Port | Service | Zugriff |
|------|---------|---------|
| 51820/UDP | WireGuard | VPS extern |
| 80 | nginx HTTP | VPS extern |
| 443 | nginx HTTPS | VPS extern |
| 3000 | Gitea Web | Proxmox intern |
| 2222 | Gitea SSH | Proxmox intern |
## Troubleshooting
Siehe [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) fuer:
- Container startet nicht
- Permission denied Fehler
- Netzwerk-Probleme
- SSL-Zertifikat Fehler
- Backup-Probleme
## Changelog
### 2024-12-28
- Initial Setup mit allen Services
- Gitea auf eigener Subdomain
- Security Hardening (Registration disabled, Rate Limiting)
- Health Checks und Resource Limits

177
configs/nginx/nginx.conf Normal file
View File

@@ -0,0 +1,177 @@
# nginx Reverse Proxy Konfiguration
# Pfad auf VPS: C:\nginx\conf\nginx.conf
# Server: Windows VPS 217.154.65.205
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
client_max_body_size 10G;
server_names_hash_bucket_size 64;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Rate Limiting
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
# ============================================
# HTTP -> HTTPS Redirects
# ============================================
server {
listen 80;
server_name eckardt-vault.duckdns.org;
location /.well-known/acme-challenge/ {
alias C:/nginx/html/.well-known/acme-challenge/;
}
location / {
return 301 https://eckardt-vault.duckdns.org$request_uri;
}
}
server {
listen 80;
server_name eckardt-cloud.duckdns.org;
location /.well-known/acme-challenge/ {
alias C:/nginx/html/.well-known/acme-challenge/;
}
location / {
return 301 https://eckardt-cloud.duckdns.org$request_uri;
}
}
server {
listen 80;
server_name eckardt-git.duckdns.org;
location /.well-known/acme-challenge/ {
alias C:/nginx/html/.well-known/acme-challenge/;
}
location / {
return 301 https://eckardt-git.duckdns.org$request_uri;
}
}
# ============================================
# eckardt-vault.duckdns.org - Main Services
# ============================================
server {
listen 443 ssl http2;
server_name eckardt-vault.duckdns.org;
ssl_certificate C:/nginx/ssl/eckardt-vault.duckdns.org-chain.pem;
ssl_certificate_key C:/nginx/ssl/eckardt-vault.duckdns.org-key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# Vaultwarden - Password Manager
location /vault/ {
limit_req zone=login burst=5 nodelay;
proxy_pass http://10.0.0.2:8083/;
proxy_ssl_verify off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# n8n - Workflow Automation
location /n8n/ {
limit_req zone=general burst=20 nodelay;
proxy_pass http://10.0.0.2:5678/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# API - FastAPI Backend
location /api/ {
limit_req zone=general burst=50 nodelay;
proxy_pass http://10.0.0.2:8000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Websites - Static Content (Default)
location / {
limit_req zone=general burst=20 nodelay;
proxy_pass http://10.0.0.2:8082/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# ============================================
# eckardt-cloud.duckdns.org - Nextcloud
# ============================================
server {
listen 443 ssl http2;
server_name eckardt-cloud.duckdns.org;
ssl_certificate C:/nginx/ssl/eckardt-cloud.duckdns.org-chain.pem;
ssl_certificate_key C:/nginx/ssl/eckardt-cloud.duckdns.org-key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
location / {
limit_req zone=general burst=50 nodelay;
proxy_pass http://10.0.0.2:8081/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Nextcloud specific
proxy_max_temp_file_size 10240m;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
}
}
# ============================================
# eckardt-git.duckdns.org - Gitea
# ============================================
server {
listen 443 ssl http2;
server_name eckardt-git.duckdns.org;
ssl_certificate C:/nginx/ssl/eckardt-git.duckdns.org-chain.pem;
ssl_certificate_key C:/nginx/ssl/eckardt-git.duckdns.org-key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
location / {
limit_req zone=general burst=30 nodelay;
proxy_pass http://10.0.0.2:3000/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
client_max_body_size 1G;
}
}
}

View File

@@ -0,0 +1,32 @@
# WireGuard Konfiguration - Proxmox Client
# Pfad auf Proxmox: /etc/wireguard/wg0.conf
#
# WICHTIG: PrivateKey und PublicKey muessen fuer jede Installation
# neu generiert werden!
#
# Keys generieren:
# wg genkey | tee privatekey | wg pubkey > publickey
#
# Aktivieren:
# systemctl enable wg-quick@wg0
# systemctl start wg-quick@wg0
[Interface]
# Eigener Private Key (GEHEIM!)
PrivateKey = <PRIVATE_KEY_HIER>
# IP im WireGuard Tunnel-Netzwerk
Address = 10.0.0.2/24
[Peer]
# Public Key des VPS Servers
PublicKey = <VPS_PUBLIC_KEY_HIER>
# VPS Server IP und Port
Endpoint = 217.154.65.205:51820
# Erlaubte IPs (nur Tunnel-Netzwerk)
AllowedIPs = 10.0.0.0/24
# Keepalive fuer NAT-Traversal
PersistentKeepalive = 25

21
docker/.env.template Normal file
View File

@@ -0,0 +1,21 @@
# Proxmox Infrastruktur - Environment Variables
# WICHTIG: Diese Datei kopieren nach .env und Werte anpassen!
# Die .env Datei NIEMALS committen!
# ============================================
# NEXTCLOUD
# ============================================
NEXTCLOUD_DB_PASSWORD=<sicheres-passwort-hier>
NEXTCLOUD_DB_ROOT_PASSWORD=<sicheres-root-passwort-hier>
# ============================================
# VAULTWARDEN
# ============================================
# Admin Token generieren: openssl rand -base64 48
VAULTWARDEN_ADMIN_TOKEN=<admin-token-hier>
# ============================================
# N8N
# ============================================
N8N_USER=admin
N8N_PASSWORD=<sicheres-passwort-hier>

11
docker/.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
# Niemals Secrets committen!
.env
*.env
!.env.template
# Backup-Dateien
*.bak
*.backup
# Logs
*.log

270
docker/docker-compose.yml Normal file
View File

@@ -0,0 +1,270 @@
services:
# ============================================
# NEXTCLOUD - Cloud Storage
# ============================================
nextcloud:
image: nextcloud:latest
container_name: nextcloud
restart: unless-stopped
security_opt:
- apparmor=unconfined
- seccomp=unconfined
ports:
- "8081:80"
volumes:
- /opt/docker/nextcloud/data:/var/www/html
environment:
- MYSQL_HOST=nextcloud-db
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
depends_on:
nextcloud-db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/status.php"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- nextcloud-net
nextcloud-db:
image: mariadb:10
container_name: nextcloud-db
restart: unless-stopped
security_opt:
- apparmor=unconfined
- seccomp=unconfined
volumes:
- /opt/docker/nextcloud/db:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${NEXTCLOUD_DB_ROOT_PASSWORD}
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- nextcloud-net
# ============================================
# VAULTWARDEN - Password Manager
# ============================================
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
security_opt:
- apparmor=unconfined
- seccomp=unconfined
ports:
- "8083:80"
volumes:
- /opt/docker/vaultwarden:/data
environment:
- ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN}
- SIGNUPS_ALLOWED=false
- INVITATIONS_ALLOWED=true
- SHOW_PASSWORD_HINT=false
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/alive"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- vaultwarden-net
# ============================================
# N8N - Workflow Automation
# ============================================
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
security_opt:
- apparmor=unconfined
- seccomp=unconfined
ports:
- "5678:5678"
volumes:
- /opt/docker/n8n:/home/node/.n8n
environment:
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=${N8N_USER}
- N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
- N8N_PATH=/n8n/
- N8N_EDITOR_BASE_URL=https://eckardt-vault.duckdns.org/n8n/
- WEBHOOK_URL=https://eckardt-vault.duckdns.org/n8n/
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:5678/healthz"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- n8n-net
# ============================================
# AUDIOBOOKSHELF - Audiobook Server
# ============================================
audiobookshelf:
image: ghcr.io/advplyr/audiobookshelf:latest
container_name: audiobookshelf
restart: unless-stopped
security_opt:
- apparmor=unconfined
- seccomp=unconfined
ports:
- "13378:80"
volumes:
- /opt/docker/audiobookshelf/audiobooks:/audiobooks
- /opt/docker/audiobookshelf/podcasts:/podcasts
- /opt/docker/audiobookshelf/config:/config
- /opt/docker/audiobookshelf/metadata:/metadata
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:80/healthcheck"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- audiobookshelf-net
# ============================================
# WEBSITES - Static Website Hosting
# ============================================
websites:
image: nginx:alpine
container_name: websites
restart: unless-stopped
security_opt:
- apparmor=unconfined
- seccomp=unconfined
ports:
- "8082:80"
volumes:
- /opt/docker/websites/html:/usr/share/nginx/html:ro
- /opt/docker/websites/conf:/etc/nginx/conf.d:ro
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '0.5'
memory: 128M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- websites-net
# ============================================
# API - FastAPI Backend
# ============================================
api:
image: python:3.11-slim
container_name: api-server
restart: unless-stopped
security_opt:
- apparmor=unconfined
- seccomp=unconfined
working_dir: /app
ports:
- "8000:8000"
volumes:
- /opt/docker/api:/app
command: sh -c "pip install --quiet fastapi uvicorn httpx && python -m uvicorn main:app --host 0.0.0.0 --port 8000"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- api-net
# ============================================
# NETWORKS - Isolierte Netzwerke pro Service
# ============================================
networks:
nextcloud-net:
driver: bridge
vaultwarden-net:
driver: bridge
n8n-net:
driver: bridge
audiobookshelf-net:
driver: bridge
websites-net:
driver: bridge
api-net:
driver: bridge

275
docs/INSTALL.md Normal file
View File

@@ -0,0 +1,275 @@
# Installationsanleitung
Detaillierte Anleitung zur Erstinstallation der Proxmox Infrastruktur.
## Voraussetzungen
### Hardware
- **CPU:** Min. 2 Cores (4 empfohlen)
- **RAM:** Min. 4GB (8GB empfohlen)
- **Speicher:** Min. 50GB SSD
### Software
- Proxmox VE 7.x/8.x oder Debian 11/12 / Ubuntu 22.04+
- Docker CE (wird automatisch installiert)
- WireGuard (fuer externen Zugriff)
### Netzwerk
- Statische IP oder DHCP-Reservierung
- Zugriff auf Port 51820/UDP (WireGuard)
- Domain/Subdomain (z.B. via DuckDNS)
---
## Teil 1: Proxmox Server vorbereiten
### 1.1 Docker installieren
```bash
# System aktualisieren
apt update && apt upgrade -y
# Docker installieren
curl -fsSL https://get.docker.com | sh
# Docker beim Boot starten
systemctl enable docker
systemctl start docker
# Pruefen
docker --version
docker compose version
```
### 1.2 WireGuard installieren
```bash
# WireGuard installieren
apt install wireguard -y
# Keys generieren
wg genkey | tee /etc/wireguard/privatekey | wg pubkey > /etc/wireguard/publickey
# Berechtigungen setzen
chmod 600 /etc/wireguard/privatekey
# Keys anzeigen
cat /etc/wireguard/privatekey
cat /etc/wireguard/publickey
```
### 1.3 WireGuard konfigurieren
```bash
cat > /etc/wireguard/wg0.conf << 'EOF'
[Interface]
PrivateKey = <DEIN_PRIVATE_KEY>
Address = 10.0.0.2/24
[Peer]
PublicKey = <VPS_PUBLIC_KEY>
Endpoint = <VPS_IP>:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
EOF
# Aktivieren
systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0
# Testen
ping 10.0.0.1
```
---
## Teil 2: Repository klonen und konfigurieren
### 2.1 Repository klonen
```bash
cd /opt
git clone https://eckardt-git.duckdns.org/Martin/proxmox-infrastruktur.git
cd proxmox-infrastruktur
```
### 2.2 Environment-Variablen konfigurieren
```bash
# Template kopieren
cp docker/.env.template docker/.env
# Sichere Passwoerter generieren
echo "NEXTCLOUD_DB_PASSWORD=$(openssl rand -hex 16)"
echo "NEXTCLOUD_DB_ROOT_PASSWORD=$(openssl rand -hex 16)"
echo "VAULTWARDEN_ADMIN_TOKEN=$(openssl rand -base64 48)"
echo "N8N_PASSWORD=$(openssl rand -hex 16)"
# Datei bearbeiten und Passwoerter eintragen
nano docker/.env
```
### 2.3 Verzeichnisse erstellen
```bash
# Alle Datenverzeichnisse erstellen
mkdir -p /opt/docker/nextcloud/{data,db}
mkdir -p /opt/docker/vaultwarden
mkdir -p /opt/docker/n8n
mkdir -p /opt/docker/audiobookshelf/{audiobooks,podcasts,config,metadata}
mkdir -p /opt/docker/websites/{html,conf}
mkdir -p /opt/docker/api
mkdir -p /opt/docker/gitea
mkdir -p /opt/backups
mkdir -p /opt/scripts
# Berechtigungen setzen
chown -R 1000:1000 /opt/docker/*
```
---
## Teil 3: Services deployen
### 3.1 Docker Compose kopieren
```bash
cp docker/docker-compose.yml /opt/docker/
cp docker/.env /opt/docker/
```
### 3.2 Container starten
```bash
cd /opt/docker
docker compose pull
docker compose up -d
```
### 3.3 Status pruefen
```bash
docker compose ps
docker compose logs -f
```
---
## Teil 4: Services einrichten
### 4.1 Nextcloud
1. Browser oeffnen: `http://<PROXMOX_IP>:8081`
2. Admin-Account erstellen
3. Datenbank: MySQL/MariaDB
- Host: `nextcloud-db`
- Datenbank: `nextcloud`
- User: `nextcloud`
- Passwort: aus .env
4. Installation abschliessen
### 4.2 Vaultwarden
1. Browser oeffnen: `http://<PROXMOX_IP>:8083`
2. Account erstellen
3. Admin-Panel: `http://<PROXMOX_IP>:8083/admin`
- Token aus .env eingeben
4. Einstellungen anpassen:
- Registrierung deaktivieren
- Invite only aktivieren
### 4.3 Gitea
Separates Repository: [proxmox-gitea](https://eckardt-git.duckdns.org/Martin/proxmox-gitea)
```bash
cd /opt/docker/gitea
# docker-compose.yml aus proxmox-gitea Repository
docker compose up -d
```
1. Browser oeffnen: `http://<PROXMOX_IP>:3000`
2. Datenbank: SQLite3
3. Admin-Account erstellen
### 4.4 n8n
1. Browser oeffnen: `http://<PROXMOX_IP>:5678`
2. Login mit Credentials aus .env
---
## Teil 5: VPS Reverse Proxy (Optional)
Fuer externen Zugriff ueber das Internet.
### 5.1 WireGuard auf VPS
```bash
# Auf Windows VPS mit WireGuard installiert
# Config in C:\Program Files\WireGuard\wg0.conf
[Interface]
PrivateKey = <VPS_PRIVATE_KEY>
Address = 10.0.0.1/24
ListenPort = 51820
[Peer]
PublicKey = <PROXMOX_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
```
### 5.2 nginx auf VPS
```bash
# nginx.conf aus configs/nginx/nginx.conf verwenden
# Pfad auf Windows: C:\nginx\conf\nginx.conf
```
### 5.3 SSL-Zertifikate
```cmd
# win-acme fuer Let's Encrypt
C:\winacme\wacs.exe --target manual --host eckardt-vault.duckdns.org --validation filesystem --webroot C:\nginx\html --store pemfiles --pemfilespath C:\nginx\ssl
```
---
## Teil 6: Automatisierung
### 6.1 Scripts installieren
```bash
cp scripts/*.sh /opt/scripts/
chmod +x /opt/scripts/*.sh
```
### 6.2 Backup Cronjob
```bash
# crontab -e
0 3 * * * /opt/scripts/backup.sh all >> /var/log/backup.log 2>&1
```
### 6.3 Health-Check Cronjob
```bash
# crontab -e
*/5 * * * * /opt/scripts/health-check.sh >> /var/log/health-check.log 2>&1
```
---
## Fertig!
Nach der Installation sollten alle Services laufen:
```bash
# Pruefen
/opt/scripts/health-check.sh
```
Bei Problemen: [TROUBLESHOOTING.md](TROUBLESHOOTING.md)

351
docs/TROUBLESHOOTING.md Normal file
View File

@@ -0,0 +1,351 @@
# Troubleshooting Guide
## Inhaltsverzeichnis
1. [Container Probleme](#1-container-probleme)
2. [Netzwerk Probleme](#2-netzwerk-probleme)
3. [SSL/Zertifikat Probleme](#3-sslzertifikat-probleme)
4. [Service-spezifische Probleme](#4-service-spezifische-probleme)
5. [Backup/Restore Probleme](#5-backuprestore-probleme)
6. [Performance Probleme](#6-performance-probleme)
---
## 1. Container Probleme
### Container startet nicht
**Symptom:** `docker compose up -d` laeuft, aber Container ist nicht aktiv
```bash
# Status pruefen
docker compose ps
# Logs anzeigen
docker logs <container-name>
# Detaillierte Infos
docker inspect <container-name>
```
**Haeufige Ursachen:**
1. **Port bereits belegt**
```bash
# Port pruefen
netstat -tulpn | grep <port>
# Prozess beenden oder Port aendern
```
2. **Volume-Berechtigungen**
```bash
# Berechtigungen korrigieren
chown -R 1000:1000 /opt/docker/<service>
chmod -R 755 /opt/docker/<service>
```
3. **Fehlende .env Datei**
```bash
# Pruefen ob .env existiert
ls -la /opt/docker/.env
# Aus Template erstellen
cp docker/.env.template docker/.env
```
### "Permission denied" auf Proxmox
**Symptom:** `socketpair() failed (13: Permission denied)`
**Loesung:** security_opt in docker-compose.yml:
```yaml
security_opt:
- apparmor=unconfined
- seccomp=unconfined
```
### Container restarts staendig
**Symptom:** Container Status zeigt "Restarting"
```bash
# Exit-Code pruefen
docker inspect --format='{{.State.ExitCode}}' <container>
# Letzten Fehler anzeigen
docker logs --tail 50 <container>
# Health-Check deaktivieren zum Debuggen
docker compose up -d --no-healthcheck <service>
```
---
## 2. Netzwerk Probleme
### WireGuard Tunnel nicht verbunden
**Symptom:** Keine Verbindung zu 10.0.0.x Adressen
```bash
# WireGuard Status
wg show wg0
# Interface pruefen
ip addr show wg0
# Tunnel neu starten
systemctl restart wg-quick@wg0
# Logs pruefen
journalctl -u wg-quick@wg0 -n 50
```
**Checkliste:**
- [ ] PrivateKey/PublicKey korrekt?
- [ ] Endpoint IP:Port erreichbar?
- [ ] Firewall-Regeln auf VPS?
- [ ] PersistentKeepalive gesetzt?
### Service nicht extern erreichbar
```bash
# 1. Container laeuft?
docker ps | grep <service>
# 2. Port offen auf Proxmox?
curl http://localhost:<port>
# 3. WireGuard Tunnel aktiv?
ping 10.0.0.1 # VPS von Proxmox
# 4. nginx Config auf VPS testen
cd C:\nginx && nginx.exe -t
# 5. nginx neu laden
net stop nginx && net start nginx
```
### DNS-Probleme
```bash
# DuckDNS IP pruefen
nslookup eckardt-vault.duckdns.org
# Eigene externe IP pruefen
curl ifconfig.me
# DuckDNS manuell aktualisieren
curl "https://www.duckdns.org/update?domains=eckardt-vault&token=<TOKEN>&ip="
```
---
## 3. SSL/Zertifikat Probleme
### Zertifikat abgelaufen
**Auf Windows VPS:**
```cmd
# Zertifikat erneuern
cd C:\winacme
wacs.exe --renew --force
# nginx neu laden
net stop nginx && net start nginx
```
### Let's Encrypt Rate Limit
**Symptom:** "too many certificates already issued"
**Loesung:**
- 5 Zertifikate pro Domain pro Woche
- Warten oder Subdomain aendern
- Staging-Umgebung zum Testen nutzen
### Mixed Content Warnung
**Symptom:** Browser zeigt "unsichere Inhalte"
**Loesung:** Alle Services muessen HTTPS nutzen
```nginx
# In nginx.conf
proxy_set_header X-Forwarded-Proto $scheme;
```
---
## 4. Service-spezifische Probleme
### Nextcloud
**"Maintenance mode is enabled"**
```bash
docker exec nextcloud php occ maintenance:mode --off
```
**Datei-Upload schlaegt fehl**
```bash
# PHP Limits anpassen
docker exec nextcloud bash -c 'echo "upload_max_filesize=10G" >> /usr/local/etc/php/conf.d/uploads.ini'
docker exec nextcloud bash -c 'echo "post_max_size=10G" >> /usr/local/etc/php/conf.d/uploads.ini'
docker restart nextcloud
```
**"Trusted Domain" Fehler**
```bash
docker exec nextcloud php occ config:system:set trusted_domains 1 --value=eckardt-cloud.duckdns.org
```
### Vaultwarden
**Admin-Seite nicht erreichbar**
```bash
# Admin-Token pruefen
docker logs vaultwarden | grep -i admin
# URL: /admin mit Token aus .env
```
**Sync-Fehler in Clients**
```bash
# Verbindung testen
curl -v https://eckardt-vault.duckdns.org/vault/api/alive
```
### Gitea
**SSH Clone funktioniert nicht**
```bash
# SSH-Verbindung testen
ssh -T -p 2222 git@192.168.178.111
# Authorized Keys pruefen
docker exec gitea cat /data/git/.ssh/authorized_keys
```
**"Unable to find user" nach Restart**
```bash
# Gitea User pruefen
docker exec gitea gitea admin user list
```
### n8n
**Webhooks funktionieren nicht**
```bash
# Webhook-URL pruefen
# Muss WEBHOOK_URL in .env auf externe URL zeigen
docker logs n8n | grep -i webhook
```
---
## 5. Backup/Restore Probleme
### Backup schlaegt fehl
```bash
# Berechtigungen pruefen
ls -la /opt/backups/
# Speicherplatz pruefen
df -h /opt/backups/
# Manuell testen
/opt/scripts/backup.sh nextcloud
```
### Restore durchfuehren
```bash
# Container stoppen
docker compose stop <service>
# Altes Volume loeschen
rm -rf /opt/docker/<service>/*
# Backup entpacken
tar -xzf /opt/backups/<service>_YYYYMMDD.tar.gz -C /opt/docker/<service>/
# Container starten
docker compose up -d <service>
```
---
## 6. Performance Probleme
### Hohe CPU-Last
```bash
# Top Prozesse
docker stats --no-stream
# Ressourcen-Limits pruefen
docker inspect --format='{{.HostConfig.NanoCpus}}' <container>
```
### Speicher voll
```bash
# Docker Cleanup
docker system prune -a --volumes
# Alte Logs loeschen
truncate -s 0 /var/lib/docker/containers/*/*-json.log
# Alte Backups loeschen
find /opt/backups -mtime +30 -delete
```
### Langsame Antwortzeiten
```bash
# Netzwerk-Latenz testen
ping -c 10 10.0.0.2
# Container-Ressourcen
docker stats <container>
# Disk I/O
iostat -x 1 5
```
---
## Diagnose-Befehle Uebersicht
```bash
# Alle Container Status
docker compose ps
# Alle Logs (live)
docker compose logs -f
# Ressourcen-Nutzung
docker stats
# Netzwerke anzeigen
docker network ls
# Volumes anzeigen
docker volume ls
# System-Info
docker system df
# Health-Check ausfuehren
/opt/scripts/health-check.sh
```
---
## Kontakt / Hilfe
- **Gitea Issues:** https://eckardt-git.duckdns.org/Martin/proxmox-infrastruktur/issues
- **Docker Docs:** https://docs.docker.com/
- **Nextcloud Docs:** https://docs.nextcloud.com/
- **Vaultwarden Wiki:** https://github.com/dani-garcia/vaultwarden/wiki

144
scripts/backup.sh Normal file
View File

@@ -0,0 +1,144 @@
#!/bin/bash
# ============================================
# Proxmox Infrastruktur Backup Script
# ============================================
# Ausfuehrung: ./backup.sh [service|all]
# Cronjob: 0 3 * * * /opt/scripts/backup.sh all >> /var/log/backup.log 2>&1
set -euo pipefail
BACKUP_DIR="/opt/backups"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7
# Farben fuer Output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"; }
# Backup-Verzeichnis erstellen
mkdir -p "$BACKUP_DIR"
backup_nextcloud() {
log_info "Starte Nextcloud Backup..."
local backup_file="$BACKUP_DIR/nextcloud_$DATE.tar.gz"
# Maintenance Mode aktivieren
docker exec nextcloud php occ maintenance:mode --on || true
# Daten sichern
tar -czf "$backup_file" \
-C /opt/docker/nextcloud \
data db \
2>/dev/null
# Maintenance Mode deaktivieren
docker exec nextcloud php occ maintenance:mode --off || true
log_info "Nextcloud Backup erstellt: $backup_file ($(du -h "$backup_file" | cut -f1))"
}
backup_vaultwarden() {
log_info "Starte Vaultwarden Backup..."
local backup_file="$BACKUP_DIR/vaultwarden_$DATE.tar.gz"
tar -czf "$backup_file" \
-C /opt/docker \
vaultwarden \
2>/dev/null
log_info "Vaultwarden Backup erstellt: $backup_file ($(du -h "$backup_file" | cut -f1))"
}
backup_gitea() {
log_info "Starte Gitea Backup..."
local backup_file="$BACKUP_DIR/gitea_$DATE.tar.gz"
# Gitea internen Backup-Befehl nutzen
docker exec -u git gitea gitea dump -c /data/gitea/conf/app.ini -f /data/gitea-dump.zip || true
# Dump und Daten sichern
tar -czf "$backup_file" \
-C /opt/docker/gitea \
. \
2>/dev/null
log_info "Gitea Backup erstellt: $backup_file ($(du -h "$backup_file" | cut -f1))"
}
backup_n8n() {
log_info "Starte n8n Backup..."
local backup_file="$BACKUP_DIR/n8n_$DATE.tar.gz"
tar -czf "$backup_file" \
-C /opt/docker \
n8n \
2>/dev/null
log_info "n8n Backup erstellt: $backup_file ($(du -h "$backup_file" | cut -f1))"
}
backup_audiobookshelf() {
log_info "Starte Audiobookshelf Backup..."
local backup_file="$BACKUP_DIR/audiobookshelf_$DATE.tar.gz"
# Nur Config und Metadata, nicht die Audiobooks selbst
tar -czf "$backup_file" \
-C /opt/docker/audiobookshelf \
config metadata \
2>/dev/null
log_info "Audiobookshelf Backup erstellt: $backup_file ($(du -h "$backup_file" | cut -f1))"
}
backup_configs() {
log_info "Starte Config Backup..."
local backup_file="$BACKUP_DIR/configs_$DATE.tar.gz"
tar -czf "$backup_file" \
/opt/docker/docker-compose.yml \
/opt/docker/gitea/docker-compose.yml \
/etc/wireguard/wg0.conf \
2>/dev/null || true
log_info "Config Backup erstellt: $backup_file"
}
cleanup_old_backups() {
log_info "Loesche Backups aelter als $RETENTION_DAYS Tage..."
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
log_info "Cleanup abgeschlossen"
}
backup_all() {
log_info "========== VOLLSTAENDIGES BACKUP GESTARTET =========="
backup_nextcloud
backup_vaultwarden
backup_gitea
backup_n8n
backup_audiobookshelf
backup_configs
cleanup_old_backups
log_info "========== BACKUP ABGESCHLOSSEN =========="
log_info "Backup-Groesse gesamt: $(du -sh "$BACKUP_DIR" | cut -f1)"
}
# Hauptprogramm
case "${1:-all}" in
nextcloud) backup_nextcloud ;;
vaultwarden) backup_vaultwarden ;;
gitea) backup_gitea ;;
n8n) backup_n8n ;;
audiobookshelf) backup_audiobookshelf ;;
configs) backup_configs ;;
all) backup_all ;;
*)
echo "Verwendung: $0 [nextcloud|vaultwarden|gitea|n8n|audiobookshelf|configs|all]"
exit 1
;;
esac

96
scripts/deploy.sh Normal file
View File

@@ -0,0 +1,96 @@
#!/bin/bash
# ============================================
# Proxmox Infrastruktur Deployment Script
# ============================================
# Erstinstallation oder Update der kompletten Infrastruktur
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Root-Check
if [ "$EUID" -ne 0 ]; then
log_error "Bitte als root ausfuehren"
exit 1
fi
log_info "=========================================="
log_info " Proxmox Infrastruktur Deployment"
log_info "=========================================="
# Verzeichnisse erstellen
log_info "Erstelle Verzeichnisse..."
mkdir -p /opt/docker/{nextcloud/{data,db},vaultwarden,n8n,audiobookshelf/{audiobooks,podcasts,config,metadata},websites/{html,conf},api,gitea}
mkdir -p /opt/backups
mkdir -p /opt/scripts
# .env pruefen
if [ ! -f /opt/docker/.env ]; then
log_warn ".env Datei nicht gefunden!"
log_info "Erstelle Template..."
cat > /opt/docker/.env << 'EOF'
# Proxmox Infrastruktur - Environment Variables
NEXTCLOUD_DB_PASSWORD=CHANGE_ME_$(openssl rand -hex 8)
NEXTCLOUD_DB_ROOT_PASSWORD=CHANGE_ME_$(openssl rand -hex 8)
VAULTWARDEN_ADMIN_TOKEN=$(openssl rand -base64 48)
N8N_USER=admin
N8N_PASSWORD=CHANGE_ME_$(openssl rand -hex 8)
EOF
log_warn "WICHTIG: Bearbeite /opt/docker/.env und ersetze die Passwoerter!"
log_warn "Dann erneut ausfuehren."
exit 1
fi
# Docker installieren (falls nicht vorhanden)
if ! command -v docker &> /dev/null; then
log_info "Installiere Docker..."
curl -fsSL https://get.docker.com | sh
systemctl enable docker
systemctl start docker
fi
# Docker Compose pruefen
if ! docker compose version &> /dev/null; then
log_error "Docker Compose nicht gefunden!"
exit 1
fi
# Scripts kopieren
log_info "Kopiere Scripts..."
cp -f scripts/*.sh /opt/scripts/ 2>/dev/null || true
chmod +x /opt/scripts/*.sh 2>/dev/null || true
# Docker Compose kopieren
log_info "Kopiere Docker Compose..."
cp -f docker/docker-compose.yml /opt/docker/
# Container starten
log_info "Starte Container..."
cd /opt/docker
docker compose pull
docker compose up -d
# Status pruefen
log_info "Warte auf Container-Start..."
sleep 10
docker compose ps
log_info "=========================================="
log_info " Deployment abgeschlossen!"
log_info "=========================================="
log_info ""
log_info "Naechste Schritte:"
log_info " 1. Nextcloud einrichten: http://$(hostname -I | awk '{print $1}'):8081"
log_info " 2. Vaultwarden Admin: http://$(hostname -I | awk '{print $1}'):8083/admin"
log_info " 3. Gitea einrichten: http://$(hostname -I | awk '{print $1}'):3000"
log_info ""
log_info "Health Check: /opt/scripts/health-check.sh"
log_info "Backup: /opt/scripts/backup.sh all"

122
scripts/health-check.sh Normal file
View File

@@ -0,0 +1,122 @@
#!/bin/bash
# ============================================
# Proxmox Infrastruktur Health Check Script
# ============================================
# Ausfuehrung: ./health-check.sh
# Cronjob: */5 * * * * /opt/scripts/health-check.sh >> /var/log/health-check.log 2>&1
set -uo pipefail
# Farben fuer Output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
FAILED=0
check_service() {
local name=$1
local url=$2
local expected=${3:-200}
response=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "$url" 2>/dev/null || echo "000")
if [ "$response" = "$expected" ]; then
echo -e "${GREEN}[OK]${NC} $name - HTTP $response"
else
echo -e "${RED}[FAIL]${NC} $name - HTTP $response (erwartet: $expected)"
FAILED=$((FAILED + 1))
fi
}
check_container() {
local name=$1
if docker ps --format '{{.Names}}' | grep -q "^${name}$"; then
status=$(docker inspect --format='{{.State.Health.Status}}' "$name" 2>/dev/null || echo "no-healthcheck")
if [ "$status" = "healthy" ] || [ "$status" = "no-healthcheck" ]; then
echo -e "${GREEN}[OK]${NC} Container $name - Running ($status)"
else
echo -e "${YELLOW}[WARN]${NC} Container $name - $status"
fi
else
echo -e "${RED}[FAIL]${NC} Container $name - Not running"
FAILED=$((FAILED + 1))
fi
}
check_disk() {
local path=$1
local threshold=${2:-90}
usage=$(df "$path" | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$usage" -lt "$threshold" ]; then
echo -e "${GREEN}[OK]${NC} Disk $path - ${usage}% verwendet"
else
echo -e "${RED}[FAIL]${NC} Disk $path - ${usage}% verwendet (Grenze: ${threshold}%)"
FAILED=$((FAILED + 1))
fi
}
check_wireguard() {
if wg show wg0 &>/dev/null; then
latest_handshake=$(wg show wg0 latest-handshakes | awk '{print $2}')
current_time=$(date +%s)
diff=$((current_time - latest_handshake))
if [ "$diff" -lt 180 ]; then
echo -e "${GREEN}[OK]${NC} WireGuard - Verbunden (Handshake vor ${diff}s)"
else
echo -e "${YELLOW}[WARN]${NC} WireGuard - Letzter Handshake vor ${diff}s"
fi
else
echo -e "${RED}[FAIL]${NC} WireGuard - Nicht aktiv"
FAILED=$((FAILED + 1))
fi
}
echo "=========================================="
echo " Proxmox Infrastruktur Health Check"
echo " $(date '+%Y-%m-%d %H:%M:%S')"
echo "=========================================="
echo ""
echo "--- Container Status ---"
check_container "nextcloud"
check_container "nextcloud-db"
check_container "vaultwarden"
check_container "n8n"
check_container "audiobookshelf"
check_container "websites"
check_container "api-server"
check_container "gitea"
echo ""
echo "--- Service Endpoints (Intern) ---"
check_service "Nextcloud" "http://localhost:8081/status.php"
check_service "Vaultwarden" "http://localhost:8083/alive"
check_service "n8n" "http://localhost:5678/healthz"
check_service "Websites" "http://localhost:8082/"
check_service "API" "http://localhost:8000/health"
check_service "Gitea" "http://localhost:3000/api/healthz"
echo ""
echo "--- Netzwerk ---"
check_wireguard
echo ""
echo "--- Disk Usage ---"
check_disk "/" 85
check_disk "/opt/docker" 90
echo ""
echo "=========================================="
if [ $FAILED -eq 0 ]; then
echo -e "${GREEN}Alle Checks bestanden!${NC}"
exit 0
else
echo -e "${RED}$FAILED Check(s) fehlgeschlagen!${NC}"
exit 1
fi