case_627 SaaS・IT

【2026年最新】Claude CodeをVPSで動かす手順と7つの落とし穴

【2026年最新】Claude CodeをVPSで動かす手順と7つの落とし穴

Claude CodeをVPSで常時運用する実務ガイド。インストール・認証トークン管理・cron自動化の環境変数とロケール問題・タイムアウト設計・コスト管理まで、実運用で踏んだ7つの落とし穴と対策を解説。

結論:Claude CodeはVPS上でも公式ドキュメントどおりにインストール・認証すれば動きますが、実運用で壊れるのはインストールではなく「cron起動時の環境変数」「認証トークンの失効」「タイムアウトと失敗検知の未設計」の3点です。対話モードで動いたコマンドをそのままcrontabに貼ると、PATH・ロケール・認証の3つの前提が崩れて静かに止まります。

  • 要点1:公式の動作要件はUbuntu 20.04以降・Debian 10以降などのLinuxと4GB以上のRAM(code.claude.com「Advanced setup」2026年8月4日参照)。インストール自体は1行で終わり、VPS固有の追加手順はほぼない
  • 要点2:ヘッドレス運用の認証は「claude setup-tokenで発行した長期OAuthトークンをCLAUDE_CODE_OAUTH_TOKENに渡す」か「ANTHROPIC_API_KEYで従量課金APIを使う」の2択。トークンは失効しうる前提で、失効を検知する側の設計が必要になる
  • 要点3:cron自動化の失敗の多くはClaude Code本体ではなく周辺の設計——PATH未設定・ロケール警告の出力混入・exit codeを見ないラッパー——で起きる。本記事では筆者が自社VPSの記事生成・監視パイプラインで実際に踏んだ7つの落とし穴を対策つきで示す

対象読者:Claude Codeを常時稼働サーバーで動かしたい開発者・SRE・自動化パイプラインを設計するPM。

今日やること:VPSに専用ユーザーを作り、インストール後にclaude -p "pwd を表示して"が非対話で通るところまで確認する。

ある朝、VPSのcronで毎日動くはずのジョブが止まっていました。ログを見ると、ラッパースクリプトは「exit code 1」だけを記録していて、肝心のエラー本文を握りつぶしている。最初は「使用量の上限に当たったのだろう」と誤診して2回リトライを重ね、実ログを掘ってようやく認証トークンの失効(401)が原因だと分かりました。復旧作業そのものは数分。原因特定に溶けた時間のほうがずっと長かったんです。

本記事は、この種の「VPSでClaude Codeを動かすときにだけ起きる問題」を先回りで潰すための実務ガイドです。以下の内容はすべて、筆者が自社で運用しているVPS(コンテンツ生成・監視ジョブを日次で実行)での実体験にもとづいています。

検証環境:Ubuntu 22.04 LTS(海外VPS・RAM 4GB)、Claude Code v2.1系、ネイティブインストール、cronによる日次実行。コマンド・フラグ・環境変数はすべて2026年8月4日時点の公式ドキュメント(code.claude.com)で実在を確認しています。

Claude CodeをVPSで動かすと何ができるのか

ローカルPCで使うClaude Codeとの違いは「常時稼働」と「無人実行」の2点に尽きます。VPSに載せると、次のような使い方が現実的になります。

  1. cronによる定時ジョブ — ログの要約、日次レポート生成、データ突合の一次分類など、毎日決まった時刻に走らせる処理
  2. チャットボットのバックエンド — Slack BotやLINE Botの応答生成をVPS上のClaude Codeに任せる構成。Bot開発自体の手順はClaude CodeでSlack botを開発する実践ガイドLINE Bot開発|Webhook実装で扱っています
  3. PCを閉じても続く長時間タスク — 大量ファイルの変換・整理など、ローカルだとスリープで中断される処理
  4. チーム共用の実行環境 — 各メンバーのPC環境差に依存しない実行基盤(ただし認証は後述のとおり個人単位が原則)

