🦑

#1【キャッシュ】フォワードプロキシのキャッシュが原因で古いCSSが適用される?(Chrome,Squid,Nginx)

に公開

背景

最近「WEBサイトを更新したにもかかわらず、フォワードプロキシのキャッシュが原因で古い画面が表示されることがある」という話を聞きました。
確かにそういうこともありそうだなと思いつつも、本当にそうか?ブラウザキャッシュが表示されただけなのでは?と思ったので、実際に検証してみようというのが今回のテーマです。

構成

以下4台を用意します。
なおサーバおよびプロキシは、Proxmox上にデプロイしたRockyLinux8.8に構築することとします。

  • WEBオリジンサーバ : 192.168.12.55
    HTMLとCSSのコンテンツを保管する。(Nginx1.14.1)
  • WEBキャッシュサーバ : 192.168.12.56
    オリジンサーバのコンテンツキャッシュを行い、クライアントからのアクセスを受け付ける。なおコンテンツの有効期限は1分で、基本的に最新のコンテンツを取りに行く仕様。(Nginx1.14.1)
  • フォワードプロキシ : 192.168.12.57
    クライアントからのHTTPアクセスを中継し、一度ダウンロード(アクセス)したコンテンツは60分間キャッシュに保持する。(Squid4.15)
  • クライアントPC : 192.168.12.X(DHCP)
    HTTPアクセスを行う。使用するブラウザはChrome Ver.134。

構築

要件に従い構築します。

①WEBオリジンサーバ

  1. インストール&フォルダ作成
dnf install nginx -y

mkdir -p /var/www/html
chown -R nginx:nginx /var/www/html
chmod -R 755 /var/www/html
  1. HTML&CSS作成
/var/www/html/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSSテスト</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>CSSテスト</h1>
    <p>CSS修正後、この部分は赤色に表示されるはずです。</p>
</body>
</html>
/var/www/html/style.css
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    text-align: center;
    padding: 50px;
}

h1 {
    color: black;
}

p {
    font-weight: bold;
    font-size: 1.2em;
    color: black;  /* 黒 */
}
  1. コンフィグファイル編集
/etc/nginx/nginx.conf(一部抜粋)
    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        # root         /usr/share/nginx/html;
        root         /var/www/html;
        index        index.html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
            try_files $uri $uri/ =404;
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
  1. FWとか起動とか
firewall-cmd --add-service=http --zone=public --permanent
firewall-cmd --reload
firewall-cmd --list-all

systemctl enable --now nginx
systemctl status nginx
  1. SELinux対策
    そのまんまだとアクセスしても403になるので、SELinuxポリシーを再構築します。
# 確認から新ポリシーの作成・適用まで
cat /var/log/audit/audit.log | grep denied | tail -5
cat /var/log/audit/audit.log | grep denied | audit2allow
cat /var/log/audit/audit.log | grep denied | audit2allow -M nginxpolicy_20250323_01
semodule -i nginxpolicy_20250323_01.pp

# 再確認。新ポリシー適用後もhttpアクセスが弾かれる場合、何度かポリシーを作り直す。
# なお今回は2回の作成で済んだ。最終的に許可されたポリシーは以下のようになる。
cat /var/log/audit/audit.log | grep denied | audit2allow

#============= httpd_t ==============

#!!!! This avc is allowed in the current policy
allow httpd_t var_t:file { getattr open read };

h++p://192.168.12.55/にアクセスし、index.htmlの内容が表示されればOK。

WEBキャッシュサーバ

  1. インストール&フォルダ作成
dnf install nginx -y

mkdir -p /var/cache/nginx
chown -R nginx:nginx /var/cache/nginx
chmod -R 755 /var/cache/nginx
  1. コンフィグファイル編集
    proxy_set_headerって設定値は謎です。add_headerってのはちゃんと反映されてましたね。
    まあよく分かんないですが今回は無視ですね。趣旨はそこじゃないので。
