n8n を VPS にセルフホストして、Claude と MCP で繋ぐ (Docker Compose + Tailscale)
自動化ツール n8n を月 2,000 円台の VPS に Docker で立て、Tailscale 経由で HTTPS のままスマホから使えるようにします。Claude を挟んだワークフローの作り方と、n8n を MCP サーバーにして Claude Code から呼ぶ手順まで。
本記事にはプロモーション (アフィリエイト広告) が含まれます。
n8n は、Zapier や Make と同じ「ノードを線で繋いで自動化を組む」ツールです。違いはソースが公開されていて、自分の VPS に置けば無料・実行回数無制限 で使えることです。
この記事では、n8n を VPS に立てて、3 段階で使えるようにします。
- Docker Compose で n8n を起動し、Tailscale 経由でスマホからも HTTPS で開ける状態にする (20 分)
- ワークフローの途中に Claude を挟む。例として「毎朝 VPS の状態を Claude に要約させて通知する」を作る
- n8n を MCP サーバー として公開し、Claude Code から n8n のワークフローを道具として呼べるようにする
3 まで行くと、Claude Code に「VPS のディスク空き容量を見て」と頼むだけで、n8n のワークフローが走って結果が返ってきます。
n8n Cloud とセルフホストの違い
| n8n Cloud | セルフホスト | |
|---|---|---|
| 料金 | 月 20 ユーロ〜 (Starter、年払い) | VPS 代のみ |
| 実行回数 | Starter 2,500 回 / Pro (50 ユーロ) 10,000 回 | 無制限 |
| 更新 | 自動 | 自分で docker compose pull |
| 外部からの Webhook | そのまま届く | 公開設定が必要 (後述) |
| データの置き場所 | n8n 社のサーバー | 自分の VPS |
セルフホストが向いているのは、実行回数が多い、扱うデータを外に出したくない、同じ VPS で動いているもの (Ollama やデータベース) と直接繋ぎたい、のどれかに当てはまる場合です。逆に、GitHub や Stripe からの Webhook を受ける用途が中心なら、Cloud の方が楽です。
この記事で使う環境
- VPS: XServer VPS クラウド 4GB、Ubuntu 24.04。初期設定 と Tailscale の設定 が済んでいる状態
- Docker: 公式のインストーラーで導入済み (
curl -fsSL https://get.docker.com | sudo sh→sudo usermod -aG docker $USER→ 入り直し)。この記事の時点で 29.8.1、Compose は v5.5.1 - Claude: Anthropic の API キー (n8n から Claude を呼ぶのは API 経由。claude.ai のサブスクリプションとは別の課金です)
- 手元: Mac と Android (Pixel 7a)。どちらも Tailscale に接続済み
1. Docker Compose で立てる
mkdir -p ~/n8n && cd ~/n8n
compose.yaml を置きます。
# ~/n8n/compose.yaml
services:
n8n:
image: docker.n8n.io/n8nio/n8n
container_name: n8n
ports:
- "127.0.0.1:5678:5678" # ループバックだけに束縛。外には出さない
environment:
N8N_HOST: "vpsnotes-001.tailc121dc.ts.net" # Tailscale の MagicDNS 名 (後述)
N8N_PROTOCOL: "https"
N8N_PORT: "5678"
WEBHOOK_URL: "https://vpsnotes-001.tailc121dc.ts.net/"
GENERIC_TIMEZONE: "Asia/Tokyo"
TZ: "Asia/Tokyo"
N8N_RUNNERS_ENABLED: "true"
volumes:
- n8n_data:/home/node/.n8n
restart: unless-stopped
volumes:
n8n_data:
ポイントは 2 つです。
portsを127.0.0.1:5678:5678にして、インターネット側には一切出さない。Docker は ufw を迂回するので、ここで束縛しておくのが確実ですN8N_HOSTとWEBHOOK_URLには、次の手順で Tailscale が割り当てる HTTPS の名前を入れます。ここが合っていないと、Webhook の URL 表示やログインの Cookie がおかしくなります
tailc121dc の部分は自分の tailnet 名です。Mac から ping vpsnotes-001 を打ったときに vpsnotes-001.tailc121dc.ts.net のようにフルネームで表示されるので、そこで分かります。Tailscale の管理画面の DNS タブにも出ています。
docker compose up -d
docker compose logs -f
n8n | n8n ready on ::, port 5678
n8n | Version: 2.39.8
n8n | Editor is now accessible via:
n8n | https://vpsnotes-001.tailc121dc.ts.net
この記事の時点のバージョンは 2.39.8 です。ログに Error fetching from Strapi API (https://api.n8n.io/api/mcp-servers): timeout のようなエラーが出ることがありますが、これは n8n が MCP サーバーのカタログを外部から取りに行って失敗しただけで、動作には影響しません。
起動直後のメモリはこうでした。
docker stats --no-stream n8n
NAME MEM USAGE / LIMIT CPU %
n8n 931.1MiB / 3.818GiB 0.05%
n8n だけで 930MB 使います。Claude Code の常駐と合わせると、ホスト全体で 1.8GB、空きが 2.0GB です。4GB プランで n8n + Claude Code は問題ありませんが、ここに Ollama も載せるなら 8GB が要ります。
2. Tailscale Serve で HTTPS にする
ループバックに束縛した 5678 番を、Tailscale の serve で tailnet の中だけに HTTPS 付きで公開します。証明書は Tailscale が Let’s Encrypt から自動で取ります。
先に、Tailscale の管理画面 (https://login.tailscale.com/admin/dns) の下の方にある HTTPS Certificates を有効にしておきます。これがないと証明書が取れません。

VPS で serve を有効にします。
sudo tailscale serve --bg 5678
sudo tailscale serve status
Available within your tailnet:
https://vpsnotes-001.tailc121dc.ts.net/
|-- proxy http://127.0.0.1:5678
Serve started and running in the background.
https://vpsnotes-001.tailc121dc.ts.net (tailnet only)
|-- / proxy http://127.0.0.1:5678
Mac やスマホのブラウザで https://vpsnotes-001.tailc121dc.ts.net を開くと n8n の画面が出ます。証明書は Let’s Encrypt から自動で取られ、私の環境では serve を打ってから 1 分以内にブラウザで開けました。ufw で 5678 を開ける必要はなく、Tailscale に繋いでいないデバイスからは届きません。実際に VPS のグローバル IP に対して 5678 番と 443 番を叩いても、どちらもタイムアウトします。
最初に開いたときに、オーナーアカウント (メールアドレスとパスワード) の作成を求められます。これは n8n の中だけで使う認証で、外部には送られません。
そのあと案内が 3 つ続きますが、全部飛ばして構いません。
- アンケート (会社の種類、役割、用途など)。統計用で、動作に影響しません
- 無料ライセンスキーの案内。メールを登録すると、デバッグ機能とフォルダ機能が開放されます。実質はメルマガ登録で、後から設定画面で申請できるので「Skip」で
- AI アシスタントの案内。n8n 社のクラウドに繋ぐ機能で、セルフホストの目的からすると不要です。「Set up later in Settings」で



「Let’s build your first automation」の画面が出れば、セットアップは完了です。

外部からの Webhook を受けたいとき
serve は tailnet の中だけです。GitHub や Slack のような外部サービスから Webhook を受けるには、そのパスだけをインターネットに出す必要があります。tailscale funnel を使うと、指定したパスだけを公開できます。
sudo tailscale funnel --bg --set-path /webhook http://127.0.0.1:5678/webhook
エディタ画面までインターネットに出すのは避けてください。Webhook のパスだけで十分です。この記事では外部からの Webhook を使わないので、funnel は試していません。使う前に tailscale funnel status で、/ (エディタ) が公開に含まれていないことを確認してください。
3. Claude をワークフローに挟む
n8n には Anthropic ノードがあり、API キーを設定すると Claude をワークフローの途中に置けます。もっと複雑な「AI Agent」ノード (ツールを持たせて自律的に動かす) もありますが、この記事は「渡した文章を要約させる」だけなので、Anthropic ノードを直接使います。
API キーを発行する
Anthropic Console (https://console.anthropic.com/) の「API キー」→「キーを作成」で発行します。claude.ai のサブスクリプションとは別の従量課金で、初回は支払い方法の登録が要ります。この記事の用途 (1 日数回の短い要約) なら月に数十円です。

「ID 連携を使えば API キーは不要です」という案内が出ますが、これは GCP や GitHub Actions のようなクラウド側で使う仕組みで、自分の VPS の n8n には使えません。「API キーで続ける」を選びます。

名前は n8n-vpsnotes のように用途が分かるものにします。有効期限に注意 してください。初期値が 30 日になっていることがあり、そのままだと 1 か月後にワークフローが止まります。常駐で使うなら無期限か、長いものを選びます。

作成後に表示されるキーは一度しか見られないので、そのまま n8n に貼ります。
n8n に登録する
n8n の左上「+」→「New credential」→ 検索欄に Anthropic → Continue。


API Key の欄にキーを貼って Save します。他の欄 (Base URL、Custom Header、Allowed Domains) は初期値のままで構いません。

Save すると n8n がキーを使って Anthropic の API に接続し、「Connection tested successfully」と出ます。

まず Claude が呼べることを確かめる
いきなり全部組む前に、Claude に 1 行返させるだけの最小のワークフローで経路を確かめます。
- 左上「+」→「New workflow」
- キャンバスの「+」→ 検索
Manual→ Trigger manually - その右の「+」→ 検索
Anthropic→ Anthropic ノード。Operation は「Message a Model」 - Credential に
Anthropic account、Model にclaude-sonnet-5、Prompt にVPS の運用担当として、今日の一言を 30 字で。 - 「Execute step」
初回はここでエラーになりました。

「Bad request - please check your parameters」と出るので設定ミスに見えますが、詳細を読むと Your credit balance is too low です。Anthropic の API は 前払い制 で、キーを作っただけでは残高が 0 です。Console の Plans & Billing で最小額 (5 ドル) を買うと通ります。この記事の用途なら数か月持ちます。

「落ちない設計より、落ちても気づける設計を。」と返ってきました。経路は通っています。
例: 毎朝 VPS の状態を Claude に要約させる
やることは単純です。VPS で free -h と df -h を実行し、その出力を Claude に渡して「気になる点があれば指摘して」と頼み、結果を通知します。
- Schedule Trigger: 毎朝 8 時
- SSH:
free -h && df -h / && uptimeを実行 - Anthropic: 2 の出力を渡して要約させる
- Telegram: 3 の結果を送る
n8n のコンテナから VPS 自身に SSH する
2 の SSH ノードが、この記事で一番詰まったところです。n8n は Docker のコンテナの中で動いているので、localhost と書いてもコンテナ自身を指してしまい、VPS には届きません。ホストの Tailscale IP (100.96.34.27) を指定します。
まず VPS 側で、n8n 専用の鍵を作ります。鍵の形式に注意 してください。n8n の SSH ライブラリは新しい OpenSSH 形式 (-----BEGIN OPENSSH PRIVATE KEY-----) の ed25519 鍵を読めず、Cannot parse privateKey: Unsupported key format になります。RSA を PEM 形式で作ります。
ssh-keygen -t rsa -b 4096 -m PEM -f ~/.ssh/n8n_rsa -N "" -C "n8n@vpsnotes-001"
cat ~/.ssh/n8n_rsa.pub >> ~/.ssh/authorized_keys
cat ~/.ssh/n8n_rsa
最後の cat で出る -----BEGIN RSA PRIVATE KEY----- から -----END RSA PRIVATE KEY----- までを、n8n の Credential に貼ります。左上「+」→「New credential」→ SSH → SSH Private Key。Host 100.96.34.27、Port 22、Username deploy、Private Key に鍵の全文です。
ここで Save しても、最初は「Couldn’t connect with these settings」になりました。

原因は ufw です。初期設定と Tailscale で、22 番は「tailscale0 からだけ許可」にしました。コンテナからの通信は Docker のブリッジ (192.168.16.x) から来るので、これに弾かれます。コンテナからの SSH だけ許可を足します。
sudo ufw allow from 192.168.16.0/20 to any port 22 proto tcp comment 'n8n container to ssh'
sudo ufw status numbered
To Action From
-- ------ ----
[ 1] Anywhere on tailscale0 ALLOW IN Anywhere
[ 2] 22/tcp ALLOW IN 192.168.16.0/20 # n8n container to ssh
[ 3] Anywhere (v6) on tailscale0 ALLOW IN Anywhere (v6)
192.168.16.0/20 は Docker が n8n のネットワークに割り当てた範囲です。自分の環境では docker exec n8n ip route で確認できます。インターネット側からの 22 番は閉じたままです。
Credential の「Retry」で通ります。

SSH の出力を Claude に渡す
ワークフローの Trigger と Anthropic の間に SSH ノードを足します。Resource は Command、Operation は Execute、Command に free -h && df -h / && uptime。「Execute step」で stdout に出力が入ります。

Anthropic ノードの Prompt を、この stdout を差し込む形に書き換えます。Prompt 欄を Expression に切り替えてから、次を入れます。
あなたは VPS の運用担当です。以下は VPS で実行した free / df / uptime の出力です。
メモリ・ディスク・負荷に気になる点があれば指摘し、なければ「問題なし」と 1 行で。日本語で 3 行以内。
{{ $json.stdout }}
{{ $json.stdout }} が前のノードの出力に置き換わります。Fixed のままだと文字列として送られてしまうので、Expression になっていることを確認してください。

「メモリ・ディスク・負荷いずれも健全な範囲内です。問題なし。」と返ってきました。これで「SSH で取って Claude に判断させる」の基本形は完成です。

Telegram に通知する
通知先は Telegram にしました。普段使っていてスマホに通知が来るものなら何でも構いません。Discord や Slack なら Webhook で同じことができます。
Telegram は Bot を作って、その Bot から自分宛てに送る形です。
- Telegram で
@BotFatherを開き、/newbot→ 表示名 → ユーザー名 (末尾bot) の順に答えると、HTTP API token が出る。これは秘密情報なので n8n にだけ貼る - 作った Bot を開いて
/startか何か 1 通送る - ブラウザで
https://api.telegram.org/bot<トークン>/getUpdatesを開くと、"chat":{"id":123456789の形で Chat ID が出る。反映に数秒かかるので、空なら少し待って再読み込み
n8n で Anthropic ノードの右の「+」→ Telegram → Send a text message。Credential を新規作成して Access Token に Bot のトークンを入れると、接続テストが通ります。

Chat ID に 3 で取った数字、Text を Expression で {{ $json.content[0].text }} にして「Execute step」。

スマホの Telegram に Claude の要約が届きました。末尾に「This message was sent automatically with n8n」という宣伝文が付きますが、Additional Fields の Append n8n Attribution を OFF にすると消せます。
毎朝 8 時に動かす
最後に、手動のトリガーをスケジュールに変えます。右上の「+」→ Schedule → Schedule Trigger。Trigger Interval を Days、Hour を 8、Minute を 0 にして、出力を「Execute a command」に繋ぎます。
Manual Trigger (「When clicking ‘Execute workflow’」) は、クリックすると実行されてしまって選択しにくく、消すのに手間取りました。ドラッグで少し動かしてから離すと選択状態になり、Delete キーで消えます。消さずに残しておいても動作には影響しません。
ワークフロー名を付けて、右上の Publish を押すと有効になります。Publish しないとスケジュールは動きません。

この形ができると、「SSH で何か取ってきて Claude に判断させて通知する」パターンは全部同じ作りで組めます。ログの異常検知、バックアップの成否確認、証明書の期限確認などです。
4. n8n を MCP サーバーにして Claude Code から呼ぶ
ここからが、このサイトならではの使い方です。n8n には MCP Server Trigger というノードがあり、ワークフローを MCP の「ツール」として公開できます。Claude Code にそのサーバーを登録すると、Claude Code が必要に応じて n8n のワークフローを呼ぶようになります。
n8n 側: ツールになるワークフローを作る
構造は 2 段です。「MCP Server Trigger を持つワークフロー」が窓口で、その Tools に「実際の処理をするサブワークフロー」をぶら下げます。SSH ノードは Tools に直接は繋げないので (Tools に繋げるのは「〜 Tool」という種類のノードだけ)、SSH を実行するサブワークフローを別に作って、それを「Call n8n Workflow Tool」で呼ぶ形にします。
サブワークフロー disk_and_memory
- 「+」→「New workflow」
- 最初のノードで「Execute Sub-workflow」カテゴリを開き、Triggers の When executed by Another Workflow を選ぶ

- 右に SSH ノード (Credential は先ほどの SSH Private Key account、Command は
free -h && df -h / && uptime) - 名前を
disk_and_memoryにして Publish

MCP のワークフロー VPS MCP tools
- 「+」→「New workflow」→ 最初のノードで
MCPを検索 → MCP Server Trigger

- Path を
vps-toolsのような分かりやすい名前に、Instructions にVPS (vpsnotes-001) の状態を確認するツール群。と書く。Instructions は Claude Code がこのサーバーの用途を把握するのに使われます - 下の Tools の「+」→
workflowで検索 → Call n8n Workflow Tool

- Workflow に
disk_and_memoryを選び、Description にVPS (vpsnotes-001) のメモリ・ディスク・稼働時間を取得する。引数は不要。と書く。この Description が、Claude Code がツールを選ぶときの判断材料になります

「This node must be connected to an AI agent」という警告が出ますが、MCP Server Trigger の Tools に繋がっていれば動きます。Tools の ◇ と Tool の ◇ が点線で繋がっていることを確認してください。

- Publish
Authentication は None のままにしました。エンドポイントは Tailscale の中にしか公開していないので、tailnet の外からは届きません。インターネットに出す場合は Bearer にしてトークンを設定してください。
動いているか確かめる
Publish 後のエンドポイントは https://vpsnotes-001.tailc121dc.ts.net/mcp/vps-tools です (Test URL の mcp-test が mcp になります)。トランスポートは Streamable HTTP で、curl で initialize を投げると応答します。
curl -s -X POST https://vpsnotes-001.tailc121dc.ts.net/mcp/vps-tools \
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
event: message
data: {"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{}},"serverInfo":{"name":"MCP_Server_Trigger","version":"0.1.0"},"instructions":"VPS (vpsnotes-001) の状態を確認するツール群。"},"jsonrpc":"2.0","id":1}
Claude Code 側: MCP サーバーを登録する
Claude Code を動かしているマシン (この VPS 自身でも、手元の Mac でも) で登録します。Tailscale に繋がっていれば、どちらからでも届きます。
claude mcp add --transport http n8n https://vpsnotes-001.tailc121dc.ts.net/mcp/vps-tools
claude mcp list
n8n: https://vpsnotes-001.tailc121dc.ts.net/mcp/vps-tools (HTTP) - ✔ Connected
あとは普通に話しかけるだけです。
> n8n の MCP ツールを使って、VPS のディスクとメモリの状況を確認して。結果を 3 行で要約して。
VPS (vpsnotes-001) の状況です。
- メモリ: 3.8GiB中1.5GiB使用、available 2.3GiB、swapはほぼ未使用(524Ki/2GiB)で余裕あり
- ディスク: /dev/vda1 48GB中6.8GB使用(15%)、41GB空き
- 稼働: 4日21時間稼働、load average 0.02とほぼアイドル状態、いずれも健全
Claude Code が n8n のツールを呼び、n8n がサブワークフローで SSH を実行し、その結果を Claude Code が読んで答えています。ツール名は「Call n8n Workflow Tool」のノード名から自動で付くので (初期値だと Call_disk_and_memory_)、ノード名を disk_and_memory に変えておくときれいになります。
何が嬉しいのか
Claude Code に「道具」を足す方法はいくつかありますが、n8n を挟むと、道具の中身を画面で組み替えられる のが利点です。SSH で取る情報を増やす、結果を Slack にも流す、といった変更を、Claude Code 側は何も触らずに済ませられます。
逆に、n8n の MCP Client Tool ノードを使えば、n8n のワークフローから外部の MCP サーバーを呼ぶこともできます。こちらは試していないので、別の機会に。
運用
更新
cd ~/n8n
docker compose pull
docker compose up -d
n8n は更新が速いので、月に 1 回くらいは上げておくと、ノードの追加や不具合修正の恩恵を受けられます。
バックアップ
ワークフローと認証情報は n8n_data ボリュームに入っています。
docker run --rm -v n8n_n8n_data:/data -v $(pwd):/backup alpine tar czf /backup/n8n-$(date +%F).tgz -C /data .
docker volume ls で見ると、ボリューム名は n8n_n8n_data (ディレクトリ名 + compose の volume 名) でした。
認証情報は n8n が暗号化して保存しています。暗号化キーは ~/.n8n/config の中にあり、ボリュームごとバックアップすれば一緒に取れます。VPS を作り直すときは、このキーがないと認証情報が復号できません。
費用
- VPS: XServer VPS クラウド 4GB で月 2,480 円 (12 か月契約なら 2,068 円)
- Anthropic API: ワークフローの実行回数次第。毎朝 1 回の要約なら月数十円です
- n8n、Tailscale: 無料
初回に 5 ドル分のクレジットを買い、この記事の検証 (十数回の呼び出し) で消費したのは数セントでした。毎朝 1 回の要約なら、5 ドルで半年以上持つ計算です。
つまずいた点
- Anthropic API の「Bad request」。設定ミスかと思ったら、クレジット残高が 0 でした。API キーを作っただけでは使えず、前払いでクレジットを買う必要があります
- API キーの有効期限。Anthropic Console で作るときの初期値が 30 日になっていました。気づかずに進めると 1 か月後にワークフローが止まります
- SSH の鍵の形式。ed25519 で作った鍵を n8n に貼ったら
Unsupported key formatで弾かれました。RSA を PEM 形式 (-m PEM) で作り直して通りました - コンテナから VPS 自身に SSH できない。ufw で
tailscale0からしか 22 番を許可していなかったので、Docker のブリッジから来る通信が弾かれていました。Docker のネットワーク範囲を許可して解決 - Manual Trigger が消せない。クリックすると実行されてしまい、選択できませんでした。ドラッグで少し動かすと選択状態になります。消さずに残しても動作には影響しません
- MCP の Tools に SSH ノードが出ない。Tools に繋げるのは「〜 Tool」という種類だけなので、SSH を実行するサブワークフローを別に作って「Call n8n Workflow Tool」で呼ぶ構造にしました。トリガー「When executed by Another Workflow」は「Execute Sub-workflow」カテゴリの中にあり、検索で見つけにくかったです
- Telegram の Chat ID が取れない。
getUpdatesが空で返ってきましたが、Bot にメッセージを送ってから数秒待つと入りました
Docker の起動から Telegram 通知まで 1 時間半、MCP で Claude Code から呼べるまで、さらに 1 時間ほどでした。n8n の UI はバージョンで変わるので、ノードの探し方で迷う時間が多かったです。
次にやること
- Ollama を同じ VPS に置いて、Anthropic API の代わりにローカルモデルで要約させる (準備中)
- Immich をセルフホストして、写真のバックアップ完了を n8n で通知する (準備中)
まとめ
- n8n はセルフホストなら無料・実行回数無制限。VPS 4GB で Claude Code と同居できる
portsは127.0.0.1に束縛し、公開はtailscale serveで。ufw で 5678 を開ける必要はないN8N_HOSTとWEBHOOK_URLに Tailscale の HTTPS 名を入れる- Claude は Anthropic ノードで挟む。「SSH で取って Claude に判断させて通知」が基本形。コンテナから VPS 自身への SSH は、鍵の形式 (RSA/PEM) と ufw (Docker のネットワーク許可) の 2 点に注意
- MCP Server Trigger で n8n を Claude Code の道具にできる。道具の中身は n8n の画面で組み替えられる
- 外部からの Webhook が要るときだけ
tailscale funnelでそのパスを出す。エディタは出さない