なお「Claude Codeにcronジョブやバッチ処理を作らせる」話は別記事のバッチ処理・定期実行をClaude Codeで自動化する実践ガイドで解説しています。本記事はその逆で、Claude Code自体をcronから起動して運用する側の話です。

先に全体像:実運用で踏んだ7つの落とし穴

本記事で扱う落とし穴を先にまとめます。それぞれ該当セクションで対策まで解説します。

# 落とし穴 症状
1 cronのPATH・環境変数が対話シェルと違う 手動では動くのにcronだと「command not found」
2 ロケール警告が出力に混入する 下流のパース・比較処理が全件誤判定
3 OAuthトークンの失効 ある日突然、全自動化ジョブが401で停止
4 認証情報の平文保存・権限過大 漏洩時にアカウント全体が危険に
5 タイムアウト未設計 ハングしたジョブが翌日のジョブと多重起動
6 exit codeを見ない失敗の握りつぶし 止まっているのに「正常」に見える沈黙死
7 コスト・使用量上限の見落とし 月末にジョブが失敗し始めて原因が分からない

VPSの選び方と最低要件

公式ドキュメント「Advanced setup」(2026年8月4日参照)に記載されている動作要件は次のとおりです。

  • OS:Ubuntu 20.04以降 / Debian 10以降 / Alpine Linux 3.19以降(ほかmacOS・Windowsにも対応)
  • ハードウェア:RAM 4GB以上、x64またはARM64
  • ネットワーク:インターネット接続必須
  • 利用地域:Anthropicのサポート対象国であること

実務目安として、月1,000円前後で借りられる2vCPU・RAM 4GBクラスの標準的なVPSプランで日次ジョブは問題なく回っています(筆者環境での経験値であり、ワークロードによって必要スペックは変わります)。メモリ2GBのプランは要件を満たさないので避けてください。Hetzner・さくら・ConoHaなどプロバイダーの違いよりも、RAM 4GBの確保とリージョンの通信安定性のほうが効いてきます。海外リージョンを選ぶ場合は、上記の「サポート対象国」の一覧と利用規約を事前に確認しておくと安心です。

セットアップ手順:専用ユーザー作成からインストールまで

VPSでの初期構築は4ステップです。ポイントは「rootで動かさない」こと。後述のセキュリティ設計にも直結します。

# 1. 専用ユーザーを作成(rootでの運用は避ける)
adduser claude-ops
su - claude-ops

# 2. ネイティブインストーラで導入(公式推奨・macOS/Linux/WSL共通)
curl -fsSL https://claude.ai/install.sh | bash

# 3. バージョン確認
claude --version

# 4. 動作確認(初回は認証が必要)
claude -p "pwd の結果を1行で答えて"

ネイティブインストールはNode.jsのセットアップが不要で、バックグラウンドで自動更新されます(公式ドキュメント記載)。DebianやAlpineではapt・apkでの導入経路も用意されています。逆に言うと、自動更新によってバージョンが勝手に上がるため、「昨日と同じバージョンで動いている保証はない」前提でログにバージョンを残しておくと、挙動が変わったときの切り分けが楽になります。

認証設計:VPS運用の心臓部

ここがVPS運用で一番つまずくところです。ローカルPCなら/loginでブラウザ認証すれば終わりですが、ヘッドレスなVPSでは選択肢が実質2つになります(公式「Authentication」「Environment variables」2026年8月4日参照)。

方式 使うもの 向いている用途 注意点
サブスク認証(長期トークン) claude setup-tokenで発行しCLAUDE_CODE_OAUTH_TOKENに設定 Pro/Maxプラン契約者の自動化 サブスクリプション契約が必要。トークンは失効しうる
API従量課金 ANTHROPIC_API_KEY(Claude Consoleで発行) CI/CD・コストを従量で管理したい場合 設定されていると-p実行時は常にAPIキーが優先される

長期トークンの発行と設定はこう書きます。

