Zum Inhalt springen

Produktions-Stack

  • Ein Linux-Host mit Docker Engine und dem Docker-Compose-Plugin.
  • Die Ports 80 und 443 für Ihre Benutzer erreichbar (oder beliebige andere Ports, in .env festgelegt).
  • Für Let’s-Encrypt-Zertifikate: ein DNS-Name, der auf den Host zeigt, und die Ports 80 und 443 aus dem Internet erreichbar.

Auditix wird als drei Images (frontend, backend, updater) in der Auditix-Registry rg.fr-par.scw.cloud/auditix veröffentlicht und immer mit demselben Tag bereitgestellt. Die Compose-Datei ergänzt die Dienste, auf die sie angewiesen sind:

Dienst Aufgabe
gateway Der einzige veröffentlichte Dienst: liefert Auditix über HTTP und HTTPS aus.
frontend Die Weboberfläche.
backend Die Anwendung. Wendet Datenbankänderungen beim Start selbst an.
updater Spielt die Updates ein, die unter Einstellungen › Plattform › Update gestartet werden. Optional.
orchestrator Startet und stoppt die Worker-Container, die die Hintergrundarbeit erledigen.
developer Die Referenz der externen API, unter /developer.
logs Leitet die Protokolle an die Syslog-Server von Einstellungen › Plattform › Protokolle weiter.
rabbitmq Warteschlangen der Hintergrundarbeit.
mercure Echtzeit-Updates der Oberfläche.
database PostgreSQL: Hier liegen sämtliche Daten.

Die Dienste updater und orchestrator haben Zugriff auf Docker. Sie wirken ausschließlich auf die Container ihrer eigenen Installation (das aus demselben Ordner bereitgestellte Compose-Projekt), nie auf andere Container des Hosts.

  1. Bei der Registry anmelden (überspringen Sie diesen Schritt, wenn die Registry öffentlich ist), mit einem geheimen Scaleway-API-Schlüssel, der die Registry lesen darf:

    Terminal-Fenster
    docker login rg.fr-par.scw.cloud/auditix -u nologin
    # Password: your Scaleway API secret key
  2. Installationsordner anlegen:

    Terminal-Fenster
    mkdir -p /opt/auditix && cd /opt/auditix
  3. compose.yaml anlegen, mit dem Inhalt weiter unten.

  4. .env anlegen, nur für root lesbar (chmod 600 .env), und jedes Geheimnis einmalig mit openssl rand -hex 32 füllen:

    Terminal-Fenster
    # "latest": updated from Settings › Platform › Update. Or a fixed release (vX.Y.Z).
    AUDITIX_VERSION=latest
    HTTP_PORT=80
    HTTPS_PORT=443
    # Generate each once with: openssl rand -hex 32
    APP_SECRET=
    POSTGRES_PASSWORD=
    MERCURE_JWT_SECRET=
    RABBITMQ_PASSWORD=
    GATEWAY_SECRET=
    UPDATER_SECRET=
  5. Starten:

    Terminal-Fenster
    docker compose pull
    docker compose up -d
    docker compose ps # every service should be "healthy"
  6. Anmelden unter http://<host> mit dem Standardadministrator admin / password. Auditix verlangt vor allem anderen ein neues Passwort: Legen Sie es sofort fest, bevor Sie den Dienst zugänglich machen.

