28.

本番サーバーでコード変更が反映されない(キャッシュ・OPcache・LB・CDN の切り分け)

編集
この記事の要点
  • 原因の 9 割はキャッシュ。Laravel: php artisan optimize:clear、PHP: OPcache reset、ブラウザ/CDN: バスター付与
  • Laravel: config:clear / cache:clear / view:clear / route:clear をまとめて
  • OPcacheopcache_reset() または php-fpm reload で再評価
  • LB 配下で「特定ユーザーだけ古い」なら、ロードバランサ配下の一部サーバだけデプロイ漏れを疑う
  • CDN / Cloudflare: ダッシュボードで Purge Everything、または ?v=20260517 でキャッシュバスター
  • ブラウザキャッシュ: Ctrl+F5 / DevTools の「Disable cache」、本番では HTML に Cache-Control ヘッダ

切り分けフロー

質問YES ならNO なら
1. 自分の手元(開発機)では反映済?本番固有問題(下へ)コード変更/コミット漏れを疑う
2. サーバーに pull / デプロイされている?3 へgit pull / デプロイ再実行
3. PHP / Node / Java のプロセスをリスタートした?4 へopcache reset / php-fpm reload / pm2 restart
4. ブラウザを Ctrl+F5 した?5 へブラウザキャッシュ
5. CDN / プロキシ経由?CDN purgeサーバー内キャッシュ深掘り
6. LB で複数台ある?各サーバーの版数確認

Laravel: まず全キャッシュをクリア

cd /var/www/html

# 全部まとめてクリア
php artisan optimize:clear

# 個別実行
php artisan config:clear      # config/ 配下のキャッシュ
php artisan cache:clear       # Cache::put した内容
php artisan view:clear        # コンパイル済 Blade
php artisan route:clear       # ルートキャッシュ
php artisan event:clear       # イベントキャッシュ

# 本番では config / route / view はキャッシュした方が高速 → 再生成
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

OPcache をリセット

PHP は本番ではOPcacheでコンパイル済みコードをメモリ保持しているため、ファイル更新後すぐに反映されないことがあります。

# 方法1: PHP-FPM をリロード(無停止)
sudo systemctl reload php8.2-fpm
# OPcache のメモリがクリアされる

# 方法2: 専用エンドポイントで opcache_reset()
# routes/web.php 等に(IP 制限必須):
# Route::get('/opcache-reset', function () {
#     if (request()->ip() !== '127.0.0.1') abort(403);
#     opcache_reset();
#     return 'reset';
# });

# 方法3: cachetool(推奨)
composer global require gordalina/cachetool
cachetool opcache:reset --fcgi=/run/php/php8.2-fpm.sock

# OPcache の状態を確認
cachetool opcache:status --fcgi=/run/php/php8.2-fpm.sock

php.ini で「自動再評価」設定

; 本番推奨設定
opcache.enable = 1
opcache.memory_consumption = 256
opcache.max_accelerated_files = 20000

; ファイル変更を 60 秒ごとに自動検出(開発機向け)
opcache.validate_timestamps = 1
opcache.revalidate_freq = 60

; 完全停止して再起動でしか反映しない(本番の最高速設定)
opcache.validate_timestamps = 0
; → デプロイのたびに php-fpm reload が必須

ブラウザキャッシュ対処











    
@vite('resources/css/app.css')                              

Nginx の Cache-Control 設定

# HTML は短いキャッシュ
location ~ \.(html|htm)$ {
    add_header Cache-Control "no-cache, must-revalidate";
}

# 画像/CSS/JS(ハッシュ付ファイル名前提)は長期キャッシュ
location ~* \.(css|js|jpg|jpeg|png|webp|svg|woff2)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

# プロキシキャッシュを使っている場合は purge も
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=app:10m;
# 緊急時:
# rm -rf /var/cache/nginx/*
# systemctl reload nginx

CDN (Cloudflare 等) のパージ

# Cloudflare API でパージ
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"purge_everything":true}'

# 特定 URL だけ
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"files":["https://example.com/css/app.css"]}'

# Cloudflare ダッシュボード → Caching → Configuration → Purge Everything

ロードバランサ配下の「特定ユーザーだけ古い」

「自分は最新、同僚は古い」「リロードすると最新と古いが交互に出る」というときは、LB の後ろの一部サーバだけデプロイ漏れを疑います。

# 各サーバの版数を返すエンドポイントを用意
# routes/web.php:
# Route::get('/_version', fn() => gethostname() . ':' . exec('git rev-parse --short HEAD'));

# クライアントから連打して全サーバを叩く
for i in {1..20}; do curl https://example.com/_version; echo; done
# web01:abc1234
# web02:def5678   ← これだけ違うコミット = デプロイ漏れ
# web01:abc1234
# ...

# デプロイ漏れサーバで個別実行
ssh web02 'cd /var/www/html && git pull && php artisan optimize:clear && systemctl reload php8.2-fpm'

Java / Node / Python の場合

言語反映に必要な操作
Java (Tomcat)新しい .war をデプロイ → systemctl restart tomcat / 自動 reload 設定
Java (Spring Boot)jar 入替 → systemd で restart
Node.jspm2 reload / pm2 restart all
Python (Django/Flask)systemctl reload gunicorn / uwsgi reload
Python (Lambda)関数を再デプロイ(更新後即時反映)

FAQ

Q: php artisan optimize:clear しても反映されない
A: OPcache が残っている可能性大。systemctl reload php8.2-fpm を必ず併用。

Q: 開発機では動くのに本番だけ古い
A: 本番だけ config キャッシュが効いている。php artisan config:clear && php artisan config:cache

Q: 画像/CSS だけ古い
A: 静的アセットは長期 Cache-Control が効いている。バージョンクエリ付与 or Vite/Mix のハッシュファイル名運用に。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 環境構築とプロジェクト/アプリの作成
  2. MVC(MVT)のそれぞれの使い方と説明
  3. データベースへの接続と操作
  4. Django Administration
  5. git管理
  6. エラー一覧
  7. バージョンの確認方法
  8. ログ出力方法
  9. SQLのログ出力方法
  10. ログのローテート設定
  11. settings.pyの定数にアクセスする方法
  12. 本番環境へのインストールとアプリのデプロイ(apache編)
  13. 本番環境へのインストールとアプリのデプロイ(nginx編)
  14. djangoアプリの本番の開始URLを変更する
  15. 静的(static)ファイルの置き場所と読み込み(画像、css、js )
  16. CSRFトークンをAjaxで使用する方法
  17. ajaxの使用例(POST編)
  18. ファイルのアップロードとファイルの名前
  19. クイックスタート/チュートリアル
  20. ログイン機能
  21. テンプレート側のログイン判定
  22. ビュー側のログイン判定
  23. 管理者ユーザーの作成/判定と管理画面
  24. モデルのjson化とレスポンス
  25. runserverでポートを指定する方法
  26. cronによるバッチ実行
  27. テンプレートで利用する共通のcontextを定義する方法
  28. プログラムが本番サーバーで反映されない場合の対処法
  29. APIの作成
  30. cron用コマンド・ファイルの作成