# ローカルPCなど、ブラウザが使える環境で実行(要サブスクリプション)
claude setup-token
# → 長期OAuthトークンが端末に表示される(自動保存はされない)

# VPS側:600権限のファイルに保存して読み込む
install -m 600 /dev/null ~/.config/claude-ops/token.env
echo 'export CLAUDE_CODE_OAUTH_TOKEN=(発行されたトークン)' >> ~/.config/claude-ops/token.env
source ~/.config/claude-ops/token.env
claude -p "認証確認。OK とだけ答えて"

落とし穴3(トークン失効)は、まさにこの構成で起きました。冒頭のエピソードのとおり、ある朝すべての自動化ジョブが止まり、原因は長期トークンの失効。別マシンでの再ログインや認証情報の更新をきっかけに、サーバー側に置いたトークンだけが古くなるパターンです。対策は2つ。①失効を「検知」する専用の軽量ジョブを分けること(後述の監視設計)、②復旧手順を1行で書き残しておくこと。筆者は「ローカルで再発行→scpでVPSに転送→ジョブ再実行」の手順をREADMEに固定してから、復旧が数分で終わるようになりました。

落とし穴4(平文保存・権限過大)への対策は最低限これだけは守ってください。

  • トークンファイルはchmod 600・専用ユーザーの所有にする(他ユーザーから読めない状態)
  • Gitリポジトリ・crontab本体・シェル履歴にトークンを直書きしない
  • チームでの共用サーバーでも、認証は個人単位を原則にする。認証情報の使い回しは漏洩時の影響範囲を広げるだけでなく、規約上のリスクにもなるため、最新の利用規約を確認して運用を決めてください

cron自動化:非対話モードと環境変数の罠

Claude Codeの非対話実行は-p--print)フラグです。スクリプトやCIでは--bareを足すと、hooks・スキル・MCP・CLAUDE.mdなどの自動読み込みを省略して起動が速くなり、どのマシンでも同じ結果になります(公式「Run Claude Code programmatically」参照。ただし--bareはOAuthを読まないためANTHROPIC_API_KEYが必要です)。

# ワンショット実行の基本形
claude -p "昨日のエラーログを要約して。仮定した点は必ず『仮定』と明記してください"

# パイプで流し込む(stdinは10MBまで。超える場合はファイルパスで渡す)
cat /var/log/app/error.log | claude -p "このログから障害の根本原因を3行で。不明な点は不明と書いてください" > /tmp/summary.txt

# ツールを事前許可して無人実行
claude -p "reports/ 配下のCSVを検品して異常行を列挙して" --allowedTools "Read,Bash"

そしてcronです。対話シェルで動いたコマンドをそのままcrontabに貼ると、高確率で動きません。cronは最小限の環境変数しか持たないため、PATHにインストール先が入っておらず「command not found」になる——これが落とし穴1です。実際に動いているcrontabの形はこうなります。

# crontab -e (claude-opsユーザーで)
PATH=/home/claude-ops/.local/bin:/usr/local/bin:/usr/bin:/bin
LANG=ja_JP.UTF-8
LC_ALL=ja_JP.UTF-8

# 毎朝7時:日次レポート生成(flockで二重起動防止・stderrは分離)
0 7 * * * flock -n /tmp/daily-report.lock /home/claude-ops/jobs/daily_report.sh >> /home/claude-ops/logs/daily_report.log 2>> /home/claude-ops/logs/daily_report.err

ポイントは4つあります。

  • PATHを明示するwhich claudeで実体の場所を確認し、crontab冒頭のPATHに含める。スクリプト内でフルパス指定でもよい
  • ロケールを明示する落とし穴2の対策。日本語ロケールが未生成のVPSだと、シェル起動のたびに「setlocale: LC_ALL: cannot change locale」の警告がstderrに出ます。筆者はSSH経由の取得処理で2>&1とまとめて受けていたせいで、この警告が全出力の先頭に混入し、下流の本文比較処理が全ペア誤判定になったことがあります。locale-gen ja_JP.UTF-8で生成するか、stdoutとstderrを必ず分離してください
  • flockで二重起動を防ぐ:前日のジョブがハングしたまま翌日のジョブが重なると、負荷もコストも二重になります
  • 環境変数の前置きはコマンドの直前に:ラッパースクリプト経由で呼ぶ場合、VAR=1 wrapper.sh -- commandのように書くと、変数を置く位置を1箇所間違えるだけでジョブ全体が壊れます。筆者はこの書式ミスで監視ラッパーごと止めた経験があり、以後「環境変数はラッパーの前、コマンドは–の後」を機械的に統一しています

