This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "n8n Sandbox Service",
|
||||
"id": "n8n-sandbox",
|
||||
"available": true,
|
||||
"exposable": false,
|
||||
"no_gui": true,
|
||||
"dynamic_config": true,
|
||||
"port": 8080,
|
||||
"tipi_version": 1,
|
||||
"min_tipi_version": "4.7.0",
|
||||
"version": "1.3.0",
|
||||
"author": "n8n",
|
||||
"source": "https://github.com/n8n-io/n8n-sandbox-service",
|
||||
"website": "https://docs.n8n.io/deploy/host-n8n/configure-n8n/set-up-ai-assistant",
|
||||
"categories": ["automation", "development"],
|
||||
"short_desc": "Sandbox d'execution de code pour l'AI Assistant de n8n (api + runner Docker-in-Docker).",
|
||||
"description": "Stack n8n Sandbox Service (sandbox-certs, sandbox-api, sandbox-runner-1) en mTLS. Aucun port publie : n8n joint sandbox-api:8080 via tipi_main_network. Le runner tourne en privileged (Docker-in-Docker).",
|
||||
"supported_architectures": ["amd64", "arm64"],
|
||||
"form_fields": [
|
||||
{
|
||||
"type": "random",
|
||||
"encoding": "hex",
|
||||
"min": 48,
|
||||
"label": "Cle API sandbox (SANDBOX_API_KEYS)",
|
||||
"hint": "A recopier dans l'app n8n : N8N_SANDBOX_SERVICE_API_KEY. Plusieurs cles possibles, separees par des virgules.",
|
||||
"required": true,
|
||||
"env_variable": "SANDBOX_API_KEYS"
|
||||
},
|
||||
{
|
||||
"type": "random",
|
||||
"encoding": "hex",
|
||||
"min": 48,
|
||||
"label": "Jeton d'enregistrement du runner (SANDBOX_REGISTRATION_TOKEN)",
|
||||
"hint": "Secret interne api <-> runner. Rien a recopier ailleurs.",
|
||||
"required": true,
|
||||
"env_variable": "SANDBOX_REGISTRATION_TOKEN"
|
||||
},
|
||||
{
|
||||
"type": "random",
|
||||
"encoding": "hex",
|
||||
"min": 48,
|
||||
"label": "Cle API interne du runner (SANDBOX_RUNNER_KEY)",
|
||||
"hint": "Secret interne api <-> runner. Rien a recopier ailleurs.",
|
||||
"required": true,
|
||||
"env_variable": "SANDBOX_RUNNER_KEY"
|
||||
}
|
||||
],
|
||||
"created_at": 1788345796000,
|
||||
"updated_at": 1788345796000
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"services": [
|
||||
{
|
||||
"name": "sandbox-certs",
|
||||
"image": "n8nio/n8n-sandbox-service-api:1.3.0",
|
||||
"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\n"
|
||||
],
|
||||
"entrypoint": [
|
||||
"sh",
|
||||
"-c"
|
||||
],
|
||||
"environment": {
|
||||
"NUM_RUNNERS": "1"
|
||||
},
|
||||
"user": "0:0",
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/tls",
|
||||
"containerPath": "/tls"
|
||||
},
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/api",
|
||||
"containerPath": "/var/lib/n8n-sandbox-api"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sandbox-api",
|
||||
"image": "n8nio/n8n-sandbox-service-api:1.3.0",
|
||||
"isMain": true,
|
||||
"internalPort": 8080,
|
||||
"addToMainNetwork": true,
|
||||
"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": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/tls",
|
||||
"containerPath": "/tls",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/api",
|
||||
"containerPath": "/var/lib/n8n-sandbox-api"
|
||||
}
|
||||
],
|
||||
"healthCheck": {
|
||||
"test": "wget -qO- http://localhost:8080/healthz",
|
||||
"interval": "5s",
|
||||
"timeout": "3s",
|
||||
"retries": 5,
|
||||
"startPeriod": "10s"
|
||||
},
|
||||
"dependsOn": {
|
||||
"sandbox-certs": {
|
||||
"condition": "service_completed_successfully"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sandbox-runner-1",
|
||||
"image": "n8nio/n8n-sandbox-service-runner-dind:1.3.0",
|
||||
"environment": {
|
||||
"SANDBOX_RUNNER_API_KEYS": "${SANDBOX_RUNNER_KEY}",
|
||||
"SANDBOX_RUNNER_REGISTRATION_TOKEN": "${SANDBOX_REGISTRATION_TOKEN}",
|
||||
"SANDBOX_RUNNER_API_GRPC_ADDR": "sandbox-api:9090",
|
||||
"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"
|
||||
},
|
||||
"privileged": true,
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/tls",
|
||||
"containerPath": "/tls",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/runner-state",
|
||||
"containerPath": "/var/sandboxes"
|
||||
},
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/runner-docker",
|
||||
"containerPath": "/var/lib/docker"
|
||||
}
|
||||
],
|
||||
"healthCheck": {
|
||||
"test": "wget -qO- http://localhost:8080/readyz",
|
||||
"interval": "5s",
|
||||
"timeout": "5s",
|
||||
"retries": 24,
|
||||
"startPeriod": "20s"
|
||||
},
|
||||
"dependsOn": {
|
||||
"sandbox-api": {
|
||||
"condition": "service_healthy"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# n8n Sandbox Service
|
||||
|
||||
Sandbox auto-hébergé pour l'**AI Assistant** de n8n (setup « Self-host the sandbox manually » de la doc n8n). L'app déploie les trois services de la stack officielle :
|
||||
|
||||
| Service | Rôle |
|
||||
|---|---|
|
||||
| `sandbox-certs` | Job one-shot : génère la CA privée et les certificats mTLS, puis s'arrête. |
|
||||
| `sandbox-api` | Point d'entrée HTTP (`:8080`) que n8n appelle pour exécuter du code. |
|
||||
| `sandbox-runner-1` | Docker-in-Docker **privileged** : crée et exécute les conteneurs sandbox. |
|
||||
|
||||
## Après l'installation
|
||||
|
||||
Dans l'app **n8n** (paramètres ou `app.env`), ajouter :
|
||||
|
||||
```
|
||||
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=<valeur du champ « Clé API sandbox »>
|
||||
```
|
||||
|
||||
Puis redémarrer n8n et vérifier depuis son conteneur :
|
||||
|
||||
```
|
||||
wget -qO- http://sandbox-api:8080/healthz # {"status":"ok"}
|
||||
```
|
||||
|
||||
## Données persistantes
|
||||
|
||||
Tout est sous `app-data/<store>/n8n-sandbox/data/` :
|
||||
|
||||
- `tls/` : certificats mTLS (contient la clé de la CA, à traiter comme un secret)
|
||||
- `api/` : base SQLite de l'API
|
||||
- `runner-state/` : base SQLite du runner
|
||||
- `runner-docker/` : `/var/lib/docker` du DinD (cache de l'image sandbox, peut peser plusieurs Go ; vidable sans perte)
|
||||
|
||||
## Sécurité
|
||||
|
||||
- Aucun port n'est publié sur l'hôte. `sandbox-api:8080` est joignable par les autres apps Runtipi via `tipi_main_network`, protégé uniquement par la clé API.
|
||||
- Le runner est `privileged` : équivalent root sur l'hôte. Ne jamais l'exposer.
|
||||
- n8n recommande cette stack pour le développement/test et Daytona pour la production.
|
||||
|
||||
## Notes
|
||||
|
||||
- Les noms `sandbox-api` et `sandbox-runner-1` sont les SAN des certificats : ne pas les renommer.
|
||||
- Les certificats ne se renouvellent pas seuls. Pour les régénérer, supprimer `data/tls/` et redémarrer l'app.
|
||||
- L'image sandbox est téléchargée par le runner au premier usage.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Reference in New Issue
Block a user