Files
runtipi-appstore/apps/n8n-sandbox/docker-compose.yml
T
2026-09-02 17:27:56 +02:00

160 lines
6.7 KiB
YAML

# n8n Sandbox Service — app custom Runtipi (format docker-compose.yml + x-runtipi)
#
# Images : n8nio/n8n-sandbox-service-{api,runner-dind,sandbox}:1.3.0
# (verifier au besoin : docker manifest inspect n8nio/n8n-sandbox-service-sandbox:1.3.0)
#
# Les 3 secrets ne sont PAS dans ce fichier : ce sont des form_fields du
# config.json (SANDBOX_API_KEYS, SANDBOX_REGISTRATION_TOKEN, SANDBOX_RUNNER_KEY),
# saisis/generes dans la GUI Runtipi a l'installation, modifiables ensuite
# dans les parametres de l'app, et injectes ici par ${...}.
#
# Cote app n8n (autre app Runtipi, doc "Set up AI Assistant", setup 2) :
# N8N_ENABLED_MODULES=instance-ai
# N8N_INSTANCE_AI_SANDBOX_ENABLED=true
# N8N_INSTANCE_AI_SANDBOX_PROVIDER=n8n-sandbox
# N8N_INSTANCE_AI_SANDBOX_IMAGE=n8nio/n8n-sandbox-service-sandbox:1.3.0
# N8N_SANDBOX_SERVICE_URL=http://sandbox-api:8080
# N8N_SANDBOX_SERVICE_API_KEY=<une des valeurs de SANDBOX_API_KEYS>
# Test depuis le conteneur n8n : wget -qO- http://sandbox-api:8080/healthz
#
# Les noms de services sandbox-api et sandbox-runner-1 sont fixes : ce sont
# les SAN des certificats. Si un nom ou NUM_RUNNERS change, supprimer
# ${APP_DATA_DIR}/data/tls (bootstrap-mtls.sh ne regenere rien tant que
# les fichiers existent).
#
# Donnees persistantes (toutes sous ${APP_DATA_DIR}/data, donc couvertes par
# les sauvegardes Runtipi — attention, runner-docker peut peser plusieurs Go) :
# tls/ certificats mTLS (CA + feuilles)
# api/ SQLite de l'API (etat des sandboxes)
# runner-state/ SQLite du runner
# runner-docker/ /var/lib/docker du DinD (cache de l'image sandbox)
services:
sandbox-certs:
image: n8nio/n8n-sandbox-service-api:1.3.0
# Obligatoire sous Runtipi : sans cette ligne le builder injecte
# restart: unless-stopped et ce job one-shot boucle en redemarrage.
restart: "no"
user: "0:0"
entrypoint: ["sh", "-c"]
# Genere les certs (idempotent) puis fixe les droits pour l'utilisateur
# sandbox-api de l'image : /tls/api et le repertoire SQLite de l'API
# (en bind mount, Docker cree le dossier en root sinon).
command:
- >
bootstrap-mtls.sh --out-dir /tls --api-san sandbox-api
--control-san-prefix sandbox-runner &&
chown -R sandbox-api:sandbox-api /tls/api /var/lib/n8n-sandbox-api
environment:
NUM_RUNNERS: "1"
volumes:
- ${APP_DATA_DIR}/data/tls:/tls
- ${APP_DATA_DIR}/data/api:/var/lib/n8n-sandbox-api
sandbox-api:
image: n8nio/n8n-sandbox-service-api:1.3.0
restart: unless-stopped
depends_on:
sandbox-certs:
condition: service_completed_successfully
environment:
SANDBOX_API_KEYS: "${SANDBOX_API_KEYS}"
SANDBOX_API_RUNNER_REGISTRATION_TOKEN: "${SANDBOX_REGISTRATION_TOKEN}"
SANDBOX_API_RUNNER_API_KEY: "${SANDBOX_RUNNER_KEY}"
SANDBOX_API_GRPC_TLS_CERT_FILE: /tls/api/grpc-server.crt
SANDBOX_API_GRPC_TLS_KEY_FILE: /tls/api/grpc-server.key
SANDBOX_API_GRPC_TLS_CLIENT_CA_FILE: /tls/api/ca.crt
SANDBOX_API_RUNNER_CONTROL_GRPC_TLS_CA_FILE: /tls/api/ca.crt
SANDBOX_API_RUNNER_CONTROL_GRPC_TLS_CERT_FILE: /tls/api/control-grpc-api-client.crt
SANDBOX_API_RUNNER_CONTROL_GRPC_TLS_KEY_FILE: /tls/api/control-grpc-api-client.key
SANDBOX_API_RUNNER_CONTROL_GRPC_TLS_SERVER_NAME: sandbox-runner-1
volumes:
- ${APP_DATA_DIR}/data/tls:/tls:ro
# SANDBOX_API_DATA_DIR par defaut (SQLite).
- ${APP_DATA_DIR}/data/api:/var/lib/n8n-sandbox-api
healthcheck:
# Forme chaine (et non tableau) : c'est la forme documentee par Runtipi
# et la seule acceptee par le formulaire de creation.
test: "wget -qO- http://localhost:8080/healthz"
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
# is_main est OBLIGATOIRE : l'UI Runtipi refuse un compose sans
# exactement un service principal ("There must be exactly one main service").
# Sans internal_port et sans cocher "open port" a l'installation,
# is_main ne publie aucun port et ne pose aucun label Traefik.
# Le service principal rejoint automatiquement tipi_main_network, ce qui
# rend sandbox-api:8080 joignable par les autres apps Runtipi (dont n8n),
# protege uniquement par SANDBOX_API_KEYS. Ne jamais publier 8080/9090.
x-runtipi:
is_main: true
add_to_main_network: true
sandbox-runner-1:
image: n8nio/n8n-sandbox-service-runner-dind:1.3.0
restart: unless-stopped
# Mode "dev/macOS" de l'upstream (qui attend sysbox-runc en production ;
# n8n recommande Daytona pour la prod). Equivalent root sur l'hote :
# ce service reste hors de tipi_main_network et ne publie aucun port.
privileged: true
depends_on:
sandbox-api:
condition: service_healthy
environment:
SANDBOX_RUNNER_API_KEYS: "${SANDBOX_RUNNER_KEY}"
SANDBOX_RUNNER_REGISTRATION_TOKEN: "${SANDBOX_REGISTRATION_TOKEN}"
SANDBOX_RUNNER_API_GRPC_ADDR: sandbox-api:9090
# http:// et non https:// : le mTLS ne couvre que le gRPC
# (enregistrement + SandboxControl). Le trafic proxy exec/files de
# l'API vers le runner reste en HTTP clair authentifie par X-Api-Key
# (docs/configuration.md du depot et compose officiel n8n).
SANDBOX_RUNNER_HTTP_BASE_URL: http://sandbox-runner-1:8080
SANDBOX_RUNNER_CONTROL_GRPC_LISTEN_ADDR: ":9091"
SANDBOX_RUNNER_CONTROL_GRPC_ADVERTISE_ADDR: sandbox-runner-1:9091
SANDBOX_RUNNER_ID: runner-1
SANDBOX_RUNNER_DOCKER_SANDBOX_IMAGE: n8nio/n8n-sandbox-service-sandbox:1.3.0
SANDBOX_RUNNER_REGISTRATION_GRPC_CA_FILE: /tls/runner/ca.crt
SANDBOX_RUNNER_REGISTRATION_GRPC_CERT_FILE: /tls/runner/grpc-client.crt
SANDBOX_RUNNER_REGISTRATION_GRPC_KEY_FILE: /tls/runner/grpc-client.key
SANDBOX_RUNNER_REGISTRATION_GRPC_SERVER_NAME: sandbox-api
SANDBOX_RUNNER_CONTROL_GRPC_TLS_CERT_FILE: /tls/runner/control-grpc-server.crt
SANDBOX_RUNNER_CONTROL_GRPC_TLS_KEY_FILE: /tls/runner/control-grpc-server.key
SANDBOX_RUNNER_CONTROL_GRPC_TLS_CLIENT_CA_FILE: /tls/runner/ca.crt
volumes:
- ${APP_DATA_DIR}/data/tls:/tls:ro
# Etat SQLite du runner (SANDBOX_RUNNER_DATA_DIR par defaut).
- ${APP_DATA_DIR}/data/runner-state:/var/sandboxes
# Docker interne du DinD : sans ce montage, l'image sandbox est
# re-telechargee a chaque recreation de l'app. Necessite un app-data
# sur ext4/xfs/btrfs (overlay2 ne fonctionne pas sur NFS).
- ${APP_DATA_DIR}/data/runner-docker:/var/lib/docker
healthcheck:
# /readyz passe au vert une fois le runner enregistre aupres de l'API
# (meme check que le compose du depot upstream).
test: "wget -qO- http://localhost:8080/readyz"
interval: 5s
timeout: 5s
retries: 24
start_period: 20s
x-runtipi:
schema_version: 2