タイトル: プログラムが本番サーバーで反映されない場合の対処法
SEOタイトル: 本番サーバーでコード変更が反映されない(キャッシュ・OPcache・LB・CDN の切り分け)
| この記事の要点 |
|
切り分けフロー
| 質問 | 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 が必須
ブラウザキャッシュ対処
<!-- HTML ファイル自体をキャッシュさせない -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<!-- 静的アセットはバージョン付与 -->
<link rel="stylesheet" href="/css/app.css?v=20260517">
<script src="/js/app.js?v=20260517"></script>
<!-- Laravel Mix / Vite の場合は自動バスター -->
<link rel="stylesheet" href="{{ mix('css/app.css') }}"> <!-- ?id=ハッシュ -->
@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.js | pm2 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 のハッシュファイル名運用に。