sysadmin向けClaudeの使い方と安全なサーバー作業
Claudeでできるサーバー作業を6つ紹介します。失敗したunitのログ解析、systemd unit作成、nginxやCompose設定のレビュー方法と、絶対に貼り付けてはいけない秘密情報を解説します。
sysadmin 向け Claude: 助言を先に、実行は後に
sysadmin 向けの Claude は、レビュアーとして使うと最も効果を発揮します。ログの抜粋、設定ファイル、見慣れないコマンド、エラー文字列を貼り付けると、変更を加える前に確認できる説明が返ります。誤った回答でも、実行するまでは何も失いません。そのため、モデルを助言の側に留めることが安全性の基本になります。
レンタル Linux VPS(virtual private server)では、毎週 6 種類の作業が発生します。以下では、それぞれについて有効なプロンプトのパターン、回答を検証するコマンド、想定すべき失敗の種類を示します。どの作業でも、モデルにサーバーへのアクセス権を与える必要はありません。
本番サーバーでは、実行する順序が重要です。説明を読み、自分で確認コマンドを実行してから判断してください。検証用の VM であれば、自律実行でも問題ありません。顧客向けサービスを提供するサーバーでは、モデルが推測している実際の状態を確認できないため、レビューを優先します。
貼り付けてはならないもの
プロンプトに入力した内容はすべてサーバーの外部に送信されます。次の4種類はサーバー内に残してください。
- 秘密鍵:
~/.ssh/id_ed25519、/etc/ssh/ssh_host_*_key、および/etc/letsencrypt/live/配下の TLS (transport layer security) 鍵。 - 認証情報ファイル:
.env、~/.aws/credentials、/root/.docker/config.json、ならびに任意のファイルやログ行に含まれるデータベースのパスワード。 - アカウントデータ:
/etc/shadowと/etc/gshadow。sysadmin の質問に回答するために、パスワードハッシュが必要になることはありません。 - ユーザーに属する情報: メールアドレス、注文データ、セッション Cookie や PII (personally identifiable information) を含むリクエストログなど。
公開鍵は貼り付けても安全です。秘密鍵は貼り付けてはなりません。2つのファイルは一見すると似ているため、コピーする前に先頭行を確認してください。先頭行に BEGIN OPENSSH PRIVATE KEY が含まれるファイルは、プロンプトに入力してはいけません。SSH 鍵マテリアルを正しく管理するには、それだけで10分をかける価値があります。
200行の中から1つのトークンを見つけられると考えず、貼り付ける前に伏せ字にしてください。
sudo journalctl -u myapp -n 200 --no-pager | sed -E 's/(token|secret|password|api[_-]?key)[=:][^[:space:]]+/\1=REDACTED/gI'Docker には固有の落とし穴が1つあります。docker compose config は、出力時に .env の値を展開するため、ディスク上のファイル自体に秘密情報が含まれていなくても、その出力は秘密情報になります。値を検証するだけで何も出力しない docker compose config -q を使用してください。エージェントに何を見せてよいかに関する広範な方針については、AI エージェントから秘密情報を除外するで環境側の対策を説明しています。
ジョブ 1: このサービスはなぜ失敗したのか
答えが含まれている次の2つのコマンドから始めます。
systemctl status myapp.service --no-pager
sudo journalctl -u myapp.service -b -n 100 --no-pager -o short-isoモデルが推測できないコンテキストも添えて、2つとも貼り付けます。ディストリビューションとバージョン、最後に変更した内容、以前に動作していたかどうか、問題が発生してからの経過時間を含めてください。まず原因の仕組みを尋ねます。
Ubuntu 24.04 です。myapp.serviceは、1時間前に unit を編集するまでは正常に動作していました。systemctl statusと、journal の最後の100行を貼ります。最初の実際のエラーはどの行で、何を意味しますか。まだ修正方法は提示しないでください。
このプロンプトでは、「まだ修正方法は提示しないでください」という指定が重要な役割を果たします。ログでは、最初の障害によって発生した再試行が続くため、最初の失敗が埋もれます。修正方法を尋ねられたモデルは、目に入った最後の行を説明しがちです。重要な行は通常、ノイズの20行ほど上にあります。
得られるのは、Main PID: 1841 (code=exited, status=203/EXEC) のような行です。終了ステータス 203/EXEC は、カーネルが ExecStart に指定されたファイルを実行できなかったことを示します。パスが存在しないか、ファイルは存在するものの実行可能ではありません。インストールされていないインタープリターを指定する #! の行でも、同じステータスになります。これらはすべて、ls -l と head -1 で確認できます。
失敗パターン: 原因の捏造です。貼り付ける情報が少なすぎると、モデルは「ポートがすでに使用中です」のような一般的な原因で空白を補います。対処方法は、次の質問を返すことです。「私が提示した内容のどの行が、その判断を裏付けていますか」。テキスト内で指し示せない原因は推測です。
systemd unit または cron エントリを作成する
unit ファイルに必要な情報を指定します。正確なコマンド、実行ユーザー、作業ディレクトリ、ネットワークを待つ必要があるかどうか、終了ステータスが non-zero の場合の動作を明記します。その後、何が返るかを確認してから有効化します。
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl start myapp.service
systemctl status myapp.service --no-pagersystemd-analyze verify は systemd と同じ方法でファイルを解析するため、人が見落としやすい問題を検出できます。ディレクティブのスペルミスがあると /etc/systemd/system/myapp.service:7: Unknown key name 'Enviroment' in section 'Service', ignoring. と表示されます。バイナリがない場合は Command /usr/local/bin/myapp is not executable: No such file or directory と表示されます。どちらも daemon-reload 中はエラーにならないため、unit は正常に読み込まれても、実行時に失敗することがあります。
作成時のミスで、特に多いものが 2 つあります。1 つ目は After=network.target です。これはネットワークスタックが設定済みであることだけを示し、アドレスがすでに存在することは示しません。特定の IP に bind するサービスは、起動時に bind: Cannot assign requested address で失敗します。修正には Wants=network-online.target と After=network-online.target を使用します。2 つ目は、daemonize するプログラムに Type=simple を指定することです。systemd は最初のプロセスをサービスとして扱います。その親プロセスがすぐに終了すると、unit は dead とマークされます。一方で、実際のプロセスは管理されないまま実行を続けます。
スケジュールは、内容を読むのではなく検証します。
systemd-analyze calendar 'Mon *-*-* 04:00:00'このコマンドは正規化された形式と、式が次に実行される時刻を表示します。式の意味について意見が分かれても、これで確認できます。timer と crontab のどちらを使用するか迷う場合は、VPS での systemd services と timers で違いを確認できます。
cron には、質問しない限りどのモデルも警告しない落とし穴があります。cron は最小限の環境でジョブを実行するため、PATH はおおむね /usr/bin:/bin となり、shell の profile は読み込まれません。ターミナルに貼り付けると動作するジョブが、cron では /bin/sh: 1: docker: not found で失敗することがあります。そのバイナリが /usr/local/bin にあるためです。crontab では絶対パスを使用します。
ジョブ 3: nginx または Compose ファイルを本番稼働前に確認する
このジョブが最も高い効果を得られます。ファイルを貼り付け、想定する動作を説明し、実際の動作を行単位で確認するよう依頼します。
この vhost はexample.comを HTTPS で提供し、/apiをポート 8080 のローカルサービスへプロキシする想定です。内容を読み上げ、説明と一致しない点を挙げてください。
次に、構文を確認できるツールを実行します。
sudo nginx -t
docker compose config -qnginx -t は nginx: configuration file /etc/nginx/nginx.conf test is successful を出力します。該当する場合は、nginx: [emerg] unknown directive "proxy_pas" in /etc/nginx/conf.d/app.conf:12 のようにファイル名と行番号も示します。ファイルの解析に成功した場合、docker compose config -q は何も出力しません。インデントを誤ると、yaml: line 7: did not find expected key のような簡潔なエラーを出力します。
どちらのツールも意図は確認しません。nginx -t を通過した設定でも、誤ったポートへプロキシしたり、127.0.0.1 のつもりが 0.0.0.0 で待ち受けたりすることがあります。この差分を埋めるのがモデルの役割ですが、同時に失敗しやすい部分でもあります。1 つのディレクティブの修正を依頼すると、ファイル全体を書き換え、2 つのディレクティブを気付かないまま削除することがよくあります。変更した行と、それぞれの変更理由だけを提示するよう依頼し、手動で編集してください。
実際に公開したものを確認します。
sudo ss -tulpnsudo を付けない場合、待ち受けソケットは表示されますが、それを所有するプロセスは表示されません。表示結果が想定外なら、ポートの仕組みと Linux によるバインド方法のほうが短く読めます。
ジョブ 4: 不慣れなコマンドは実行前に説明させる
コマンドを貼り付け、次の4点を質問します。各フラグは何をするのか、何を書き込むのか、何を削除するのか、2回実行するとどうなるのかです。最後の質問によって、ほかの質問より多くの被害を防げます。
find /var/log -name '*.gz' -mtime +7 -deleteを例にします。適切な回答では、-mtime +7が24時間単位の期間全体を数えて端数を切り捨てるため、7日ではなく少なくとも8日前のファイルに一致することを説明します。また、findは式を左から右へ評価するため、-deleteを-nameの前に移動すると、開始パス以下のすべてが削除されることも説明します。この点はfindの man ページに警告として記載されており、これによって/var/logを失った人もいます。
rsync -a --delete /srv/app/ /backup/app/も同様です。source の末尾にあるスラッシュは「このディレクトリの内容」を意味します。これを外すと/backup/app/app/になります。--deleteを追加すると、source に存在しない destination 内の項目がすべて削除されます。これはミラーリングには正しい動作ですが、source のパスが間違っていると大きな被害になります。
モデルではなくツールで確認します。
rsync -a --delete --dry-run /srv/app/ /backup/app/ | head -20
find /var/log -name '*.gz' -mtime +7-deleteを付けずにfindを実行すると、削除せずに一覧を取得できます。
失敗例: フラグの捏造です。モデルは30年分のドキュメントがあるツールについては信頼できますが、ベンダーの CLI(コマンドラインインターフェース)や新しいサブコマンドについては信頼性が大幅に下がります。実在しないフラグでも、自然で正しいように見える形で生成することがあります。--helpを使えば、1秒で確認できます。引用も弱点になりやすいため、コマンドが$(...)式を含む場合は、説明を信頼するのではなく、実行前にコマンド置換がどのように展開されるかを説明した解説を読んでください。
ジョブ 5: shell の履歴を runbook に変える
何かを動作させるまでに、2 時間かかりました。その知識は端末のスクロールバックに残っているだけで、来月には失われます。
history 200 > /tmp/session.txtそのファイルを読み、パスワード、token、顧客識別子を含む行をすべて削除してから、どこかへ保存してください。Linux ホストで Secret を見つける場所として、shell の履歴は非常に信頼できます。誰でも少なくとも 1 回は Secret をコマンドに直接入力するためです。HISTCONTROL=ignorespace を ~/.bashrc に設定すると、先頭に空白を付けて入力したコマンドは履歴に一切書き込まれません。
実用的な runbook を作成する prompt では、手順だけでなく確認方法も求めます。
これは、まっさらな Debian 13 のホストに動作する Postgres をインストールした shell セッションです。番号付きの runbook としてまとめてください。各手順は 1 コマンドにしてください。各手順の後に、成功したことを証明するコマンドを示し、正常な出力がどのように見えるか説明してください。私の特定のホストに依存した手順には印を付けてください。
失敗パターンは、整いすぎた説明です。あなたのセッションには、修正するまで 2 回間違えた手順がありました。transcript からその手順を省くと説明が読みやすくなるため、model はその手順を滑らかに消してしまいます。runbook と履歴を比較し、修正内容を戻してください。また、model はもっともらしい確認コマンドを作り出すことがあります。ファイルを保存する前に、記載された確認コマンドをすべて実行してください。runbook が初回起動を扱う場合は、新しい VPS の最初の 10 分 と照らし合わせてください。すでに解決した問題を、より悪い手順として記録しないためです。
ジョブ 6: エラーメッセージを修正方法に変える
正確なエラー文字列、そのエラーを出力したコマンド、エラーが表示される前に変更したことを 1 つ、そのまま貼り付けます。原因を可能性の高い順に並べ、各原因を区別できる確認コマンドを 1 つずつ求めます。これにより、回答を検証可能な形にできます。
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)。可能性の高い原因を順位付けし、各原因を確認または除外できるコマンドを 1 つずつ示してください。
このエラーの仕組みは明確です。別のプロセスがすでに port 80 を保持しており、sudo ss -tulpn | grep ':80 ' がそのプロセスを特定します。失敗した reload の後に 2 つ目の nginx master が残っている場合や、Apache が依存関係として組み込まれ、独自の package によって起動された場合によく発生します。
失敗パターンは、原因を隠すことで機能する修正です。chmod 777、--privileged、SELinux の無効化、サービスの root での実行は、いずれもエラーを消します。モデルが狭い権限で失敗した理由を説明するまでは、権限範囲を広げる修正を拒否します。その説明が実際の回答です。回避策では、エラーが表示されなくなるだけです。
確実に誤る点
- 実際のサーバーを確認できません。回答は貼り付けられた内容だけを基に生成され、抜粋が短すぎる場合でも、そのことを伝えません。
- バージョンによる差異を正確に扱えません。パッケージ名やデフォルトのフラグはディストリビューションやリリースによって変わりますが、モデルはそれらすべてを平均した回答を生成します。
- 誤っていても流暢です。架空の仕組みでも、正しい仕組みとまったく同じように読めます。そのため、上記の各原因には、それを検証するコマンドが付いています。
- 長いセッションでは話の流れを失います。2 時間の会話の冒頭に出た事実が、終盤の回答に反映されなくなります。
最後の問題はモデル自体の問題というより、実際の運用上の問題です。長い Claude Code セッションでコンテキストを管理することが実用的な対策になります。セッションを短くし、1 回につき 1 つの作業だけを扱います。
サーバー自体にエージェントを配置する
ここまでの内容はすべてコピーして貼り付けるだけなので、モデルがマシンに触れることはありません。エージェントがサーバー上で実行され、ファイルの読み取りやコマンドの実行を行うと、リスクの性質が変わります。誤ったコマンドによって、サービスが停止する可能性があります。root ではなく、専用の非特権ユーザーを割り当ててください。動作や特徴を把握するまでは本番サーバーで実行せず、最初にスナップショットを取得してください。VPS 上で Claude Code を安全に実行する方法では、サンドボックス化と権限モデルについて説明しています。tmux 内で Claude Code を操作する方法では、もう一方の問題に対処します。SSH(secure shell)セッションが切断されると、フォアグラウンドで実行中のエージェントは作業の途中で終了するためです。アカウントはサービスアカウントと同じ考え方で作成してください。VPS での最小権限ユーザーで、その方法を詳しく説明しています。
FAQ
Claude はサーバーのログを直接読み取れますか?
それだけではできません。チャットインターフェイスから参照できるのは、貼り付けたテキストだけです。サーバー上でコマンドラインツールとして実行する Claude Code は、起動したユーザーの権限でファイルを読み取り、コマンドを実行できます。これは、より大きな信頼上の判断を伴います。通常のサポート質問であれば、エージェントに shell アクセスを与えるより、機密情報を削除した 100 行の抜粋を貼り付けるほうが速く、安全です。
サーバーから絶対に貼り付けてはいけないものは何ですか?
秘密鍵、.env ファイルやその他の認証情報ストア、/etc/shadow、およびユーザーに属するデータです。ログの抜粋をプロンプトに渡す前に、トークンを削除してください。見落としやすい例として、docker compose config の出力には .env の値が展開されます。そのため、ファイルを検証し、何も出力しない docker compose config -q を使用してください。
Claude に本番 VPS でコマンドを実行させても安全ですか?
前提を把握していない新しい管理者と同じように扱ってください。読み取りは問題ありませんが、書き込みには確認が必要です。本番環境では、説明を求めたうえで、自分でコマンドを実行してください。エージェントに実行させる場合は、sudo を無制限に許可していない専用の非特権アカウントを与え、まずはステージング環境で試してください。そこでのミスなら、障害ではなく再構築で解決できます。
Claude が存在しないフラグを提案するのはなぜですか?
もっともらしいテキストを予測するためです。もっともらしいフラグは、実在するフラグと見分けがつきません。ベンダーの CLI や新しいサブコマンドで特に起こりやすく、モデルが参照したドキュメントが少ないか、その後に変更されていることが原因です。--help と man を基準にし、削除や上書きを行うコマンドは、まず dry run を実行してください。
有効化する前に systemd unit を確認するにはどうすればよいですか?
sudo systemd-analyze verify /etc/systemd/system/myapp.service を実行してください。systemd 自身のパーサーでファイルを解析し、未知のディレクティブを行番号付きで報告します。また、存在しないか実行可能ではない ExecStart バイナリにもフラグを付けます。続いて daemon-reload、start を実行し、systemctl status を確認してから enable してください。unit は正常に読み込めても、初回実行時に失敗することがあるためです。