Aller au contenu

Stack de production

  • Un hôte Linux avec Docker Engine et le plugin Docker Compose.
  • Les ports 80 et 443 joignables par vos utilisateurs (ou tout autre port, défini dans .env).
  • Pour les certificats Let’s Encrypt : un nom DNS qui pointe vers l’hôte, et les ports 80 et 443 joignables depuis Internet.

Auditix est publié sous forme de trois images (frontend, backend, updater) sur le registre Auditix, rg.fr-par.scw.cloud/auditix, toujours déployées avec le même tag. Le fichier compose ajoute les services dont elles dépendent :

Service Rôle
gateway Le seul service publié : sert Auditix en HTTP et en HTTPS.
frontend L’interface web.
backend L’application. Applique elle-même les modifications de la base de données à son démarrage.
updater Applique les mises à jour lancées depuis Paramètres › Plateforme › Mise à jour. Facultatif.
orchestrator Démarre et arrête les conteneurs workers qui exécutent les traitements en arrière-plan.
developer La référence de l’API externe, sur /developer.
logs Transmet les journaux aux serveurs syslog de Paramètres › Plateforme › Journaux.
rabbitmq Files d’attente des traitements en arrière-plan.
mercure Mises à jour en temps réel de l’interface.
database PostgreSQL : toutes les données y sont stockées.

Les services updater et orchestrator ont accès à Docker. Ils n’agissent jamais que sur les conteneurs de leur propre installation (le projet compose déployé depuis le même dossier), jamais sur les autres conteneurs de l’hôte.

  1. Connectez-vous au registre (ignorez cette étape si le registre est public), avec une clé secrète d’API Scaleway autorisée à lire le registre :

    Fenêtre de terminal
    docker login rg.fr-par.scw.cloud/auditix -u nologin
    # Password: your Scaleway API secret key
  2. Créez le dossier d’installation :

    Fenêtre de terminal
    mkdir -p /opt/auditix && cd /opt/auditix
  3. Créez compose.yaml avec le contenu ci-dessous.

  4. Créez .env, lisible par root uniquement (chmod 600 .env), et renseignez chaque secret une seule fois avec openssl rand -hex 32 :

    Fenêtre de terminal
    # "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. Démarrez :

    Fenêtre de terminal
    docker compose pull
    docker compose up -d
    docker compose ps # every service should be "healthy"
  6. Connectez-vous sur http://<host> avec l’administrateur par défaut, admin / password. Auditix demande un nouveau mot de passe avant toute chose : faites-le immédiatement, avant d’exposer le service.

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. Dans Paramètres › Plateforme › Général, définissez le Nom de l’instance, le Fuseau horaire, la Langue par défaut et, dans Apparence, le Thème par défaut et la Couleur principale (voir Paramètres).
  2. Activez la licence.
  3. Configurez HTTPS.
  4. Créez les tenants et les comptes.

Les comptes peuvent aussi être créés en ligne de commande (avec Portainer, depuis la console du conteneur backend) :

Fenêtre de terminal
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 : collez compose.yaml.
  2. Placez les variables de .env dans les variables d’environnement de la stack, avec AUDITIX_VERSION=latest.
  3. Dans le service updater, supprimez le volume .:/install : Portainer conserve les fichiers d’une stack dans son propre volume. Les sauvegardes effectuées avant les mises à jour sont alors stockées dans un volume Docker nommé <stack>_backups, créé par l’updater.

Rien d’autre n’est nécessaire : les mises à jour ne modifient jamais la stack, et les workers sont démarrés par le service orchestrator, en dehors de la stack.

Dans Paramètres › Plateforme › Accès web, indiquez le Nom d’hôte de l’instance (son DNS doit pointer vers le serveur), puis choisissez le Certificat :

  • Let’s Encrypt : gratuit, émis et renouvelé automatiquement. Les ports 80 et 443 doivent être joignables depuis Internet. Let’s Encrypt (test) vérifie d’abord la configuration, avec des certificats auxquels les navigateurs ne font pas confiance, sans atteindre les limites de Let’s Encrypt.
  • Mon propre certificat : collez le Certificat (PEM) (avec ses certificats intermédiaires) et la Clé privée (PEM). La clé est stockée chiffrée et n’est plus jamais affichée.
  • Pas de HTTPS (HTTP seul) : pour un essai, ou derrière un reverse proxy qui gère le HTTPS.

Activez ensuite Rediriger HTTP vers HTTPS et, une fois le HTTPS fonctionnel, HTTPS strict (HSTS). Les modifications s’appliquent en quelques secondes, sans redémarrage. Si un mauvais réglage rend Auditix injoignable en HTTPS, désactivez le HTTPS depuis le serveur :

Fenêtre de terminal
docker compose exec backend bin/console auditix:web:reset

Derrière un reverse proxy qui gère déjà le HTTPS, laissez le HTTPS désactivé et transmettez au port HTTP de la gateway avec les en-têtes X-Forwarded-Proto et X-Forwarded-For.

Le service orchestrator démarre les conteneurs workers qui effectuent les traitements en arrière-plan (tâches planifiées, vérifications, imports…), selon les réglages de Paramètres › Plateforme › Workers › Pools : un nombre fixe de conteneurs, ou une mise à l’échelle Automatique selon le nombre de messages en attente. Le pool par défaut exécute 2 à 4 conteneurs. Sans l’orchestrateur, le backend exécute tout de même les tâches planifiées toutes les cinq minutes, mais rien d’autre n’est traité en arrière-plan.

Les conteneurs workers ne font pas partie du projet compose : docker compose down ne les supprime donc pas. Pour arrêter complètement l’installation (auditix étant le nom du projet) :

Fenêtre de terminal
docker compose stop orchestrator
docker rm -f $(docker ps -aq --filter label=io.auditix.orchestrator.project=auditix)
docker compose down

Toutes les données sont stockées dans PostgreSQL. Sauvegardez-les régulièrement, et toujours avant une mise à jour manuelle :

Fenêtre de terminal
docker compose exec -T database pg_dump -U auditix -Fc auditix > auditix-$(date +%F).dump

Restaurez dans une base de données vide :

Fenêtre de terminal
docker compose exec -T database pg_restore -U auditix -d auditix --clean --if-exists < auditix-YYYY-MM-DD.dump

Lorsqu’aucun administrateur ne peut se connecter, définissez un nouveau mot de passe depuis le serveur :

Fenêtre de terminal
docker compose exec backend bin/console auditix:user:password admin@example.com