n8nをVPSで動かす:落とし穴を先に潰す本番構成ガイド【2026年】
TL;DR
n8n Community Editionは2026年現在もセルフホストで無料・実行回数無制限のまま維持されています。「クラウド版が有料化した」という情報が出回っていますが、それはクラウド版のフリープランの話であり、セルフホスト版は別物です。
- 必要スペック: VPS 2GB RAM以上、Docker Compose、PostgreSQL(本番用)
- 採用構成: Ubuntu 22.04/24.04 + Docker Compose + PostgreSQL + Nginx + Let’s Encrypt
- この記事の対象: Dockerを扱えるエンジニア・情シス担当。「手順通りに起動した後、本番で止まる」を防ぐための構成ガイドです
Zapier Professional($19.99/月〜・タスク数で増加)に対して、ConoHa VPS 2GBプランなら月1,259円で無制限実行環境が整います。ただし「起動できる」と「安定稼働させられる」の間には7つの落とし穴があります。その全部を手順の前後で潰してから動かすのが、この記事の目的です。
なぜ今セルフホストに切り替えるのか
Zapierのコスト設計を一度整理しておく必要があります。
Zapierは「1ステップ=1タスク消費」の課金モデルです。5ステップで構成したワークフローを1,000回実行すると、5,000タスクを消費します。Professional プランは$19.99/月から始まりますが、ワークフローが複雑になるほどタスク消費が加速し、Team プラン($69/月〜)への移行圧力がかかります。
n8nの課金モデルは構造が異なります。同じ5ステップのワークフローを1,000回実行しても、カウントは1,000実行です。ステップ数が増えても消費は増えない。この非対称性が、ワークフローが複雑になればなるほど差を広げます。
n8n Community Editionのセルフホストは実行回数無制限で無料(2026年現在)です。コストはVPS代のみになります。
VPS月額の参考値(2026年6月時点):
- ConoHa VPS 2GBプラン: 1,259円/月(まとめトクプラン)
- さくらのVPS 最小プラン: 671円/月〜(仕様はさくらのVPS仕様ページで確認してください)
向かないケースも整理します。 バックアップ設計・サーバー管理・アップデート対応を自分でやりたくない場合や、運用工数ゼロを最優先にする場合は、n8n Cloud(Starter $24/月前後・2,500実行/月)が合理的です。管理コストをゼロにしたいニーズとセルフホストは相性が悪い。この前提を踏まえた上で、続きを読んでください。
構成の全体像を先に把握する
手順に入る前に、何を積み上げるのかを俯瞰します。
採用アーキテクチャ:
インターネット
↓ (443/80)
Nginx(HTTPS終端・リバースプロキシ)
↓ (5678 ローカルのみ)
n8n コンテナ(Docker Compose)
↓
PostgreSQL コンテナ(Docker Compose)
なぜDockerか
公式の最推奨構成です。n8nのアップデートが docker compose pull && docker compose up -d の2コマンドで完結し、環境の再現性も保たれます。
なぜPostgreSQLか
n8nのデフォルトデータベースはSQLiteです。ただし公式ドキュメントはSQLiteを本番環境に非推奨としています。ワークフロー定義・実行ログ・クレデンシャルの参照メタデータは永続化が必要で、同時書き込みが発生する本番稼働ではPostgreSQLが適切です。
なぜNginxを挟むか
n8nはデフォルトでポート5678で起動します。このポートを外部に直接公開するのは避けるべきです。NginxをHTTPS終端として置くことで、外部通信は443/80のみに絞られ、n8nのポートはコンテナ内のローカル通信に限定されます。
「動かすこと」と「安定稼働」のギャップ
この手順通りに進めれば起動はできます。ただし後述する7つの落とし穴を踏むと、本番稼働後に予期しない問題が発生します。手順の中で各落とし穴への対処を組み込みながら進めます。
実装手順
Step 1 — VPSの準備とDockerインストール
推奨OS: Ubuntu 22.04 LTS または 24.04 LTS
推奨RAM: 2GB以上。1GBは並列実行・大量データ処理でOOM(Out of Memory)クラッシュのリスクがあります(n8nlab.ioが確認済み)。後述する落とし穴のうち「メモリ不足」が最も発生しやすいサイズです。コスト優先でも1GBは避けてください。
VPS初期設定(ユーザー作成・SSHキー設定・ファイアウォール設定)が完了した状態から始めます。
Dockerをインストールします。
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
インストール後、現在のユーザーをdockerグループに追加します。
sudo usermod -aG docker $USER
newgrp docker
newgrp docker で現在のセッションにグループ変更を反映できます。再ログイン不要で確認できます。
動作確認:
docker --version
docker compose version
Step 2 — ディレクトリと .env ファイルの作成
作業ディレクトリを作成します。
mkdir -p ~/n8n && cd ~/n8n
.env ファイルを作成します。設定値の意味を一つずつ確認しながら書いてください。後の落とし穴と直結する変数が2つあります。
nano .env
# PostgreSQL
POSTGRES_USER=n8n
POSTGRES_PASSWORD=YOUR_STRONG_DB_PASSWORD
POSTGRES_DB=n8n
# n8n基本設定
N8N_HOST=yourdomain.com
N8N_PORT=5678
N8N_PROTOCOL=https
# 暗号化キー(一度設定したら変更禁止)
N8N_ENCRYPTION_KEY=YOUR_GENERATED_KEY
# WebhookのベースURL
WEBHOOK_URL=https://yourdomain.com/
# タイムゾーン(2変数ともに設定が必要)
GENERIC_TIMEZONE=Asia/Tokyo
TZ=Asia/Tokyo
N8N_ENCRYPTION_KEY について(落とし穴⑤の予防)
n8nはこのキーを使ってデータベース内のクレデンシャルを暗号化します。強いキーを生成するには以下を使います。
openssl rand -hex 32
出力された値を N8N_ENCRYPTION_KEY に設定してください。このキーは一度設定したら変更禁止です。 変更すると、既存のクレデンシャル(APIキー・パスワード)がすべて復号できなくなります(GravityWP チュートリアル確認済み)。.env ファイルは必ずバックアップしておいてください。
WEBHOOK_URL について(落とし穴①の予防)
この設定を間違えると、GitHubやSlackからのWebhookが届きません。末尾のスラッシュを含めるのが正しい形式です。
# 誤り
WEBHOOK_URL=https://yourdomain.com:5678/webhook/abc123
# 正しい
WEBHOOK_URL=https://yourdomain.com/
GENERIC_TIMEZONE と TZ の両方を設定する理由(落とし穴④の予防)
n8nはスケジュールトリガーの処理に GENERIC_TIMEZONE を参照し、コンテナのシステム時刻に TZ を参照します。片方だけ設定するとスケジュールトリガーのズレが発生します。両方を Asia/Tokyo に揃えてください。
Step 3 — Dockerボリュームの作成
docker volume create n8n_data
docker volume create n8n_db_data
なぜボリュームが必要か。コンテナを削除・再作成したとき、ボリュームなしではデータが消えます。n8n_data には暗号化キー・ローカルファイルが含まれ、n8n_db_data はPostgreSQLのデータ本体です。この2行を省略すると、コンテナを再作成するたびにすべての設定が失われます(落とし穴⑤の防止策でもあります)。
Step 4 — docker-compose.yml の作成
nano docker-compose.yml
version: "3.8"
services:
postgres:
image: postgres:15
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- n8n_db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 5s
timeout: 5s
retries: 5
n8n:
image: docker.n8n.io/n8nio/n8n
restart: unless-stopped
ports:
- "127.0.0.1:5678:5678"
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
- DB_POSTGRESDB_USER=${POSTGRES_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
- N8N_HOST=${N8N_HOST}
- N8N_PORT=${N8N_PORT}
- N8N_PROTOCOL=${N8N_PROTOCOL}
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- WEBHOOK_URL=${WEBHOOK_URL}
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- TZ=${TZ}
volumes:
- n8n_data:/home/node/.n8n
depends_on:
postgres:
condition: service_healthy
volumes:
n8n_data:
external: true
n8n_db_data:
external: true
各設定の意味を確認します。
restart: unless-stopped: VPSが再起動したときにコンテナを自動で起動させます。手動でdocker compose stopした場合は再起動しませんdepends_on: postgres: condition: service_healthy: PostgreSQLのヘルスチェックが通ってからn8nを起動します。PostgreSQLより先にn8nが起動してDB接続エラーになるのを防ぎますports: "127.0.0.1:5678:5678": ポート5678をlocalhostのみに制限します。外部から直接アクセスできない状態にします。NginxはこのlocalhostのポートにProxy Passしますimage: docker.n8n.io/n8nio/n8n: n8nの公式イメージはdocker.n8n.io/n8nio/n8nです。latestタグで自動追従するか、n8nio/n8n:X.XX.Xのように特定バージョンを固定するかはチームのポリシーに従ってください。最新の安定版バージョンは n8n GitHubリリースページ(github.com/n8n-io/n8n/releases) で確認してください。バージョンを固定する場合、アップデート時はタグの明示的な変更が必要です
Step 5 — 起動と疎通確認
docker compose up -d
起動状態を確認します。
docker compose ps
State が running になっていることを確認します。PostgreSQLのヘルスチェックが通るまで数秒かかるため、起動直後は starting になることがあります。
VPS内からの疎通確認:
curl http://localhost:5678
n8nのHTMLレスポンスが返ってくれば起動しています。
この時点ではHTTPSが未設定のため、外部からのアクセスはまだ機能しません。ポート5678はファイアウォールで閉じたままにしてください。次のStep 6でNginxとSSLを設定してから、ブラウザでアクセスします。
Step 6 — NginxとLet’s EncryptでHTTPS設定
なぜHTTPSが必須か
WebhookはGitHub・Slack・Stripe等の外部サービスから呼ばれます。これらの多くはHTTPSのエンドポイントにしかリクエストを送りません。HTTPのまま稼働させると、Webhookトリガーを使ったワークフローがまったく機能しない状態になります。
2つの選択肢
| Nginx + Certbot | Caddy | |
|---|---|---|
| SSL取得 | certbotコマンドで手動 | Caddyfileに記述するだけで自動 |
| 設定ファイル | やや記述量が多い | シンプル(2〜3行) |
| カスタマイズ | 細かく制御できる | 抽象化されている |
| 枯れ具合 | 実績が豊富 | 近年採用が増加中 |
どちらを選んでも機能的な差はありません。設定ファイルを細かく制御したい場合はNginx、設定コストを最小化したい場合はCaddyが適しています。
Nginxを選ぶ場合
Nginxインストール後、n8n向けのsite configを /etc/nginx/sites-available/n8n に作成します。基本的な構成は proxy_pass http://localhost:5678; にProxy Passする形です。WebSocketを使うため proxy_http_version 1.1; と Upgrade・Connection ヘッダーの転送設定が必要です。
具体的なserver_name・ssl_certificate・ssl_certificate_keyの設定は、DigitalOceanの「How To Install Nginx on Ubuntu 22.04」チュートリアルおよびCertbotの公式手順(certbot.eff.org)を参照して進めてください。環境(ドメイン・ディストリビューション)によって差が出るため、一次ソースの手順に従うのが安全です。
Caddyを選ぶ場合
Caddyfileに以下を記述するだけでSSL取得・自動更新まで完結します。
yourdomain.com {
reverse_proxy localhost:5678
}
HTTPS設定完了後、ファイアウォールの設定を確認します。
# UFW の場合
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# ポート5678は外部向けに閉じたまま
sudo ufw deny 5678/tcp
設定後、ブラウザで https://yourdomain.com にアクセスしてn8nのセットアップ画面が表示されれば完了です。
Step 7 — アップデート手順
n8nのアップデートは2コマンドで完結します。
cd ~/n8n
docker compose pull
docker compose up -d
docker compose pull で最新イメージを取得し、docker compose up -d で再起動します。バージョンを固定している場合は docker-compose.yml のイメージタグを変更してから実行します。
アップデート前の必須作業: PostgreSQLのバックアップを取ってから実行してください(バックアップ手順は次のセクション参照)。メジャーアップデートでDBスキーマが変わる場合があります。
本番稼働前に潰すべき落とし穴7点
手順通りに起動できても、本番で問題が出る典型パターンが7つあります。これが「起動できる」と「安定稼働させられる」の差です。
① WEBHOOK_URLの設定漏れ(最頻出)
Webhookが届かない問題の原因として最も多いのがこれです(blog.tamertemel.net確認済み)。
# 誤り(ポートが残っている)
https://yourdomain.com:5678/webhook/abc123
# 正しい(ドメインのみ・末尾スラッシュ)
https://yourdomain.com/webhook/abc123
WEBHOOK_URL は https://yourdomain.com/(末尾スラッシュあり)の形式で設定します。ポート番号を含めないでください。Nginxが80/443で受けてからlocalhost:5678に転送するため、外部からはポートが見えません。
② メモリ不足(OOM Kill)
1GB RAMのVPSで並列実行・大量データ処理を行うとOOMクラッシュが発生します(n8nlab.io確認済み)。
n8nの公式ドキュメント(docs.n8n.io)に記載されているエラーメッセージ:
Execution stopped at this node (n8n may have run out of memory while executing it)Allocation failed - JavaScript heap out of memory
このエラーが発生した場合の対処:
メモリ上限の引き上げ: docker-compose.yml のn8nサービスの environment に追加します。
- NODE_OPTIONS=--max-old-space-size=1024
ワークフローの分割: 大量データを一度に処理している場合、「Loop Over Items」ノードを使ってチャンク分割します。根本的な解決はVPSのRAMを2GB以上に変更することです。
③ SQLiteのまま本番稼働
この記事の手順(Step 4)でPostgreSQLを設定していれば回避済みです。ただし古い構成記事を参照してSQLiteのまま構築した場合、同時書き込みが発生する本番環境でデータ破損のリスクがあります。公式はSQLiteを本番環境に非推奨と明記しています。
④ タイムゾーン設定の不足
GENERIC_TIMEZONE と TZ のどちらか一方だけ設定するとスケジュールトリガーがズレます。両方を Asia/Tokyo に設定する必要があります(Step 2参照)。日本時間09:00実行のトリガーが別の時刻に動く場合、この設定を最初に確認してください。
⑤ N8N_ENCRYPTION_KEYの消失
コンテナを削除・再作成するとき、Dockerボリュームを永続化していない場合は暗号化キーが消えます。Step 3でボリュームを外部作成し、docker-compose.ymlで external: true を指定しているため、この手順通りに進めていれば回避済みです。
万が一キーが消えた場合、データベース内の既存クレデンシャルはすべて復号不可になります。.env ファイルのバックアップが唯一の復旧手段です。
⑥ Community Editionが有料化したという誤解
2025年にn8nの料金体系が変更され、「n8nが有料化した」という情報が広まりました(zeabur.com・instapods.com確認済み)。
正確な内容は以下です:
- Community Edition(セルフホスト): 引き続き無料・実行回数無制限
- Business Plan: SSO/SAML/LDAP等のエンタープライズ機能が新設(個人・中小チームには不要)
- クラウド版フリープラン: 廃止済み(次の⑦)
セルフホストの無料継続に変更はありません。
⑦ クラウド版フリープランの廃止とセルフホストの混同
n8n Cloudのフリープランは廃止されました。現在のクラウド版最安はStarter($24/月前後・2,500実行/月・instapods.com記載値)です。
セルフホスト版はこの変更の影響を受けません。 n8n CloudとCommunity Editionは別のプロダクトです。「フリープランが廃止された」という情報を見てセルフホストを検討している場合、正しい動機です。
バックアップ設計
「動かせる」と「安心して運用できる」の間を埋める最重要ポイントです。
PostgreSQLのバックアップ
DockerコンテナのPostgreSQLを pg_dump でダンプする基本形:
docker exec n8n-postgres-1 pg_dump -U n8n n8n > backup_$(date +%Y%m%d).sql
コンテナ名は環境によって異なります。docker compose ps で確認してください。
cronによる定期バックアップ
crontab -e
毎日深夜2時にバックアップを取る例:
0 2 * * * docker exec n8n-postgres-1 pg_dump -U n8n n8n > /home/youruser/backups/n8n_$(date +\%Y\%m\%d).sql
バックアップファイルはVPS上に置くだけでなく、外部ストレージ(S3・Cloudflare R2等)に転送することを推奨します。VPSごと障害になった場合に備えてです。
.n8nディレクトリのバックアップ
PostgreSQL以外に、Dockerボリューム n8n_data(マウントポイント: /home/node/.n8n)にも暗号化キー・ローカルファイルが格納されています。このボリュームも定期的にバックアップしてください。
# ボリュームの内容を tar でアーカイブする例
docker run --rm -v n8n_data:/data -v $(pwd):/backup ubuntu tar czf /backup/n8n_data_$(date +%Y%m%d).tar.gz /data
バックアップ設計全体(保持期間・S3転送・自動化の仕組み)は構成が複雑になります。本記事の手順で動かせた後、別途設計することを推奨します。
コスト総括
構成ごとのコストを整理します(2026年6月時点)。
| 構成 | 月額コスト | 実行回数上限 | 管理コスト |
|---|---|---|---|
| n8n Community + ConoHa 2GB VPS | 1,259円/月 | 無制限 | 自己管理(本記事の手順) |
| n8n Community + さくらのVPS(最小) | 671円/月〜 | 無制限 | 自己管理(RAM仕様はさくらのVPS仕様ページ参照) |
| n8n Cloud Starter | $24/月前後(instapods.com記載値) | 2,500回/月 | ゼロ |
| n8n Cloud Pro | $60/月前後(instapods.com記載値) | 10,000回/月 | ゼロ |
| Zapier Professional | $19.99/月〜(タスク数で増加)(2026年6月時点・zapier.com/pricing 確認) | タスク数依存 | ゼロ |
セルフホストを選ぶ理由は「無制限実行を安く維持したい」場合です。n8n Cloudと比較した場合、チームにもよりますが年間$200〜700程度の節約になるとされています(instapods.com調査値)。ただしその分、サーバー管理・バックアップ設計・アップデート対応が自己責任になります。
構築がうまくいかないときの確認順序
手順通りに進めても詰まる場合、まず以下の順で確認します。
ログの確認:
docker compose logs n8n
docker compose logs postgres
エラーメッセージの大半はここに出ます。
症状別の確認ポイント:
-
Webhookが届かない → まず
.envのWEBHOOK_URLを確認。https://yourdomain.com/の形式になっているか。次にNginxの設定でproxy_passがlocalhost:5678に向いているかを確認 -
起動後しばらくしてクラッシュする →
docker statsでメモリ使用量を確認。n8nコンテナが2GB近くを使っていればOOMの疑い。VPS RAMが1GBの場合は2GBプランへの変更が根本解決 -
クレデンシャルが突然使えなくなった →
.envのN8N_ENCRYPTION_KEYが変更されていないかを確認。キーが変わると既存のクレデンシャルは復号不可になります。バックアップした.envの値と一致しているかを照合
ここまで確認してもなお解決しない場合、構成の設計判断や環境固有の問題である可能性が高いです。
WEBHOOK_URL の誤設定 / OOMクラッシュ / バックアップ設計 —— この3点は、構成の判断が絡むため自己解決が難しいことがあります。確認済みの状況をメールで共有いただければ、詰まっているポイントを絞り込みます。PostgreSQL + Docker Compose + Nginx構成で詰まっている、またはZapierからn8nへの移行設計で迷っている場合が対象です。