# 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= # 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 # Le listener HTTP du runner sert obligatoirement TLS avec le certificat # SandboxControl. Son SAN sandbox-runner-1 est genere par sandbox-certs. # HTTP est refuse depuis la version 1.3.0 pour ne pas exposer X-Api-Key. SANDBOX_RUNNER_HTTP_BASE_URL: https://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 # Le probe local ignore uniquement la verification du certificat ; le # trafic API -> runner reste verifie avec la CA et le SAN partages. test: "wget -qO- --no-check-certificate https://localhost:8080/readyz" interval: 5s timeout: 5s retries: 24 start_period: 20s x-runtipi: schema_version: 2