/etc/nginx/nginx.conf(一部抜粋)
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=cache_zone:10m max_size=1g inactive=60m use_temp_path=off;

    server {
        listen 80;
        server_name 192.168.12.56;  # フロントエンドのドメインまたはIP

        location / {
            proxy_pass http://192.168.12.55;  # バックエンドのWebサーバ
            proxy_set_header Host $host;  # クライアントがリクエストしたホスト
            proxy_set_header X-Real-IP $remote_addr;  # クライアントの実IP
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # XFFヘッダ付与

            proxy_cache cache_zone;
            proxy_cache_valid any 1m;  # キャッシュ有効期限は1分間(フロントは常に最新を維持)
            # proxy_cache_bypass $http_cache_control;  # クライアントが Cache-Control ヘッダーを送信した場合はキャッシュをバイパスする
            add_header X-Cache-Status $upstream_cache_status;  # キャッシュの状態(HIT, MISS, BYPASSなど)をレスポンスヘッダーに追加する
        }
    }
  1. FWとか起動とか
firewall-cmd --add-service=http --zone=public --permanent
firewall-cmd --reload
firewall-cmd --list-all

systemctl enable --now nginx
systemctl status nginx
  1. SELinux対策
    オリジンサーバの時とやることは一緒です。
# 確認から新ポリシーの作成・適用まで
cat /var/log/audit/audit.log | grep denied | tail -5
cat /var/log/audit/audit.log | grep denied | audit2allow
cat /var/log/audit/audit.log | grep denied | audit2allow -M nginxpolicy_20250323_01
semodule -i nginxpolicy_20250323_01.pp

# 再確認。新ポリシー適用後もhttpアクセスが弾かれる場合、何度かポリシーを作り直す。
# なお今回は1回の作成で済んだ。最終的に許可されたポリシーは以下のようになる。
cat /var/log/audit/audit.log | grep denied | audit2allow

#============= httpd_t ==============

#!!!! This avc is allowed in the current policy
allow httpd_t http_port_t:tcp_socket name_connect;

h++p://192.168.12.56/にアクセスし、WEBオリジンサーバのindex.htmlが表示されればOK。

フォワードプロキシ

  1. インストール
dnf install squid -y
  1. コンフィグファイル編集
/etc/squid/squid.conf
# セーフポート
acl Safe_ports port 80          # http
acl Safe_ports port 8080        # http
http_access deny !Safe_ports

# ネットワークACL
acl localnet src 192.168.12.0/24
http_access allow localnet
http_access allow localhost
http_access deny all

# Squidのリッスンポート
http_port 8080

# キャッシュ設定
cache_dir ufs /var/spool/squid 1000 16 256  # キャッシュディレクトリ(1000MB)

# キャッシュの有効期限(60分)
refresh_pattern . 60 100% 60
  1. キャッシュ用ディレクトリ作成
ll /var/spool/squid/
squid -z
ll /var/spool/squid/
  1. FWとか起動とか
firewall-cmd --add-port=8080/tcp --zone=public --permanent
firewall-cmd --reload
firewall-cmd --list-all

systemctl enable --now squid
systemctl status squid

接続

クライアントPC側でプロキシを設定し、h++p://192.168.12.56/にアクセスできることを確認します。

アクセスが成功した場合、以下のような表示になります。
Remote AddressがプロキシのIP:8080になっているので、ちゃんとフォワードプロキシ経由でアクセスできているようです。

フォワードプロキシ構築の際は特に気にしていませんでしたが、レスポンスヘッダにX-CacheとX-Cache-Lookupが付与されていますね。知りたいのは「プロキシがキャッシュから応答したか」なので、X-Cacheだけを見れば良いのかな。
今回は初回アクセスなので、当然ながらMISSになってますね。HITならキャッシュ応答です。

さて今回はここまで。
次回は実際にプロキシ&ブラウザのキャッシュの挙動について確認します。

Discussion