創刊準備号 · 2026年秋English · RSS
AgentKoji

PR一部の記事にはアフィリエイトリンクを含みます。経由して申し込まれると、当サイトに報酬が入ることがあります。評価は変えません。 アフィリエイト開示

AIエージェントをVPSで24時間動かす

systemdで常駐させるだけなら30分。難しいのは「止まっているのに緑」を見抜くこと。常駐エージェントを運用して分かった監視と安全の設計。

エージェントを常駐させること自体は、30分もあれば終わります。手間がかかるのはその先で、数週間たったころに「プロセスは生きているのに、何も処理していない」状態を見抜けるかどうかです。この記事では、最小の構成を作ったあと、編集部の常駐 Bot で実際に踏んだ罠と、いま使っている監視の設計を順に説明します。

先に結論

1. VPSを選ぶ

推論を API に任せるなら、CPU よりも「メモリ」「リージョン」「料金の払い方」のほうが効きます。2026年10月16日時点の、各社公式ページの表示です(税込・税抜は各社の表記のまま)。

サービス目安のプラン料金メモ
ConoHa VPS2GB / 3コア / 100GB SSD時間課金で月上限 2,033円。長期契約の割引あり東京リージョン、時間課金があるので検証しやすい
HostingerKVM 1(4GB / 1vCPU / 50GB NVMe)$6.49/月(24か月前払い)、更新後 $11.99/月更新後の料金で比べること
DigitalOceanBasic 2GB / 1vCPU / 50GB$12/月(秒課金、月の上限あり)作っては壊す検証に向く

PR:上の表のサービスには、当サイトが参加する(予定の)アフィリエイトプログラムのものがあります。選んだ基準は料金とリージョンだけです。

おすすめVPS(国内):東京リージョンで始めるなら、時間課金で試しやすい ConoHa VPS か、メモリ量で選べる XServer VPS が候補です。料金とプランは変わるので、契約前に公式ページで確認してください。

2. 最小の構成

ユーザーと SSH

sudo apt update && sudo apt -y upgrade
sudo adduser --disabled-password agent
sudo ufw allow OpenSSH && sudo ufw enable
# /etc/ssh/sshd_config: PasswordAuthentication no / PermitRootLogin no
sudo systemctl reload ssh

systemd で常駐させる

# /etc/systemd/system/agent.service
[Unit]
Description=AI agent
After=network-online.target
Wants=network-online.target

[Service]
User=agent
WorkingDirectory=/home/agent/app
EnvironmentFile=/home/agent/app/.env
ExecStart=/usr/bin/node dist/main.js
Restart=on-failure
RestartSec=5
WatchdogSec=120

[Install]
WantedBy=multi-user.target

.env は chmod 600 にして、Git には入れません。WatchdogSec は、アプリから sd_notify("WATCHDOG=1") を送っていないと意味がありません。後で説明する「生きているのに動いていない」状態への最初の備えです。

3. 「判断は LLM、実行はスクリプト」

編集部では、監視役のエージェントに10分ごとにログを読ませて、状況を診断させています。ただし、修復のコマンドを直接打たせることはしません。打てるのは、名前を指定した数本のスクリプトだけです。

各スクリプトの中身は同じ型です。

  1. 対象のファイルをバックアップする
  2. 変更を tmp に書き出す
  3. 検証する(構文チェック、起動テスト)
  4. mv で原子的に置き換える
  5. 失敗したら、バックアップから戻す

最初の版では、通知に使う Bot のトークンをシステムプロンプトに入れていました。いまは通知専用のスクリプトに分けてあり、LLM が知っているのは notify.sh という名前だけです。ログには外部から来た文字列が混ざるので、鍵と信頼できない入力を同じコンテキストに置かないようにしています。同じ理由で、無人の cron から LLM に本番への投稿をさせることもやめ、本番への書き込みは人が端末から起動しています。

本番を読ませても書かせない設定は「AIエージェントの権限設計」に書きました。

4. 緑なのに止まっている

運用を始めて一番時間を取られたのは、この種の障害でした。

5. 監視の4つの不変条件

最後に、監視の一番外側(日次チェック)が黙って止まっていて、2日間の空回りに誰も気づかなかったことがあります。それ以来、次の4つは崩さないことにしています。

  1. 監視は、監視対象と別のホストに置く。 同じ VPS に置くと、一緒に落ちます。
  2. 異常がなくても、毎日 OK を送る。 OK が届かないこと自体を、異常の合図にします。
  3. 判定と通知を分ける。 判定のコードが通知の失敗に巻き込まれないようにします。
  4. 「意図的に止めている」状態を、正常とも故障とも別に扱う。 ok / error のほかに inert というラベルを用意します。

アラートの経路は、本番が健全なときには自然には通りません。そこで ?simulate=fail のようなフラグで、強制的に失敗を流せるようにしています。

# 別ホストのcronから。OKが来なければ、それ自体が通知になる
curl -fsS --config - <<< "url = \"$HEALTH_URL?simulate=${SIMULATE:-0}\""

4つの条件の先で踏んだ落とし穴は「常駐Bot監視の落とし穴」にまとめています。

6. 秘密情報で踏んだこと

権限の deny を書いても、grep -r やスクリプト経由で .env が読まれる経路は残ります。ダミーの鍵で確かめた漏れ道と塞ぎ方は「Claude Codeに秘密を渡さない」にまとめました。

7. 「止めたはず」を確かめる

止めたつもりの自動実行が、何か月も動き続けていたことがあります。そのときにやっていたのは、出力を見えなくすることと、たまったファイルを消すことだけで、生成元は生きていました。いまは停止を宣言する前に、次の4つを実際に確認しています。

systemctl list-timers --all
crontab -l; sudo ls /etc/cron.d
systemctl list-unit-files --state=enabled | grep -v '^systemd'
find /var/log /home/agent -newermt '-1 hour' -type f   # 出力がまだ増えていないか

止めたつもり、試したつもりの処理が本番で動いていた、という静かな事故は「デプロイとマイグレーションの事故集」にまとめました。

チェックリスト

一部の記事にはアフィリエイトリンクを含みます。経由して申し込まれると、当サイトに報酬が入ることがあります。評価は変えません。 アフィリエイト開示