feat(deploy): Standalone-Compose mit Host-Netzwerk für LXC und Traefik auf anderem Server

- docker-compose.standalone.yml: Build und Betrieb im Host-Netzwerk (Docker in unprivilegiertem
  LXC hat kein NAT für Bridge-Netze), Dienste über 127.0.0.1, Postgres nur lokal
- TRUST_PROXY akzeptiert die IP(s) des Reverse Proxys statt nur true/false
- Doku: Traefik-Datei-Konfiguration, Proxmox-Firewall, Ressourcen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
lucashahmannandClaude Opus 5.5 committed 2026-10-13 10:53:06 +02:00
1 parent d45d1821df
commit 9cb9531e78
5 files changed
+209 -6

No files matched your search

+2
View File
@@ -25,6 +25,8 @@ PUBLIC_ORIGIN=https://stats.example.de
# openssl rand -hex 32
INGEST_HMAC_SECRET=
SERVER_ID=atm10
# IP des Reverse Proxys (Traefik), der X-Forwarded-For setzen darf; mehrere kommagetrennt, auch CIDR.
# "true" nur, wenn die API ausschließlich über Traefik erreichbar ist (Compose mit Traefik-Labels).
TRUST_PROXY=true
TIMEZONE=Europe/Berlin
LOG_LEVEL=info
+106
View File
@@ -0,0 +1,106 @@
# ATM10 Stats – eigenständiger Server mit Host-Netzwerk, Traefik läuft auf einem ANDEREN Server.
#
# Für Docker in einem (unprivilegierten) Proxmox-LXC-Container: Dort fehlt oft das NAT für Docker-Bridge-Netze,
# Container kommen dann nicht ins Netz (DNS, Proxy, SFTP). Mit network_mode: host nutzen alle Dienste direkt das
# Netz des LXC-Containers.
#
# cp deploy/.env.example deploy/.env # Werte eintragen (TRUST_PROXY = IP des Traefik-Servers!)
# docker compose -f deploy/docker-compose.standalone.yml --env-file deploy/.env up -d --build
#
# Erreichbar auf dem LXC-Container: web http://<LXC-IP>:3000 api http://<LXC-IP>:3001
# Die Datenbank lauscht nur auf 127.0.0.1. Traefik-Konfiguration: docs/OPERATIONS.md, "Traefik auf einem anderen Server".
name: atm10-stats
x-proxy-build-args: &proxy-build-args
HTTP_PROXY: ${HTTP_PROXY:-}
HTTPS_PROXY: ${HTTPS_PROXY:-}
NO_PROXY: ${NO_PROXY:-}
http_proxy: ${HTTP_PROXY:-}
https_proxy: ${HTTPS_PROXY:-}
no_proxy: ${NO_PROXY:-}
x-backend: &backend
build:
context: ..
dockerfile: backend/Dockerfile
network: host
args: *proxy-build-args
image: atm10-stats/backend:latest
restart: unless-stopped
network_mode: host
env_file: ${ENV_FILE:-.env}
environment:
DATABASE_URL: postgres://atm:${POSTGRES_PASSWORD}@127.0.0.1:5432/atm
HTTP_PROXY: ${HTTP_PROXY:-}
HTTPS_PROXY: ${HTTPS_PROXY:-}
NO_PROXY: ${NO_PROXY:-},localhost,127.0.0.1
depends_on:
db:
condition: service_healthy
services:
db:
image: postgres:16-alpine
restart: unless-stopped
network_mode: host
command: ["postgres", "-c", "listen_addresses=127.0.0.1", "-c", "port=5432"]
environment:
POSTGRES_DB: atm
POSTGRES_USER: atm
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD fehlt}
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U atm -d atm"]
interval: 10s
timeout: 5s
retries: 10
api:
<<: *backend
command: ["node", "dist/server.js"]
worker:
<<: *backend
command: ["node", "dist/worker.js"]
healthcheck:
disable: true
web:
build:
context: ..
dockerfile: web/Dockerfile
network: host
args:
<<: *proxy-build-args
# Next.js resolves the /api rewrite at build time: the API is on the same host.
API_INTERNAL_URL: http://127.0.0.1:3001
image: atm10-stats/web:latest
restart: unless-stopped
network_mode: host
environment:
API_INTERNAL_URL: http://127.0.0.1:3001
depends_on: [api]
backup:
image: postgres:16-alpine
restart: unless-stopped
network_mode: host
environment:
PGHOST: 127.0.0.1
PGUSER: atm
PGDATABASE: atm
PGPASSWORD: ${POSTGRES_PASSWORD}
BACKUP_KEEP_DAYS: ${BACKUP_KEEP_DAYS:-14}
volumes:
- ./backup.sh:/backup.sh:ro
- backups:/backups
entrypoint: ["/bin/sh", "/backup.sh", "loop"]
depends_on:
db:
condition: service_healthy
volumes:
db-data:
backups: