この記事でわかること

  • 自作アプリが503を返すときに、どこから順に確かめればよいか
  • サーバーを再起動した後だけアプリが起動しない原因の1つと、その防ぎ方
  • 設定やスクリプトが読まれないとき、日本語が化けるときの確かめ方
  • Claude Codeに原因の仮説を先に出させ、読み取りだけで確かめさせる頼み方

対象は、Apacheのリバースプロキシの後ろで、Gunicornなどで自作のアプリを動かしているサーバーです。設定の書き方はApacheのリバースプロキシの記事、アプリの起動はFastAPIをGunicornとUvicornで公開する手順で扱いました。

検証した環境と、この記事で断定しないこと

この記事のコマンドは、2026年10月に作業PCのGit Bash(bash 5.3)とPython 3.12で、架空のファイルと127.0.0.1だけの一時のサーバーを使って確かめました。503の例は、このサイトのサーバーで実際に起きたものを読み取りだけで調べた結果です。

一方で、Apacheのエラーログにどの行が出るかと、LinuxのbashでCRLFのスクリプトを実行したときのエラーの文言は確かめていません。作業PCのbashは、CRLFのスクリプトもエラーなしで実行したためです。

切り分けは外側から内側へ進める

障害の原因は、思いついたところから調べると遠回りになります。要求が通る順に、外側から内側へ1段ずつ確かめます。

順番 確かめる場所 分かること
1 公開のURL どの状態コードが返るか
2 Apacheの設定 どのポートへ転送しているか
3 ポートの待ち受け アプリが要求を受け取れる状態か
4 プロセスとPIDファイル アプリが動いているか、なぜ動いていないか
5 アプリのログ 動いているのに失敗する理由
6 ファイル 改行コード・BOM・文字コード

どの段で「おかしい」が見つかったかで、その先を調べるか、そこで直すかを決めます。

Claude Codeには先に仮説を出させる

Claude Codeに「直して」と頼むと、原因が分かる前に設定を変えてしまうおそれがあります。まず考えられる原因を複数出させ、それぞれを読み取りだけで確かめさせます。読み取りだけを守らせる頼み方はサーバーの状態確認をClaude Codeに読み取り専用で任せる方法にまとめています。

【用途】仮説を出させてから確かめさせる /【実行場所】Claude Codeへの依頼 /【状態変更】なし(調べた結果を報告させる)

https://example.com/myapp/ が503を返します。原因を調べてください。
- 先に、考えられる原因を3つ以上挙げ、それぞれを確かめるコマンドを書いてください
- 外側から順に確かめてください(公開のURL → Apacheの設定 → ポート → プロセス → ログ)
- 実行してよいのは読み取りのコマンドだけです。設定の変更・再起動・ファイルの削除はしないでください
- 権限がなくて読めなかったものは、推測で埋めずに「読めなかった」と書いてください
結果と、原因の見立てと、直す案を報告して、私の確認を待ってください。

症状の記録から直す案・直した後の確認・完了の判定までの依頼文とチェックリストを、有料の記事「Claude Code サーバー障害の切り分けセット」にまとめています。

503が出たときの確かめ方

503は、Apacheは応答しているが、後ろのアプリへつながらないときに見えます。まず公開のURLの状態コードを見て、Apacheの設定で転送先のポートを確かめます。

【用途】状態コードと転送先を確かめる /【実行場所】サーバー(SSHでログインした一般のユーザー) /【状態変更】なし(表示するだけ)

curl -sI https://example.com/myapp/ | head -n 1
grep -n 'ProxyPass' /etc/httpd/conf.d/myapp.conf

次に、そのポートでアプリが待ち受けているかを確かめ、サーバーの中からアプリへ直接要求を送ります。

【用途】ポートの待ち受けとアプリの応答を確かめる /【実行場所】サーバー(SSHでログインした一般のユーザー) /【状態変更】なし(表示するだけ)

ss -ltnp | grep ':8081 '
curl -sI http://127.0.0.1:8081/ | head -n 1
curl -sI http://127.0.0.1:8081/ > /dev/null; echo $?

ssに何も出ず、curlの終了コードが7なら、そのポートでは誰も待ち受けていません。検証では、待ち受けている間は1行目に200 OKの行が出て、止めた後は何も出ずに終了コードが7になりました。このサイトのサーバーで503を返していたアプリも、同じく待ち受けがなく、終了コードは7でした。この場合はApacheではなく、アプリの側を調べます。

この段では、Apacheの設定は表示するだけで変えません。設定を変えるときは、先に設定のファイルの控えを取り、確認の手順と戻し方を決めてから進めます。手順はApacheのリバースプロキシの記事のとおりです。

再起動の後だけ起動しないとき

サーバーの再起動の後に、あるアプリだけが起動していないことがありました。起動のスクリプトは「PIDファイルがあり、その番号のプロセスがあれば、起動中とみなして何もしない」作りで、起動のログには次の1行が残っていました。

既に起動中です (PID: 番号)

PIDファイルは前回の起動のときのまま残っていました。kill -0はその番号のプロセスがあるかを確かめるだけで、それが目的のアプリかどうかは見ません。再起動の後はPIDが小さい番号から振り直されるので、たまたま同じ番号を別のプロセスが使っていて、起動を飛ばしたと考えられます。ただし、起動のときにその番号が何のプロセスだったかは確かめられないので、これは記録からの推定です。

まず、再起動の時刻と、PIDファイルが指すプロセスを確かめます。

【用途】再起動の時刻とPIDファイルの中身を確かめる /【実行場所】サーバー(SSHでログインした一般のユーザー) /【状態変更】なし(表示するだけ)

uptime -s
ls -l /home/your-user/apps/myapp/logs/gunicorn.pid
ps -o pid,lstart,args -p "$(cat /home/your-user/apps/myapp/logs/gunicorn.pid)"

PIDファイルの日付が再起動より前で、psが別のプログラムを表示するか何も表示しなければ、PIDファイルは古いものです。

検証では、関係のないプロセスの番号をPIDファイルに書くと、同じ判定が「起動中」と判断して起動しませんでした。番号のプロセスのコマンドにアプリの名前が含まれるかも確かめるようにすると、正しく起動に進みました。起動のスクリプトの判定は、次のように変えられます。

【用途】起動のスクリプトの判定を、目的のアプリかどうかまで確かめる形にする /【実行場所】起動のスクリプト(run.sh)の中 /【状態変更】あり(スクリプトを書き換える)

PIDFILE="logs/gunicorn.pid"
PID=$(cat "$PIDFILE" 2>/dev/null)
if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null && grep -qa gunicorn "/proc/$PID/cmdline"; then
    echo "既に起動中です (PID: $PID)"
    exit 0
fi

書き換える前に元のスクリプトの控えを取り、書き換えた後はポートの待ち受けと外側からの応答まで確かめます。

ログの場所と、読めないとき

Apacheの公式の説明では、エラーログは問題が起きたときに最初に見る場所です。ただ、置き場所はサーバーの設定によって違い、このサイトのサーバーではrootだけが読める設定でした。読めないときはsudoの使える人に頼み、Claude Codeには推測で埋めさせません。

アプリのログは、自分で読めることが多い場所です。Gunicornは既定ではアクセスログを書かないので、ログに要求の記録がなくても、要求が届いていないとは限りません。

【用途】アプリのログの最後と例外の数を確かめる /【実行場所】サーバー(SSHでログインした一般のユーザー) /【状態変更】なし(表示するだけ)

tail -n 30 /home/your-user/apps/myapp/logs/gunicorn.log
grep -c Traceback /home/your-user/apps/myapp/logs/gunicorn.log

Tracebackが増えていれば、アプリの中の例外です。起動・停止・シグナルの行だけなら、アプリは要求を処理する前の段階で止まっているか、そもそも動いていない可能性が高くなります。

設定やスクリプトが読まれないとき

