- **Zum Update:** Das erste Update auf diese Version übernimmt auch die `docker-compose.yml` (siehe unten; braucht wie die
CLI-Aktualisierung `cosign` und `cosign.pub`), migriert die Datenbank (Revision 0032; ein Rollback spielt die Sicherung davor
zurück) und stellt das Backend auf einen unprivilegierten Benutzer um. Nichts davon braucht einen Handgriff.
- **Nur ein Backend führt die Hintergrunddienste aus (HA, Stufe H0):** Laufen zwei Backends an derselben Datenbank, verschickten
beide jeden Alarm und brachen Zyklen mit `UniqueViolation` ab. Jetzt führt nur der Prozess mit der Leader-Sperre in der
Datenbank die neun Hintergrundschleifen aus; die anderen warten in Bereitschaft und übernehmen innerhalb einer halben Minute,
wenn der Leader ausfällt. Verliert der Leader seine Datenbankverbindung, hält er alle Schleifen sofort an (geprüft alle 5 Sekunden
und vor jedem Durchlauf). An einer Replica startet kein Leader. Rolle in `GET /api/health` und als Metrik `opnexus_leader`.
Zwei gleichzeitige Erststarts legen das Admin-Konto nur einmal an.
- **Umzug und Kaltreserve (HA, Stufe H1):** `opnexus backup --full --with-env --with-ca` nimmt zusätzlich die `.env` und die
interne CA des Proxys mit, `opnexus restore DATEI --with-env --with-ca` spielt sie zurück (ohne Datenbank-Zugang, Version und
Adressen des Zielservers; die CA bleibt dieselbe, Browser vertrauen weiter). Neu: `opnexus migrate-host BENUTZER@ZIEL` zieht
eine Installation in einem Schritt auf einen anderen Server um (Vorprüfung, Quelle anhalten, Sicherung mit Zufalls-Passphrase,
Restore, Kontrolle). Im Lab 90 Sekunden mit drei Firewalls. `opnexus status` zeigt das Alter der letzten Vollsicherung.
Handbuch: „Umzug und Notfall“.
- **Betriebseinstellungen im Webinterface:** Was bisher nur in der `.env` oder gar nur im Code stand, lässt sich unter
Einstellungen › Betriebseinstellungen ändern: Sitzungsdauer und Anmeldesperren, Bestätigungsfrist beim Ausrollen, Zeitlimit für
Firewall-Anfragen, Messintervalle und Aufbewahrung, Intervall der Versionsprüfung, Heartbeat-Adresse, CA des Mailservers (PEM
einfügen statt Datei einbinden), Zeitlimit Mailversand. Mit Grenzen, Standardwert, Zurücksetzen und Audit-Eintrag. Ein Wert in der
`.env` hat weiter Vorrang und wird als „vom Server“ angezeigt. Adressen, TLS und Datenbank-Zugang bleiben bewusst in der `.env`.
- **Heartbeat für einen externen Überwacher:** Die Heartbeat-Adresse (nur `https://`) wird nach jedem erfolgreichen Prüfzyklus
aufgerufen; bleibt der Aufruf aus, schlägt der Überwacher Alarm. Die Adresse wird nie angezeigt oder protokolliert.
- **Updates bringen die Compose-Datei mit:** Bisher tauschte `opnexus update` nur die Images; Änderungen an der
`docker-compose.yml` (neue Variablen, Härtung) kamen bei bestehenden Installationen nie an. Jetzt übernimmt das Update die Datei
des Zielreleases aus dem signierten Updater-Image, sichert die alte als `docker-compose.yml.bak-<version>` und legt sie beim
Rollback zurück. Eine hier angepasste Datei wird nicht überschrieben (neue Fassung als `docker-compose.yml.new`); eigene
Anpassungen gehören in `docker-compose.override.yml`.
- **Alarm „Platte des OPNexus-Servers fast voll“** (standardmäßig an, ab 90 %, einstellbar): eine volle Platte hält die Datenbank
an und damit jeden anderen Alarm. Auch im Dashboard und als Metrik `opnexus_server_disk_used_percent`.
- **Härtung aus einem externen Audit:**
- **Kein root mehr in den Containern:** Backend (uid 10001) und Frontend (`node`) laufen unprivilegiert, ohne neue Rechte (`no-new-privileges`), das Frontend zusätzlich
ohne Capabilities. Das Backend startet über `backend/scripts/start.sh` noch kurz als root, stellt die vorhandenen Datenvolumes einmalig um und gibt dann alle Rechte ab:
ein Update braucht keinen Handgriff, ein Rückweg auf eine ältere Version bleibt möglich. Notausgang für Sonderfälle: `OPNEXUS_RUN_AS_ROOT=1` in der `.env`.
`wg-hub` (braucht root für WireGuard) und `gui-gateway` (läuft schon als nobody) sind unverändert. Der Proxy (Caddy) und der optionale Updater (Docker-Socket) laufen weiter wie bisher.
- **Vollsicherung konsistent:** Ändern sich Geheimnisse, während die Sicherung läuft (jemand legt gerade ein Objekt an oder löscht eines), wird sie bis zu dreimal wiederholt;
gelingt das nicht, bricht sie mit einer klaren Meldung ab, statt ein unstimmiges Archiv zu schreiben.
- **Zieladress-Schutz überall:** Audit-Export (Webhook und Syslog), Offsite-S3 und der Update-Feed verbinden nur noch zu Adressen, die die Prüfung bestanden haben
(kein Loopback, Link-Local, Metadaten-Dienst; auch nicht über DNS-Rebinding oder Weiterleitungen). Adressen im eigenen Netz bleiben erlaubt. Der Update-Feed wird beim Lesen auf 1 MB begrenzt, nicht erst danach.
- **Fehlende Basis-Rechte werden sichtbar:** Fehlen dem API-Schlüssel schon die Rechte für die Grundmessungen (Speicher, Last, Platte), schlug das ganze Sampling still fehl und der
Rechte-Alarm konnte nie auslösen. Jetzt entsteht ein Befund „Grundwerte“ (Recht „Lobby: Dashboard“), der sich nach Korrektur von selbst schließt.
- **Installation:** Die `INSTALL.txt` im Bundle und die Anleitung auf der Website legen die `.env` jetzt mit `install -m 600` an (nur für dich lesbar), statt mit `cp`.
- **Oberfläche:** Die Aktionsknöpfe der Backup-Tabelle auf der Host-Seite werden auf schmalen Bildschirmen als Symbole gezeigt, statt abgeschnitten zu werden.
330 lines
15 KiB
YAML
330 lines
15 KiB
YAML
name: opnexus
|
|
|
|
# Dieses File enthält nur fertige Release-Images (kein `build:`) und ist
|
|
# damit zugleich das Compose-File des Release-Bundles.
|
|
# - Fertige Release-Images: in .env OPNEXUS_IMAGE_REPO und OPNEXUS_VERSION
|
|
# setzen (siehe .env.example), dann `opnexus update` oder
|
|
# docker compose pull && docker compose up -d --no-build
|
|
# - Entwicklung/Selbstbau aus dem Repo: docker-compose.override.yml wird
|
|
# automatisch mitgeladen und ergänzt die Build-Kontexte:
|
|
# docker compose up -d --build
|
|
# (taggt lokal als local/opnexus-<dienst>:latest)
|
|
|
|
# Shared bound-size log driver — without this, Docker's default json-file
|
|
# driver keeps every log line forever, which on a long-running self-hosted
|
|
# install can quietly fill the disk (this has already happened once here
|
|
# via accumulated build cache, see the 2026-09-12 health audit — logs are
|
|
# the same failure mode).
|
|
x-logging: &default-logging
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
restart: unless-stopped
|
|
logging: *default-logging
|
|
# Docker's default 64MB /dev/shm is too small for Postgres's parallel
|
|
# vacuum/query workers on anything but a toy dataset — found the hard
|
|
# way running VACUUM on a multi-GB table (see docs/HANDBUCH.md's "Logs" section for how
|
|
# large that table gets). Official Postgres image docs recommend raising this.
|
|
shm_size: "256mb"
|
|
environment:
|
|
# Datenbank- und Benutzername. Wirken nur beim allerersten Start eines
|
|
# leeren Volumes; eine bestehende Installation behält ihre Namen und
|
|
# trägt sie in .env ein (siehe docs/HANDBUCH.md, "Datenbank-Namen").
|
|
POSTGRES_DB: ${POSTGRES_DB:-opnexus}
|
|
POSTGRES_USER: ${POSTGRES_USER:-opnexus}
|
|
# No insecure fallback on purpose — a guessable baked-in default
|
|
# would ship as public, well-known source. Set it in .env.
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env before starting (see .env.example)}
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
# No host port published — only reachable from other containers on
|
|
# this stack's own network. Keeps us out of "which host ports are
|
|
# free" territory entirely for this service.
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\""]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
# Nightly logical dump of OPNexus's OWN database (users, rules, NAT,
|
|
# VPN/cert entities, audit trail, deployment history — everything
|
|
# except the secret material, which never touches Postgres in the
|
|
# first place, see the *_secret_store.py modules). This is distinct
|
|
# from the app's own backup feature under /hosts/{id}/backups, which
|
|
# backs up the MANAGED FIREWALLS' configs, not OPNexus's own data —
|
|
# before this, a lost/corrupted postgres_data volume had no recovery
|
|
# path at all. Reuses the postgres image directly (pg_dump is already
|
|
# in it) rather than adding a new image to build/maintain.
|
|
# Excludes firewall_log_entries/host_resource_samples: high-volume,
|
|
# disposable operational history (see docs/HANDBUCH.md's "Logs" section for
|
|
# how large these get) rather than
|
|
# config a disaster recovery actually needs — including them would
|
|
# make the backup itself multi-GB and a disk-usage risk in its own
|
|
# right, working against the point of this service.
|
|
postgres-backup:
|
|
image: postgres:16-alpine
|
|
restart: unless-stopped
|
|
logging: *default-logging
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
environment:
|
|
PGPASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env before starting (see .env.example)}
|
|
volumes:
|
|
- postgres_backups:/backups
|
|
entrypoint: ["sh", "-c"]
|
|
command:
|
|
- |
|
|
set -e
|
|
while true; do
|
|
ts=$$(date +%Y%m%d-%H%M%S)
|
|
echo "postgres-backup: dumping to /backups/opnexus-$$ts.dump"
|
|
pg_dump -h postgres -U ${POSTGRES_USER:-opnexus} -d ${POSTGRES_DB:-opnexus} -F c \
|
|
--exclude-table=firewall_log_entries --exclude-table=host_resource_samples \
|
|
-f "/backups/opnexus-$$ts.dump"
|
|
find /backups -name 'opnexus-*.dump' -mtime +14 -delete
|
|
sleep 86400
|
|
done
|
|
|
|
backend:
|
|
image: ${OPNEXUS_IMAGE_REPO:-local}/opnexus-backend:${OPNEXUS_VERSION:-latest}
|
|
restart: unless-stopped
|
|
logging: *default-logging
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
environment:
|
|
DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-opnexus}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env before starting (see .env.example)}@postgres:5432/${POSTGRES_DB:-opnexus}
|
|
OPNSENSE_SECRET_DIR: /data/opnsense-secrets
|
|
OPNSENSE_BACKUP_DIR: /data/opnsense-backups
|
|
IPSEC_PSK_SECRET_DIR: /data/ipsec-psk-secrets
|
|
OPENVPN_KEY_SECRET_DIR: /data/openvpn-key-secrets
|
|
WIREGUARD_KEY_SECRET_DIR: /data/wireguard-key-secrets
|
|
CERT_KEY_SECRET_DIR: /data/cert-key-secrets
|
|
ACME_SECRET_DIR: /data/acme-secrets
|
|
TOTP_SECRET_DIR: /data/totp-secrets
|
|
NOTIFICATION_SECRET_DIR: /data/notification-secrets
|
|
OVERLAY_DIR: /data/overlay
|
|
ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}
|
|
ADMIN_PASSWORD: ${ADMIN_PASSWORD:-}
|
|
FRONTEND_ORIGIN: ${FRONTEND_ORIGIN:-}
|
|
COOKIE_SECURE: ${COOKIE_SECURE:-false}
|
|
TRUST_PROXY_HEADERS: ${TRUST_PROXY_HEADERS:-false}
|
|
UPDATE_CHECK_URL: ${UPDATE_CHECK_URL:-}
|
|
OPNEXUS_IMAGE_REPO: ${OPNEXUS_IMAGE_REPO:-}
|
|
# 1 = Backend wie früher als root betreiben (Notausgang, siehe backend/scripts/start.sh).
|
|
OPNEXUS_RUN_AS_ROOT: ${OPNEXUS_RUN_AS_ROOT:-0}
|
|
ALLOW_INSECURE_FIREWALL_URLS: ${ALLOW_INSECURE_FIREWALL_URLS:-false}
|
|
ALLOW_INSECURE_SMTP_AUTH: ${ALLOW_INSECURE_SMTP_AUTH:-false}
|
|
SMTP_CA_FILE: ${SMTP_CA_FILE:-}
|
|
UPDATE_CHECK_INTERVAL_HOURS: ${UPDATE_CHECK_INTERVAL_HOURS:-12}
|
|
# Optionaler Heartbeat an einen externen Überwacher (nur https://), siehe Handbuch.
|
|
HEARTBEAT_URL: ${HEARTBEAT_URL:-}
|
|
# Optionaler Updater-Dienst (Profil "updater", siehe unten). Ohne ihn
|
|
# zeigt das Webinterface nur an, wie man ihn aktiviert.
|
|
UPDATER_URL: ${UPDATER_URL:-http://updater:8080}
|
|
# Optionaler GUI-Fernzugriff (Profil "gui", siehe gui-gateway unten).
|
|
# Leer = aus; das Backend lässt den Schalter dann nicht einschalten.
|
|
OPNEXUS_GUI_SITES: ${OPNEXUS_GUI_SITES:-}
|
|
GUI_GATEWAY_TOKEN: ${GUI_GATEWAY_TOKEN:-}
|
|
volumes:
|
|
- secrets:/data/opnsense-secrets
|
|
- backups:/data/opnsense-backups
|
|
- ipsec_psk_secrets:/data/ipsec-psk-secrets
|
|
- openvpn_key_secrets:/data/openvpn-key-secrets
|
|
- wireguard_key_secrets:/data/wireguard-key-secrets
|
|
- cert_key_secrets:/data/cert-key-secrets
|
|
- acme_secrets:/data/acme-secrets
|
|
- totp_secrets:/data/totp-secrets
|
|
- notification_secrets:/data/notification-secrets
|
|
# Management-Overlay: Konfiguration für den wg-hub und dessen Status.
|
|
- overlay_state:/data/overlay
|
|
# Gleiches Volume wie der postgres-backup-Service: hier landet das
|
|
# automatische Sicherheits-Backup vor einer Schema-Migration.
|
|
- postgres_backups:/backups
|
|
# Zugriffstoken des Updaters (nur lesen). Leer, solange der Updater
|
|
# nicht aktiviert ist.
|
|
- updater_state:/updater:ro
|
|
# Das Backend startet als root nur, um die Volumes umzustellen, und läuft dann
|
|
# als uid 10001 (backend/scripts/start.sh). Neue Rechte kann es nicht mehr erlangen.
|
|
security_opt: ["no-new-privileges:true"]
|
|
# Bound to loopback only by default — reachable from this host, not
|
|
# the network. Set BIND_ADDRESS in .env (e.g. to 0.0.0.0, or a
|
|
# specific interface IP) for network-wide access instead of editing
|
|
# this file — see docs/HANDBUCH.md's "Zugriff aus dem Netz und TLS" for the TLS-proxy
|
|
# alternative, which is safer than widening this directly.
|
|
ports:
|
|
- "${BIND_ADDRESS:-127.0.0.1}:${BACKEND_PORT:-8100}:8000"
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health', timeout=3)"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
|
|
frontend:
|
|
image: ${OPNEXUS_IMAGE_REPO:-local}/opnexus-frontend:${OPNEXUS_VERSION:-latest}
|
|
restart: unless-stopped
|
|
logging: *default-logging
|
|
environment:
|
|
# Docker always sets HOSTNAME=<container-id> in the environment,
|
|
# and Next.js's standalone server.js binds to `process.env.HOSTNAME
|
|
# || '0.0.0.0'` — so without this override it silently listens only
|
|
# on the container's own IP, never on 127.0.0.1. Harmless for the
|
|
# published port (Docker's NAT reaches the container IP directly,
|
|
# not via loopback) but breaks any in-container check (e.g. the
|
|
# healthcheck below) that queries localhost.
|
|
HOSTNAME: "0.0.0.0"
|
|
# Läuft als unprivilegierter Benutzer (frontend/Dockerfile) und braucht keine
|
|
# Capabilities.
|
|
cap_drop: ["ALL"]
|
|
security_opt: ["no-new-privileges:true"]
|
|
depends_on:
|
|
backend:
|
|
condition: service_healthy
|
|
# Same rationale and same BIND_ADDRESS override as the backend
|
|
# service above.
|
|
ports:
|
|
- "${BIND_ADDRESS:-127.0.0.1}:${FRONTEND_PORT:-3100}:3000"
|
|
healthcheck:
|
|
test: ["CMD", "node", "-e", "require('http').get('http://127.0.0.1:3000/login', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
|
|
# TLS termination in front of everything. The only service meant to be
|
|
# reachable from the network; backend/frontend stay on 127.0.0.1.
|
|
proxy:
|
|
image: ${OPNEXUS_IMAGE_REPO:-local}/opnexus-proxy:${OPNEXUS_VERSION:-latest}
|
|
restart: unless-stopped
|
|
logging: *default-logging
|
|
depends_on:
|
|
backend:
|
|
condition: service_healthy
|
|
frontend:
|
|
condition: service_healthy
|
|
environment:
|
|
OPNEXUS_SITES: ${OPNEXUS_SITES:-localhost}
|
|
OPNEXUS_DEFAULT_SNI: ${OPNEXUS_DEFAULT_SNI:-localhost}
|
|
OPNEXUS_GUI_SITES: ${OPNEXUS_GUI_SITES:-https://localhost:9441}
|
|
ports:
|
|
- "${PROXY_BIND_ADDRESS:-0.0.0.0}:${PROXY_HTTPS_PORT:-443}:443"
|
|
- "${PROXY_BIND_ADDRESS:-0.0.0.0}:${PROXY_HTTP_PORT:-80}:80"
|
|
# Slot-Ports des GUI-Fernzugriffs (Profil "gui"). Standardmäßig nur auf
|
|
# 127.0.0.1; ohne den gui-gateway-Dienst antworten sie nur mit 502.
|
|
# Host- und Container-Port sind absichtlich gleich: die Ports stehen so
|
|
# auch in OPNEXUS_GUI_SITES, und der Proxy meldet dem Gateway den Port,
|
|
# auf dem die Verbindung ankam.
|
|
# Ohne GUI_PORTS belegt Docker zufällige freie Host-Ports: ein Update darf
|
|
# den Proxy nicht daran scheitern lassen, dass 9441-9444 schon vergeben
|
|
# sind (z. B. Portainer auf 0.0.0.0:9443). Zum Einschalten GUI_PORTS setzen.
|
|
- "${GUI_BIND_ADDRESS:-127.0.0.1}:${GUI_PORTS:-}:${GUI_PORTS:-9441-9444}"
|
|
volumes:
|
|
- caddy_data:/data
|
|
- caddy_config:/config
|
|
|
|
# ── Optional: Management-Overlay (WireGuard-Hub) ─────────────────────
|
|
# Standardmäßig NICHT gestartet. Aktivieren mit COMPOSE_PROFILES=overlay in
|
|
# .env und `docker compose up -d`. Damit erreicht OPNexus auch Firewalls hinter
|
|
# NAT/CGNAT: sie wählen sich per WireGuard hier ein (UDP-Port ${OVERLAY_PORT:-51820}
|
|
# muss vom Internet erreichbar sein). Gleiches Image wie das Backend, mit
|
|
# NET_ADMIN nur für die WireGuard-Schnittstelle. Einrichtung: Handbuch,
|
|
# "Firewalls hinter NAT".
|
|
wg-hub:
|
|
image: ${OPNEXUS_IMAGE_REPO:-local}/opnexus-backend:${OPNEXUS_VERSION:-latest}
|
|
profiles: ["overlay"]
|
|
restart: unless-stopped
|
|
logging: *default-logging
|
|
command: ["python", "-m", "app.overlay_hub"]
|
|
cap_add:
|
|
- NET_ADMIN
|
|
sysctls:
|
|
net.ipv4.ip_forward: "0"
|
|
environment:
|
|
OVERLAY_DIR: /data/overlay
|
|
volumes:
|
|
- overlay_state:/data/overlay
|
|
ports:
|
|
- "${OVERLAY_PORT:-51820}:51820/udp"
|
|
|
|
# ── Optional: GUI-Fernzugriff auf verwaltete Firewalls ──────────────
|
|
# Standardmäßig NICHT gestartet und dreifach aus: Profil "gui"
|
|
# (COMPOSE_PROFILES=gui), GUI_BIND_ADDRESS (Standard 127.0.0.1) und der
|
|
# Schalter unter Einstellungen. Gleiches Image wie das Backend, aber ohne
|
|
# Datenbank, ohne Secret-Volumes und ohne eigene Ports: der Proxy terminiert
|
|
# TLS auf den Slot-Ports und leitet hierher weiter; mit dem Backend spricht
|
|
# das Gateway nur über /internal/gui/* (GUI_GATEWAY_TOKEN). Siehe Handbuch,
|
|
# "Firewall-Oberfläche über OPNexus".
|
|
gui-gateway:
|
|
image: ${OPNEXUS_IMAGE_REPO:-local}/opnexus-backend:${OPNEXUS_VERSION:-latest}
|
|
profiles: ["gui"]
|
|
restart: unless-stopped
|
|
logging: *default-logging
|
|
command: ["python", "-m", "app.gui_gateway"]
|
|
depends_on:
|
|
backend:
|
|
condition: service_healthy
|
|
environment:
|
|
GUI_GATEWAY_TOKEN: ${GUI_GATEWAY_TOKEN:-}
|
|
OPNEXUS_GUI_SITES: ${OPNEXUS_GUI_SITES:-}
|
|
GUI_BACKEND_URL: http://backend:8000
|
|
user: "65534:65534"
|
|
read_only: true
|
|
cap_drop: ["ALL"]
|
|
security_opt: ["no-new-privileges:true"]
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import socket; socket.create_connection(('127.0.0.1', 8080), 3).close()"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 5s
|
|
|
|
# ── Optional: Updates aus dem Webinterface ──────────────────────────
|
|
# Standardmäßig NICHT gestartet. Aktivieren mit COMPOSE_PROFILES=updater in
|
|
# .env und `docker compose up -d`. Dies ist der einzige Container mit
|
|
# Zugriff auf den Docker-Socket (= root-gleiche Rechte auf diesem Host): er
|
|
# hat keine veröffentlichten Ports, ist nur mit seinem Token ansprechbar
|
|
# und kann nur "aktualisieren"/"zurückrollen" (updater/server.py). Das
|
|
# Backend selbst bekommt den Socket nie. Nur für Release-Images
|
|
# (OPNEXUS_IMAGE_REPO gesetzt).
|
|
updater:
|
|
profiles: ["updater"]
|
|
image: ${OPNEXUS_IMAGE_REPO:-local}/opnexus-updater:${OPNEXUS_VERSION:-latest}
|
|
restart: unless-stopped
|
|
logging: *default-logging
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
# Das Verzeichnis mit docker-compose.yml und .env (der Updater schreibt
|
|
# nur OPNEXUS_VERSION und .opnexus-update-state hinein).
|
|
- .:/project
|
|
- updater_state:/state
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/health', timeout=3)"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 5s
|
|
|
|
volumes:
|
|
updater_state:
|
|
postgres_data:
|
|
postgres_backups:
|
|
secrets:
|
|
backups:
|
|
ipsec_psk_secrets:
|
|
openvpn_key_secrets:
|
|
wireguard_key_secrets:
|
|
cert_key_secrets:
|
|
acme_secrets:
|
|
totp_secrets:
|
|
notification_secrets:
|
|
overlay_state:
|
|
caddy_data:
|
|
caddy_config:
|