n8nを長く使っていると、UIやWebhookを受ける処理と、実際にワークフローを実行する処理を分けたくなる場面があります。特にCode Nodeや定期実行が増えてくると、どのコンテナが何を担当しているのかを分けておいた方が、更新や障害調査を進めやすくなります。
この記事では、Docker Composeでn8n Queue Modeを構成し、Main、Worker、Task Runner、Redis、PostgreSQLの役割を整理します。完全な無停止構成を作る話ではなく、受付・実行・キュー・データ保存の責務を分け、運用しやすい形にするのが狙いです。
flowchart LR Internet[Internet / Webhook] --> Caddy[Caddy] Caddy --> Main[n8n-main] Main --> Redis[(Redis Queue)] Redis --> Worker1[n8n-worker] Redis --> Worker2[n8n-worker-2] Worker1 --> Runner1[Task Runner] Worker2 --> Runner2[Task Runner 2] Main -. read/write .-> DB[(PostgreSQL)] Worker1 -. read/write .-> DB Worker2 -. read/write .-> DB
Queue Modeで分かれる役割
n8nのQueue Modeでは、MainインスタンスがトリガーやWebhookを受け付け、実行そのものはWorkerへ渡します。公式ドキュメントでも、Mainが実行IDをRedisへ渡し、WorkerがRedisから実行IDを受け取り、データベースからワークフロー情報を取得して処理する流れとして説明されています。
| n8n-main | UI、Webhook、Trigger管理。実行ジョブをRedisへ登録する。 |
| Redis | Pending executionのキュー。Workerへ実行IDを受け渡す。 |
| n8n-worker | キューからジョブを取得し、ワークフローを実行する。 |
| Task Runner | Code Nodeなどのタスク実行をn8n本体から分ける。 |
| PostgreSQL | Workflow、Credential、実行履歴などの永続データを保存する。 |
ここで大事なのは、Redisがワークフロー定義やCredentialを保存するわけではない点です。Redisはジョブの受け渡し、PostgreSQLは永続データという役割で見ると、トラブルシュート時に確認する場所を間違えにくくなります。
バージョンは環境に合わせて固定してください。Task Runnerを外部モードで使う場合、n8n本体とrunner imageのバージョンを揃えます。
Queue Modeは高可用性そのものではない
Queue Modeは、実行処理をWorkerへ分けるための構成です。Workerを増やせば同時に処理できる量を広げられますが、それだけでMain、Redis、PostgreSQLまで冗長化されるわけではありません。Mainを1台で動かすなら、Main更新中はUIやWebhook受付が短時間止まります。
- できること: MainとWorkerの責務を分け、Workerを追加・削除しやすくする
- できないこと: Queue Modeだけで全体を無停止化する
- 運用上の見方: まず役割分離、次にバックアップや監視、必要なら冗長化を考える
.envを用意する
Main、Worker、Runnerで共有する値を .env にまとめます。特に N8N_ENCRYPTION_KEY は全n8nプロセスで同じ値にします。これが違うと、データベースに保存されたCredentialをWorkerが扱えません。
openssl rand -hex 32
openssl rand -hex 32N8N_VERSION=2.25.7
N8N_ENCRYPTION_KEY=CHANGE_ME
N8N_RUNNERS_AUTH_TOKEN=CHANGE_ME
POSTGRES_PASSWORD=CHANGE_ME
REDIS_PASSWORD=CHANGE_ME
N8N_DEFAULT_BINARY_DATA_MODE=database
N8N_BLOCK_ENV_ACCESS_IN_NODE=true
N8N_COMMUNITY_PACKAGES_ENABLED=falseQueue ModeではMainとWorkerが同じバイナリデータへアクセスできる必要があります。n8n公式ドキュメントでは、Queue Modeで filesystem モードはサポートされず、database を使うよう案内されています。
docker-compose.ymlの要点
共通設定
MainとWorkerで共通するDB、Redis、暗号化キーなどはYAML anchorでまとめます。値を分散させないことで、更新時の見落としを減らします。
x-n8n-shared: &n8n-shared
image: docker.n8n.io/n8nio/n8n:${N8N_VERSION:-2.25.7}
restart: unless-stopped
environment: &n8n-env
EXECUTIONS_MODE: queue
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_DATABASE: n8n_cluster
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
QUEUE_BULL_REDIS_HOST: redis
QUEUE_BULL_REDIS_PORT: 6379
QUEUE_BULL_REDIS_PASSWORD: ${REDIS_PASSWORD:?REDIS_PASSWORD is required}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY:?N8N_ENCRYPTION_KEY is required}
N8N_DEFAULT_BINARY_DATA_MODE: database
N8N_BLOCK_ENV_ACCESS_IN_NODE: "true"n8n-main
n8n-mainはUIとWebhookを受ける入口です。手動実行もWorkerへ逃がしたい場合は OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS を有効にします。
n8n-main:
<<: *n8n-shared
ports:
- "${N8N_PORT:-5678}:5678"
environment:
<<: *n8n-env
WEBHOOK_URL: ${WEBHOOK_URL:-http://localhost:5678/}
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS: "true"
depends_on:
- redisWorkerとTask Runner
WorkerはRedisからジョブを取得して実行します。Task Runnerを外部モードで使う場合、公式ドキュメントではQueue Modeの各Workerに専用sidecarを持たせる構成が案内されています。n8n本体と n8nio/runners のバージョンも揃えます。
x-n8n-worker-env: &n8n-worker-env
<<: *n8n-env
N8N_RUNNERS_ENABLED: "true"
N8N_RUNNERS_MODE: external
N8N_RUNNERS_BROKER_LISTEN_ADDRESS: 0.0.0.0
N8N_RUNNERS_AUTH_TOKEN: ${N8N_RUNNERS_AUTH_TOKEN:?N8N_RUNNERS_AUTH_TOKEN is required}
n8n-worker:
<<: *n8n-shared
command: worker
environment:
<<: *n8n-worker-env
depends_on:
- redis
- n8n-worker-runner
n8n-worker-runner:
image: n8nio/runners:${N8N_VERSION:-2.25.7}
restart: unless-stopped
environment:
N8N_RUNNERS_AUTH_TOKEN: ${N8N_RUNNERS_AUTH_TOKEN:?N8N_RUNNERS_AUTH_TOKEN is required}
N8N_RUNNERS_TASK_BROKER_URI: http://n8n-worker:5679Workerを2台にする場合は、n8n-worker-2 と n8n-worker-runner-2 を同じ考え方で追加します。docker compose –scale で増やす方法も考えられますが、Runnerとの対応を明示したいなら個別定義の方が読みやすくなります。
RedisとPostgreSQL
Redisはコンテナ間通信だけで使うため、基本的には外部へポート公開しません。PostgreSQLはローカル検証ではCompose内で起動し、長期運用ではバックアップや可用性を考えて外部DBやマネージドDBへ移す選択肢があります。
redis:
image: redis:8-alpine
restart: unless-stopped
command: >
redis-server --requirepass ${REDIS_PASSWORD:?REDIS_PASSWORD is required}
postgres:
image: postgres:17-alpine
restart: unless-stopped
profiles:
- local-db
environment:
POSTGRES_DB: n8n_cluster
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
volumes:
- postgres-data:/var/lib/postgresql/data起動と確認
docker compose --profile local-db up -d
docker compose ps
curl -s http://localhost:5678/healthz{"status":"ok"} 問題が起きたら、まず docker compose ps で全体を見てから、Main、Worker、Redis、PostgreSQLのログへ分けて追います。役割が分かれているぶん、どこを見るかを決めやすいのがQueue Modeの良いところです。
docker compose logs -f n8n-main
docker compose logs -f n8n-worker
docker compose logs -f redis
docker compose logs -f postgresWorkerを片方ずつ更新する
Workerを複数にしていると、片方ずつ止めて更新する運用を試せます。ただし、長時間実行中のジョブを必ず無停止で守れるという意味ではありません。N8N_GRACEFUL_SHUTDOWN_TIMEOUT などで停止待ち時間を取りつつ、更新後にRedisとDBへ再接続できていることを確認します。
docker compose stop -t 300 n8n-worker-2
docker compose stop n8n-worker-runner-2
docker compose pull n8n-worker-2 n8n-worker-runner-2
docker compose up -d n8n-worker-runner-2 n8n-worker-2
docker compose psバックアップで忘れてはいけないもの
PostgreSQLにはWorkflow、Credential、実行履歴などが入ります。さらにCredentialの復号には N8N_ENCRYPTION_KEY が必要です。DBだけバックアップしても、暗号化キーを失うとCredentialを復号できません。
docker compose exec postgres pg_dump -U n8n n8n_cluster > backup.sql
# restore
docker compose exec -T postgres psql -U n8n n8n_cluster < backup.sqlハマりやすいところ
Workflowが実行待ちのまま進まない、またはWorkerのログにRedisやDB接続エラーが出る。
Redis接続情報、PostgreSQL接続情報、N8N_ENCRYPTION_KEY、Runner認証トークンの不一致が考えられます。
- MainとWorkerでN8N_ENCRYPTION_KEYが一致しているか
- WorkerがRedisとPostgreSQLへ接続できているか
- n8n本体とRunnerのバージョンが揃っているか
- Queue ModeでN8N_DEFAULT_BINARY_DATA_MODE=databaseになっているか
- Runnerごとに正しいN8N_RUNNERS_AUTH_TOKENを共有しているか
まずdocker compose psと各コンテナのログを確認し、Redis、DB、暗号化キー、Runner接続の順に切り分けます。
参考にした公式ドキュメント
使ってみた感想
Queue Modeは、単にWorkerを増やすためだけの機能ではなく、n8nの処理を役割ごとに見えるようにする構成だと感じました。Main、Worker、Runner、Redis、PostgreSQLの境界がはっきりすると、ログを見る場所や更新時に気をつける場所も決めやすくなります。
一方で、構成要素は増えます。最初から大きな負荷があるかどうかより、ワークフローを継続的に育てるつもりがあるか、Code Nodeをどの程度使うか、更新やバックアップをどう考えるかで採用を判断するのが良さそうです。
n8n Queue Modeは、受付と実行を分けて運用しやすくするための構成です。
- MainはUI、Webhook、Trigger管理を担当する
- WorkerはRedisからジョブを取得して実行する
- Task RunnerはCode Nodeの実行をn8n本体から分ける
- Redisはキュー、PostgreSQLは永続データとして役割を分けて見る
- Queue Modeだけで全体が無停止になるわけではない
TAKEAWAY個人環境でも、n8nを長く育てるなら、役割分離された構成にしておくと更新・調査・拡張の見通しが良くなります。