タイムアウト・リトライ・監視の設計

Claude Codeは正常終了でexit code 0、失敗時は非ゼロを返すため、シェルスクリプトで素直に分岐できます(公式ドキュメント記載)。ここを活かさない運用が落とし穴5・6を生みます。

#!/bin/bash
# daily_report.sh — タイムアウトとリトライを備えた実行ラッパー
set -u
LOG=/home/claude-ops/logs/daily_report.$(date +%Y%m%d).log

run_claude() {
  timeout 900 claude -p "$1" --allowedTools "Read,Bash" >> "$LOG" 2>> "${LOG%.log}.err"
}

PROMPT="data/sales.csv から日次サマリを生成して reports/ に保存して。数字は元データの行を根拠として添えてください"

if ! run_claude "$PROMPT"; then
  rc=$?
  echo "[WARN] 1回目失敗 rc=$rc $(date)" >> "$LOG"
  sleep 60
  if ! run_claude "$PROMPT"; then
    rc=$?
    echo "[ERROR] 2回目も失敗 rc=$rc" >> "$LOG"
    tail -20 "${LOG%.log}.err" | your-notify-command   # Slack等への通知に置き換え
    exit "$rc"
  fi
fi

設計の要点は次のとおりです。

  • 外側からtimeoutをかけるtimeout 900のようにジョブ全体の上限を外側で決める。Claude Code内部のBashツールにも既定タイムアウトがあり(BASH_DEFAULT_TIMEOUT_MS既定120000ミリ秒=2分、上限はBASH_MAX_TIMEOUT_MS既定600000ミリ秒=10分。公式「Environment variables」参照)、内側と外側の二段構えにする
  • リトライは冪等な処理だけ:「レポートを生成して上書き保存」は再実行しても安全ですが、「外部に投稿する」処理を無条件リトライすると二重投稿します。筆者は公開検証の誤判定から再投稿ループに入りかけたことがあり、以後「外部副作用のある工程はリトライ対象から外す」を原則にしています
  • エラー本文を必ず残す:exit codeだけ記録して標準エラーを捨てるラッパーは、トークン失効(401)も上限到達も全部「rc=1」に見えます。冒頭の誤診はこれが原因でした。stderrをファイルに残し、通知には末尾数行を含めてください
  • 「沈黙=正常」にしない:cronは失敗しても何も言いません。成功時にもタイムスタンプを1行書き、監視側は「最終成功時刻が24時間より古ければ警報」という向きで設計すると、ジョブが止まったこと自体を検知できます

コスト管理:見えない請求を見える化する

落とし穴7はコストです。無人実行は「使いすぎに気づく人間の目」がないため、計測を仕組みに入れる必要があります。

# --output-format json で実行すると、応答にコスト情報が含まれる
claude -p "README.md を3行で要約して" --output-format json | \
  python3 -c "import json,sys; d=json.load(sys.stdin); print('cost_usd:', d.get('total_cost_usd'))"

公式ドキュメントのとおり、--output-format jsonのペイロードにはtotal_cost_usdとモデル別の内訳が含まれ、呼び出しごとの支出をログに積めます。運用上の使い分けはこう整理できます。

  • サブスク認証(Pro/Max):定額ですが使用量の上限があり、自動化ジョブが上限に当たるとその時間帯は失敗します。人間の対話利用と自動化ジョブが同じアカウントを使う場合、ピーク時間をずらすなどの配慮が必要です。上限の詳細は変わりうるため公式のusage関連ページで確認してください
  • API従量課金:呼び出し単位で青天井になりうる代わりに、total_cost_usdの集計とConsole側の上限設定で統制しやすい。日次で「昨日の合計コスト」を通知に含めるだけでも、暴走の早期発見に効きます