name: auditix
# Every service hands its output to Docker's syslog driver, towards the log collector, which
# forwards it to the syslog servers of Settings › Platform › Logs.
x-logging: &logging
driver: syslog
options:
syslog-address: udp://127.0.0.1:15013
syslog-format: rfc5424
tag: "{{.Name}}"
services:
# The only published service. HTTPS and the certificate are set in Settings › Platform › Web
# access; the gateway reads them from the backend.
gateway:
logging: *logging
image: traefik:v3.7
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.forwardedHeaders.trustedIPs=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1/32
- --entrypoints.websecure.forwardedHeaders.trustedIPs=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1/32
- --providers.http.endpoint=http://backend:8080/internal/gateway
- --providers.http.pollInterval=5s
- --providers.http.headers.X-Gateway-Secret=${GATEWAY_SECRET:?Set GATEWAY_SECRET in .env}
- --certificatesresolvers.letsencrypt.acme.storage=/data/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.letsencrypt-staging.acme.storage=/data/acme-staging.json
- --certificatesresolvers.letsencrypt-staging.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.letsencrypt-staging.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
- --ping=true
- --global.checkNewVersion=false
- --global.sendAnonymousUsage=false
ports:
- "${HTTP_PORT:-80}:80"
- "${HTTPS_PORT:-443}:443"
volumes:
- gateway:/data
healthcheck:
test: ["CMD", "traefik", "healthcheck", "--ping"]
interval: 10s
timeout: 3s
retries: 6
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
frontend:
logging: *logging
image: rg.fr-par.scw.cloud/auditix/frontend:${AUDITIX_VERSION:-latest}
environment:
BACKEND_URL: http://backend:8080
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
backend:
logging: *logging
image: rg.fr-par.scw.cloud/auditix/backend:${AUDITIX_VERSION:-latest}
environment: &backend-environment
APP_SECRET: ${APP_SECRET:?Set APP_SECRET in .env}
DATABASE_URL: postgresql://auditix:${POSTGRES_PASSWORD}@database:5432/auditix?serverVersion=18&charset=utf8
MERCURE_URL: http://mercure/.well-known/mercure
MERCURE_JWT_SECRET: ${MERCURE_JWT_SECRET:?Set MERCURE_JWT_SECRET in .env}
MESSENGER_TRANSPORT_DSN: amqp://auditix:${RABBITMQ_PASSWORD:?Set RABBITMQ_PASSWORD in .env}@rabbitmq:5672/%2f
GATEWAY_SECRET: ${GATEWAY_SECRET}
UPDATER_SECRET: ${UPDATER_SECRET:-}
LOGS_COLLECTOR_HOST: logs
# Never published: the internal API is only for the frontend; integrations use the
# external API (/api/v1) through the gateway.
volumes:
- logs-config:/app/var/logs-collector
depends_on:
database:
condition: service_healthy
rabbitmq:
condition: service_healthy
restart: unless-stopped
# Applies the updates started from Settings › Platform › Update. The only service with access to
# Docker: it only acts on the services of this file (its own compose project), never on other
# containers of the host. Optional: without it, update by hand (see Update below).
updater:
logging: *logging
image: rg.fr-par.scw.cloud/auditix/updater:${AUDITIX_VERSION:-latest}
environment:
BACKEND_URL: http://backend:8080
UPDATER_SECRET: ${UPDATER_SECRET:?Set UPDATER_SECRET in .env}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# The installation directory: the backups taken before updates in backups/, and its .env
# when AUDITIX_VERSION is a fixed release.
- .:/install
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
# Runs the background work: starts and stops the worker containers (the backend image, started
# with the "worker" command) as the pools of Settings › Platform › Workers ask, a fixed number or
# following the backlog of their queues. Same image as the updater; it only acts on the worker
# containers it creates for this installation. Without it, no worker runs (see Scale the workers).
orchestrator:
logging: *logging
image: rg.fr-par.scw.cloud/auditix/updater:${AUDITIX_VERSION:-latest}
entrypoint: ["auditix-orchestrator"]
environment:
BACKEND_URL: http://backend:8080
UPDATER_SECRET: ${UPDATER_SECRET:?Set UPDATER_SECRET in .env}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
# The developer portal: the reference of the external API, at /developer.
developer:
logging: *logging
image: scalarapi/api-reference:0.6.12
environment:
BASE_PATH: /developer/scalar
API_REFERENCE_CONFIG: '{"sources":[{"url":"/api/v1/openapi.json","title":"Auditix API"}],"theme":"none","withDefaultFonts":false,"customCss":"@import url(\"/theme/developer\");","favicon":"/icon.svg","metaData":{"title":"Auditix API"},"defaultHttpClient":{"targetKey":"shell","clientKey":"curl"},"showDeveloperTools":"never","agent":{"disabled":true},"mcp":{"disabled":true}}'
restart: unless-stopped
# The log collector: forwards the logs to the syslog servers of the settings.
logs:
image: timberio/vector:0.59.0-alpine
command: ["--config-dir", "/etc/vector/auditix", "--watch-config"]
ports:
- "127.0.0.1:15013:5514/udp"
volumes:
- logs-config:/etc/vector/auditix:ro
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
# Queues of the background work.
rabbitmq:
logging: *logging
image: rabbitmq:4.3-management-alpine
hostname: rabbitmq
environment:
RABBITMQ_DEFAULT_USER: auditix
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD}
volumes:
- rabbitmq:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
interval: 10s
timeout: 10s
retries: 12
restart: unless-stopped
# Real-time updates. Not published: the browsers reach it through the gateway.
mercure:
logging: *logging
image: dunglas/mercure:v1.1
environment:
SERVER_NAME: ":80"
MERCURE_TRUSTED_ISSUERS: auditix
MERCURE_PUBLISHER_JWT_KEY: ${MERCURE_JWT_SECRET}
MERCURE_PUBLISHER_JWT_ALG: HS256
MERCURE_SUBSCRIBER_JWT_KEY: ${MERCURE_JWT_SECRET}
MERCURE_SUBSCRIBER_JWT_ALG: HS256
MERCURE_EXTRA_DIRECTIVES: |
resource_identifier http://mercure/.well-known/mercure
cookie_name auditix_live
transport bolt {
path /data/mercure.db
size 1000
cleanup_frequency 0.3
}
heartbeat 15s
volumes:
- mercure:/data
restart: unless-stopped
database:
logging: *logging
image: postgres:18-alpine
environment:
POSTGRES_DB: auditix
POSTGRES_USER: auditix
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
volumes:
- database:/var/lib/postgresql
healthcheck:
test: ["CMD", "pg_isready", "-U", "auditix", "-d", "auditix"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
volumes:
database:
gateway:
logs-config:
mercure:
rabbitmq:
  1. Legen Sie unter Einstellungen › Plattform › Allgemein den Namen der Instanz, die Zeitzone, die Standardsprache und unter Darstellung das Standarddesign und die Hauptfarbe fest (siehe Einstellungen).
  2. Aktivieren Sie die Lizenz.
  3. Richten Sie HTTPS ein.
  4. Erstellen Sie die Tenants und die Konten.

Konten lassen sich auch über die Befehlszeile anlegen (mit Portainer über die Konsole des Backend-Containers):

Terminal-Fenster
docker compose exec backend bin/console auditix:user:create jane@example.com \
--first-name=Jane --last-name=Doe --platform-admin --tenant="My company"
  1. Stacks › Add stack › Web editor: Fügen Sie compose.yaml ein.
  2. Übernehmen Sie die Variablen aus .env in die Umgebungsvariablen des Stacks, mit AUDITIX_VERSION=latest.
  3. Entfernen Sie im Dienst updater das Volume .:/install: Portainer speichert die Dateien eines Stacks in einem eigenen Volume. Die vor Updates erstellten Sicherungen landen dann in einem Docker-Volume namens <stack>_backups, das der Updater anlegt.

Mehr ist nicht nötig: Updates ändern den Stack nie, und die Worker werden vom Dienst orchestrator außerhalb des Stacks gestartet.

Geben Sie unter Einstellungen › Plattform › Webzugriff den Hostnamen der Instanz an (sein DNS muss auf den Server zeigen) und wählen Sie dann das Zertifikat:

  • Let’s Encrypt: kostenlos, automatisch ausgestellt und erneuert. Die Ports 80 und 443 müssen aus dem Internet erreichbar sein. Let’s Encrypt (Test) prüft zuerst die Einrichtung, mit Zertifikaten, denen Browser nicht vertrauen, ohne an die Limits von Let’s Encrypt zu stoßen.
  • Eigenes Zertifikat: Fügen Sie das Zertifikat (PEM) (mit seinen Zwischenzertifikaten) und den Privaten Schlüssel (PEM) ein. Der Schlüssel wird verschlüsselt gespeichert und nie wieder angezeigt.
  • Kein HTTPS (nur HTTP): für einen Test oder hinter einem Reverse-Proxy, der HTTPS übernimmt.

Schalten Sie dann HTTP auf HTTPS umleiten ein und, sobald HTTPS funktioniert, Striktes HTTPS (HSTS). Änderungen greifen innerhalb weniger Sekunden, ohne Neustart. Wenn eine falsche Einstellung Auditix über HTTPS unerreichbar macht, schalten Sie HTTPS auf dem Server aus:

Terminal-Fenster
docker compose exec backend bin/console auditix:web:reset

Hinter einem Reverse-Proxy, der HTTPS bereits übernimmt, lassen Sie HTTPS ausgeschaltet und leiten mit den Headern X-Forwarded-Proto und X-Forwarded-For an den HTTP-Port des Gateways weiter.

Der Dienst orchestrator startet die Worker-Container, die die Hintergrundarbeit erledigen (geplante Aufgaben, Prüfungen, Importe…), wie unter Einstellungen › Plattform › Workers › Pools festgelegt: eine feste Anzahl von Containern oder eine automatische Skalierung nach der Anzahl wartender Nachrichten. Der Standard-Pool betreibt 2 bis 4 Container. Ohne den Orchestrator führt das Backend die geplanten Aufgaben weiterhin alle fünf Minuten aus, aber sonst wird nichts im Hintergrund verarbeitet.

Die Worker-Container gehören nicht zum Compose-Projekt, daher entfernt docker compose down sie nicht. Um die Installation vollständig herunterzufahren (auditix ist der Projektname):

Terminal-Fenster
docker compose stop orchestrator
docker rm -f $(docker ps -aq --filter label=io.auditix.orchestrator.project=auditix)
docker compose down

Alle Daten liegen in PostgreSQL. Sichern Sie sie regelmäßig und immer vor einem Update von Hand:

Terminal-Fenster
docker compose exec -T database pg_dump -U auditix -Fc auditix > auditix-$(date +%F).dump

Wiederherstellen in eine leere Datenbank:

Terminal-Fenster
docker compose exec -T database pg_restore -U auditix -d auditix --clean --if-exists < auditix-YYYY-MM-DD.dump

Wenn sich kein Administrator mehr anmelden kann, setzen Sie auf dem Server ein neues Passwort:

Terminal-Fenster
docker compose exec backend bin/console auditix:user:password admin@example.com