For the complete documentation index, see llms.txt. This page is also available as Markdown.

Install using Docker Compose

Who this is for

This guide walks through building your own Docker Compose setup by hand, including the sandbox stack that powers n8n Assistant. Use it if you want full control over your configuration, or need to fold n8n into an existing Compose project.

If you just want n8n (and n8n Assistant) running quickly without writing any files yourself, use the one-line setup instead. It sets up everything below automatically.

What you need before you start

  • Docker Engine and Docker Compose v2. Run docker compose version to check.

  • At least 4 GB of RAM and 2 vCPUs. The sandbox that runs AI-generated code (sandbox-runner-1) uses Docker-in-Docker, which needs more headroom than a typical container.

Windows users: Use WSL, with either Docker Desktop (WSL2 backend) or Docker Engine installed directly in your Linux distribution. Keep your project folder inside the WSL filesystem (for example, ~/n8n), not under /mnt/c/.... Bind mounts across that boundary are slow and can cause permission issues.

Step 1: Create a project folder

mkdir n8n && cd n8n

Step 2: Create .env

This file holds the secrets the sandbox services use to talk to each other. Create a file named .env with your own values in place of the placeholders and keep this file out of version control.

# Sandbox service secrets — pick your own values
SANDBOX_API_KEYS=change-me-api-key
SANDBOX_API_RUNNER_REGISTRATION_TOKEN=change-me-registration-token
SANDBOX_API_RUNNER_API_KEY=change-me-runner-key

# Must match a value in SANDBOX_API_KEYS above — this is how n8n authenticates to the sandbox
N8N_SANDBOX_SERVICE_API_KEY=change-me-api-key

# Web search: secret for the bundled SearXNG instance — pick your own value
SEARXNG_SECRET=change-me-searxng-secret
N8N_INSTANCE_AI_SEARXNG_URL=http://searxng:8080

You don't need an AI provider key yet; see Turn on n8n Assistant below once everything's running.

Step 3: Create searxng-settings.yml

The stock SearXNG image only serves HTML; n8n's web search needs its JSON API, which this file turns on.

Step 4: Create compose.yml

This defines every service you're setting up: n8n itself, the sandbox stack that lets n8n Assistant safely run code, and SearXNG for web search.

Not found

What you've just set up

Component
What it's for

n8n

The workflow editor itself, available at http://localhost:5678.

sandbox-certs

Runs once to generate the TLS certificates the other sandbox services need, then exits.

sandbox-api

The control plane n8n talks to when n8n Assistant needs to run code.

sandbox-runner-1

Does the actual work; a privileged Docker-in-Docker container that creates and runs the sandboxes.

searxng

Bundled web search backend for n8n Assistant.

This bundles n8n's own sandbox (n8n-sandbox), which is a good fit for local development and testing. For a production instance, n8n currently recommends Daytona as the sandbox provider instead. See Set up n8n Assistant for how to configure a Daytona sandbox.

There's no database service defined here. n8n falls back to its built-in SQLite database, stored inside the container unless you mount a volume for it. For a production instance, swap in Postgres. See Use PostgreSQL instead of SQLite below.

Step 5: Start everything

Wait until sandbox-api shows healthy; sandbox-runner-1 and n8n will then start automatically.

Step 6: Verify it's working

Launch n8n by pointing your web browser to http://localhost:5678

Optional: Turn on n8n Assistant

Everything above runs the full sandbox stack, but n8n Assistant itself stays off until you give it a model to use. You can do this from the n8n UI (in the instance's AI settings) once n8n is running, or using .env if you'd rather configure it before first login:

  1. Add your AI provider key to .env:

  2. Restart n8n so it picks up the change:

Web search runs through the bundled SearXNG service by default. If you'd rather use Brave Search instead, you can set it from the UI or add your Brave API key to .env; it takes priority over SearXNG once set:

Full setup steps, including the supported model providers, are in Set up n8n Assistant.

Optional: Use PostgreSQL instead of SQLite

SQLite is fine for trying things out, but for a production instance that must handle more than a handful of users or workflows running around the clock use Postgres instead.

  1. Add the Postgres credentials to .env, alongside the sandbox secrets:

  2. Add a postgres service to compose.yml, and a volume for its data:

  3. Point n8n at it by adding these to the n8n service's environment block, and making it wait on Postgres too:

  4. Restart everything:

    n8n migrates itself to the new Postgres database on startup. Existing SQLite data doesn't carry over automatically. This setup is for a fresh instance, not an in-place migration.

    For a more hardened setup, such as a dedicated non-root Postgres user and an external task runner, see the [`withPostgres` example](https://github.com/n8n-io/n8n-hosting/tree/main/docker-compose/withPostgres) in the n8n hosting repository.

Troubleshooting

Symptom
Likely cause

sandbox-api or sandbox-runner-1 fail to start, cert errors

sandbox-certs didn't complete. Check docker compose logs sandbox-certs.

sandbox-api never becomes healthy

Check its logs; also confirm wget actually exists in that image.

sandbox-runner-1 crash-loops on startup with ... must be set errors

It's missing required environment variables, most commonly SANDBOX_RUNNER_API_KEYS or SANDBOX_RUNNER_REGISTRATION_TOKEN. For the full list of environment variables the runner requires, run strings /usr/local/bin/sandbox-runner | grep -oE 'SANDBOX_[A-Z_]+ must be set' inside the runner container.

Runner never registers with the API

SANDBOX_RUNNER_REGISTRATION_TOKEN mismatch, or SANDBOX_RUNNER_API_GRPC_ADDR wrong.

n8n's sandbox calls fail

Sandbox URL/key in .env doesn't match sandbox-api's address or SANDBOX_API_KEYS.

Works on Linux, fails on WSL

Usually a bind-mount path issue. Keep the project inside the WSL filesystem, not /mnt/c/....

Security checklist

  • sandbox-runner-1 (privileged: true, Docker-in-Docker) is never exposed to the public internet. Treat it as equivalent to root on the host.

  • Only n8n's port is open on your cloud firewall.

  • SANDBOX_API_KEYS, the registration token, and the runner key are unique, not left as change-me-..., and rotated periodically.

  • sandbox-api and sandbox-runner-1 do not use env_file: .env. Each only receives the specific variables it needs, explicitly, in its environment block. The model API key, Brave key, Postgres password, and n8n encryption key never reach the sandbox containers.

  • The mTLS keys under the sandbox-tls volume, including the root CA key, are locked down to 0600 and owned only by the service that needs them (sandbox-api for its own key; root for the runner's key and the CA key). None of them are world-readable.

  • You have a plan to regenerate the sandbox-tls volume. The certs sandbox-certs generates don't autorenew.

Service architecture

n8n sends code execution requests to sandbox-api, which hands them to sandbox-runner-1, which creates and runs the actual sandbox containers. sandbox-certs runs once at startup to generate the TLS certificates the other two need and then exits; everything else waits on it.

Last updated

Was this helpful?