セキュリティ:VPSならではの追加リスク

VPSは常時インターネットに露出しているため、ローカルPCより一段厳しい前提で設計します。

  • rootで動かさない:セットアップ手順で専用ユーザーを作ったのはこのためです。Claude Codeに権限を渡しすぎると、プロンプト1つのミスがシステム全体に波及します
  • --dangerously-skip-permissionsの扱い:確認プロンプトを全部スキップするこのフラグは、無人実行では魅力的に見えます。ただし名前のとおり危険側のフラグです。使う場合は「専用ユーザー・書き込み先を限定したディレクトリ・外部送信の手段を持たないジョブ」に閉じ込め、まずは--allowedTools "Read,Bash"のように必要なツールだけを許可する設計から始めてください
  • 秘密情報をプロンプトに流さない:ログファイルにはプロンプトと出力が残ります。顧客情報やAPIキーを含むデータを処理させる場合は、ログの保存先・保持期間・アクセス権も一緒に設計し、所属組織の規程に従ってください
  • SSH自体の防御:公開鍵認証のみ・パスワード認証無効・fail2ban導入はVPS運用の基本です。Claude Code以前にVPSが乗っ取られたら意味がありません

【要注意】よくある失敗パターンと回避策

失敗1:対話モードで動作確認して、そのままcronに載せる

❌ SSHログイン中のシェルで動いたコマンドをcrontabへコピペ
env -i /bin/bash -c 'あなたのコマンド'のように環境変数を空にした状態で通ることを確認してからcronに載せる

なぜ重要か:cronの実行環境は対話シェルとは別物です。PATH・ロケール・認証情報の3点は「cronの環境で」検証する必要があります。

失敗2:トークンをcrontabやスクリプトに直書きする

CLAUDE_CODE_OAUTH_TOKEN=sk-... claude -p ...をcrontabに書く
⭕ 600権限のenvファイルに分離し、スクリプト内でsourceする。Git管理からも除外する

なぜ重要か:crontabはバックアップやリポジトリ経由で意外と広く共有されます。認証情報の置き場所は最初に分離しておくのが一番安上がりです。

失敗3:リトライを「とりあえず3回」で入れる

❌ 失敗の種類を見ずに全ジョブへ無条件リトライ
⭕ 認証エラー(再実行しても直らない)と一時エラーを分け、外部副作用のある工程はリトライから外す

なぜ重要か:トークン失効に3回リトライしても3回失敗するだけです。逆に投稿系ジョブのリトライは二重実行の事故につながります。

失敗4:動いているうちはログを見ない

❌ 「エラー通知が来ていない=正常」と考える
⭕ 週1回はstderrログとコスト集計を目視する。「最終成功時刻」ベースの監視を仕込む

なぜ重要か:通知の仕組み自体が壊れると、失敗は誰にも届きません。筆者は監視スクリプトのトークン失効で「最後の砦が沈黙死」していた経験があり、監視の監視(最終成功時刻の確認)だけは人間側に残しています。

よくある質問

Q. Claude Codeを動かすVPSのスペックはどれくらい必要ですか?

公式の動作要件はRAM 4GB以上・x64またはARM64・Ubuntu 20.04以降などです(code.claude.com「Advanced setup」2026年8月4日参照)。筆者は2vCPU・RAM 4GBの標準プランで日次ジョブを運用しています。重い並列処理をさせる場合はメモリを増やす方向で検討してください。

Q. Claude CodeでMCPサーバーに接続するにはどうすればいいですか?