Windowsで作ったファイルをサーバーへ送ると、改行コード(CRLF)やBOMが原因で、設定やスクリプトが読まれないことがあります。サーバーでは、まず見えない文字があるかを確かめます。

【用途】BOMと改行コードを確かめる /【実行場所】サーバー(SSHでログインした一般のユーザー) /【状態変更】なし(表示するだけ)

head -c 3 .env | od -An -tx1
file deploy.sh
cat -A deploy.sh | head -n 3

1行目がef bb bfならBOMが付いています。fileの表示にCRLFの語が含まれ、cat -Aで行末が^M$になっていれば、改行はCRLFです。

検証では、BOM付きの.envをPythonのpython-dotenvで読むと、先頭の変数の名前の前にBOMが付いた別の名前になり、DATABASE_URLとして読めませんでした。2行目からは正しく読めるので、気づきにくい障害です。

直すときは、作業PCでBOMなし・LFで保存し直してから送り直します。作業PCの側でずれを防ぐ方法はWindowsでClaude Codeを使うときの注意点にまとめています。

日本語が化けるとき

日本語が化けたときは、ファイルの文字コードを確かめます。

【用途】文字コードを確かめ、CP932のファイルをUTF-8で書き出す /【実行場所】サーバー(SSHでログインした一般のユーザー) /【状態変更】あり(新しいファイルを作る。元のファイルは変えない)

file notes.txt
iconv -f CP932 -t UTF-8 notes.txt > notes_utf8.txt
file notes_utf8.txt

検証では、fileはUTF-8のファイルをUTF-8 textと表示しましたが、CP932のファイルはCP932とは表示せず、Non-ISO extended-ASCII textと表示しました。CP932のファイルをUTF-8として読もうとすると、iconvは変換できずに終了コード1を返します。

化け方の形も手がかりになります。CP932のファイルをUTF-8として読むと記号の混じった表示に、UTF-8のファイルをCP932として読むと漢字と半角カナの並びに化けました。

直すかどうかの判断と、直した後の確認

原因が分かったら、直す前に次のことを決めます。

  • 変えるファイルの控えを取る(DBが関わるときはバックアップと復元確認の記事の手順で)
  • 直した後に、どの確認を繰り返すかを決める(切り分けで使ったコマンドをそのまま使う)
  • うまくいかなかったときの戻し方を決める

直した後は、内側から外側へ戻りながら、ポート・アプリの応答・公開のURLの順に確かめます。1つの確認だけで終わらせず、障害を見つけた段より外側をすべて確かめます。

このサイトでのつまずき

このサイトでは、これまでに次の障害を経験しました。サーバー全体の作業の流れはClaude CodeでAlmaLinuxサーバーを構築・運用する方法にまとめています。

  • .envをBOM付きで配置し、先頭の変数が読めずにDBのマイグレーションが失敗した
  • 記事の中のリンクがサブパスを含まず、全記事の内部リンクが404になっていた
  • Windowsから送ったファイルの日本語が化けたり、改行がCRLFになったりした
  • サーバーの再起動の後に、同じサーバーの別のアプリが起動しておらず、503を返していた

どれも、症状は外側(画面や応答)に出て、原因は内側(ファイルや起動のしかた)にありました。最後の例は、この記事を書くために読み取りで調べていて見つけたものです。調査ではそのアプリを変えず、直すかどうかは別に判断することにしました。

まとめ

  • 障害は、公開のURL → Apacheの設定 → ポート → プロセス → ログ → ファイルの順に、外側から確かめる
  • Claude Codeには、仮説を先に出させ、読み取りだけで確かめさせる
  • 503でポートに待ち受けがなければ、アプリの側を調べる
  • kill -0は番号のプロセスがあるかしか見ない。PIDファイルが古いと、再起動の後に起動を飛ばすことがある
  • BOM・改行コード・文字コードは、見えない文字を確かめてから、作業PCで直して送り直す

まずは、今動いているアプリでss -ltnpとcurl -sIを実行し、正常なときの表示を控えておくところから始めてみてください。