5 Commits
Author SHA1 Message Date
git-hermes 4b21030d28 fix(n8n-sandbox): remove unused port selector (#6)
Test / test (push) Canceled after 0s
Remove the misleading unused host-port setting while preserving internal Docker access on sandbox-api:8080.
2026-09-03 08:40:01 +00:00
git-hermes e2b6a35b26 fix(n8n-sandbox): remove unused port selector
Test / test (pull_request) Canceled after 0s
2026-09-03 10:37:49 +02:00
git-hermes 405524b036 fix(n8n-sandbox): keep Runtipi app status healthy (#5)
Test / test (push) Canceled after 0s
Keep the certificate bootstrap healthy and idle so Runtipi sees all managed containers running.
2026-09-03 08:34:21 +00:00
git-hermes 7a58959869 fix(n8n-sandbox): reset certificate readiness marker
Test / test (pull_request) Canceled after 0s
2026-09-03 10:31:24 +02:00
git-hermes 0a5476793e fix(n8n-sandbox): keep Runtipi app status healthy
Test / test (pull_request) Canceled after 0s
2026-09-03 10:28:42 +02:00
4 changed files with 35 additions and 16 deletions
+16 -4
View File
@@ -74,7 +74,8 @@ describe("n8n-sandbox installation secrets", () => {
expect(apiKey?.type).toBe('password')
expect(apiKey?.required).toBe(true)
expect(apiKey?.min).toBeGreaterThanOrEqual(48)
expect(config.tipi_version).toBeGreaterThanOrEqual(2)
expect(config.port).toBeUndefined()
expect(config.tipi_version).toBeGreaterThanOrEqual(5)
})
})
@@ -84,6 +85,7 @@ describe("n8n-sandbox post-install documentation", () => {
expect(description).toContain('services:\n n8n-2:\n environment:')
expect(description).toContain('N8N_SANDBOX_SERVICE_URL=http://sandbox-api:8080')
expect(description).toContain("Runtipi ne demande aucun port pour cette app")
expect(description).not.toContain('sandbox-api:<PORT')
expect(description).toContain('N8N_SANDBOX_SERVICE_API_KEY=<clé choisie lors de linstallation>')
expect(description).toContain('/opt/runtipi/app-data/migrated/searxng/data/settings.yml')
@@ -92,14 +94,24 @@ describe("n8n-sandbox post-install documentation", () => {
})
describe("modern compose files preserve runtime semantics", () => {
test("n8n-sandbox keeps its one-shot certificate service", async () => {
test("n8n-sandbox keeps its certificate bootstrap healthy for Runtipi", async () => {
const fileContent = await getFile('n8n-sandbox', 'docker-compose.yml')
expect(fileContent).not.toBeNull()
const parsed = YAML.parse(fileContent || '')
const certs = parsed.services?.['sandbox-certs']
const api = parsed.services?.['sandbox-api']
expect(parsed['x-runtipi']?.schema_version).toBe(2)
expect(parsed.services?.['sandbox-certs']?.restart).toBe('no')
expect(parsed.services?.['sandbox-api']?.['x-runtipi']?.is_main).toBe(true)
const certCommand = certs?.command?.join(' ') || ''
expect(certs?.restart).toBe('unless-stopped')
expect(certCommand).toContain('rm -f /tmp/certs-ready')
expect(certCommand).toContain('touch /tmp/certs-ready')
expect(certCommand).toContain('tail -f /dev/null')
expect(certCommand.indexOf('rm -f /tmp/certs-ready')).toBeLessThan(certCommand.indexOf('bootstrap-mtls.sh'))
expect(certs?.healthcheck?.test).toContain('test -f /tmp/certs-ready')
expect(api?.depends_on?.['sandbox-certs']?.condition).toBe('service_healthy')
expect(api?.['x-runtipi']?.is_main).toBe(true)
expect(parsed.services?.['sandbox-runner-1']?.environment?.SANDBOX_RUNNER_HTTP_BASE_URL).toBe('https://sandbox-runner-1:8080')
expect(parsed.services?.['sandbox-runner-1']?.healthcheck?.test).toContain('https://localhost:8080/readyz')
})
+1 -2
View File
@@ -5,8 +5,7 @@
"exposable": false,
"no_gui": true,
"dynamic_config": true,
"port": 8080,
"tipi_version": 3,
"tipi_version": 5,
"min_tipi_version": "4.7.0",
"version": "1.3.0",
"author": "n8n",
+16 -8
View File
@@ -32,24 +32,32 @@
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"
# Runtipi considere l'app arretee si un seul de ses conteneurs est sorti.
# Le bootstrap reste donc actif et sain apres la generation idempotente.
restart: unless-stopped
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).
# Genere les certs, fixe les droits pour sandbox-api, publie l'etat ready,
# puis reste actif sans ouvrir de port ni lancer de service reseau.
command:
- >
rm -f /tmp/certs-ready &&
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
chown -R sandbox-api:sandbox-api /tls/api /var/lib/n8n-sandbox-api &&
touch /tmp/certs-ready &&
exec tail -f /dev/null
environment:
NUM_RUNNERS: "1"
volumes:
- ${APP_DATA_DIR}/data/tls:/tls
- ${APP_DATA_DIR}/data/api:/var/lib/n8n-sandbox-api
healthcheck:
test: "test -f /tmp/certs-ready"
interval: 5s
timeout: 2s
retries: 12
start_period: 5s
sandbox-api:
image: n8nio/n8n-sandbox-service-api:1.3.0
@@ -57,7 +65,7 @@ services:
depends_on:
sandbox-certs:
condition: service_completed_successfully
condition: service_healthy
environment:
SANDBOX_API_KEYS: "${SANDBOX_API_KEYS}"
+2 -2
View File
@@ -4,7 +4,7 @@ Sandbox auto-hébergé pour l'**AI Assistant** de n8n (configuration « Self-hos
| Service | Rôle |
|---|---|
| `sandbox-certs` | Job one-shot : génère la CA privée et les certificats mTLS, puis s'arrête. |
| `sandbox-certs` | Initialise la CA privée et les certificats mTLS, puis reste inactif et sain pour que Runtipi conserve l'app au statut « Démarré ». |
| `sandbox-api` | Point d'entrée HTTP interne (`:8080`) que n8n appelle pour exécuter du code. |
| `sandbox-runner-1` | Docker-in-Docker **privileged** : crée et exécute les conteneurs sandbox. |
@@ -35,7 +35,7 @@ services:
Remplacer entièrement `<clé choisie lors de linstallation>` par la vraie clé, sans conserver les caractères `<` et `>`. Ne jamais publier cette valeur.
Le port de `N8N_SANDBOX_SERVICE_URL` reste `8080` : il s'agit du port interne du service Docker, pas du port éventuellement choisi dans l'interface Runtipi.
Le port de `N8N_SANDBOX_SERVICE_URL` reste `8080` : il s'agit du port interne du service Docker. Runtipi ne demande aucun port pour cette app, car elle n'en publie aucun sur l'hôte.
Enregistrer la configuration, puis redémarrer l'application **n8n**. Pour vérifier la communication depuis son conteneur :