claude mcpコマンドでMCPサーバーを設定できます。OAuth認証が必要なMCPサーバーは、v2.1.186以降ならclaude mcp login サーバー名で認証でき、SSH接続中のVPSのようにブラウザを開けない環境では--no-browserを付けると認可URLが表示されるので、手元のブラウザで開いてリダイレクトURLを貼り戻します(公式CLIリファレンス参照)。

Q. VPSで動かすとアカウント停止(BAN)になりませんか?

2026年8月時点で、公式ドキュメント上に「VPSやサーバーでの利用自体を禁止する」という記載は確認できていません。実際、公式ドキュメントはCI/CDやスクリプトからの非対話実行を正式にサポートしています。ただし認証情報を複数人で使い回す運用は規約上のリスクがあるため避け、最新の利用規約とUsage Policyを確認したうえで運用してください。

Q. Windows Serverでも動きますか?

公式の対応OSにWindows 10 1809以降・Windows Server 2019以降が含まれています。PowerShell用のインストールコマンドが用意されているほか、WSL 2経由でLinux版を使う構成も公式に案内されています。

Q. cronで複数のジョブを同時に走らせても大丈夫ですか?

技術的には可能ですが、メモリと使用量上限を同時に消費します。RAM 4GBの環境では同時実行は2本程度までに抑え、flockでジョブごとの二重起動を防ぎつつ、時間帯をずらすのが安全です(筆者環境での運用値です)。

Q. 実行ログはどこに残せばいいですか?

Claude Code自体の出力はstdout/stderrに出るので、cron側でファイルにリダイレクトして残すのが基本です。本文で示したように、stdoutとstderrは必ず別ファイルに分離してください。日付入りファイル名にして、logrotateなどで保持期間を決めておくとディスク枯渇も防げます。

まとめ:今日から始める3つのアクション

  1. 今日やること:VPSに専用ユーザーを作り、claude -p "pwd を表示して"が非対話で通ることを確認する
  2. 今週中:一番単純な日次ジョブを1本、flock・timeout・stderr分離つきのラッパーでcronに載せる
  3. 今月中:「最終成功時刻」ベースの監視と、トークン失効時の復旧手順1行メモを整備する

VPS運用は「動かすまで」より「止まったことに気づける設計」が本体です。この記事の7つの落とし穴は、裏を返せばチェックリストとしてそのまま使えます。

Claude Codeの導入設計や自動化パイプラインの構築を体系的に進めたい方は、Uravationのお問い合わせフォームからお気軽にご相談ください。

次回予告:VPSに載せたClaude Codeを複数ジョブで安全に共存させる、キュー設計と優先度制御の実務を扱う予定です。

関連事例:WordPress 301統合slugの再公開をClaude Codeで機械遮断——本記事で扱ったcron自動投稿が301統合済みslugを再生産した「ゾンビ公開」事故を、wp_insert_post_dataフックの公開ガードで遮断した実装記録です。

参考・出典


著者:佐藤傑(さとう・すぐる)
株式会社Uravation代表取締役。X(@SuguruKun_ai)フォロワー約10万人。100社以上の企業向けAI研修・導入支援を展開。著書『AIエージェント仕事術』(SBクリエイティブ)。SoftBank IT連載7回執筆。自社ではVPS上のClaude Codeによるコンテンツ生成・監視パイプラインを日次運用している。

関連アップデート(2026年8月追記):Claude Codeには2026年8月6日、公式のself-hosted environments(claude self-hosted-runner)がTeam/Enterpriseプラン向けに追加されました。本記事で解説したVPSへの手動セットアップとは別に、Anthropicの制御プレーンがキューイングを担う公式のセルフホスト機能もあります。違いはClaude Codeセルフホスト実行ガイド|4ステップで解説しています。

Next Step

この事例を、自社の業務に置き換える。

対象業務、利用データ、評価基準、社内展開の順番まで整理すると、AI開発ツール導入の失敗を減らせます。

導入を相談する

チームで学ぶなら: Claude Code 法人研修(2日間ハンズオン) / 1人で習得するなら: 個別指導(週1マンツーマン)