第16章 プロキシサーバー(Squid/Nginxリバースプロキシ)

LPIC-2 208.3〜208.4 相当

前々章ではApacheの基本設定を扱いましたが、ここでは「プロキシ」としての役割に焦点を当て、フォワードプロキシのSquidと、リバースプロキシとしてのNginxを扱います。両者は「クライアントとサーバーの間に立つ」という点は共通していますが、向いている方向が逆であるという違いを意識しながら読み進めてください。

フォワードプロキシとリバースプロキシの違い

フォワードプロキシ(クライアントの代理として外へ出ていく)
[社内クライアントA]  \
[社内クライアントB]  --->  [Squid(フォワードプロキシ)]  --->  [インターネット上の任意のサーバー]
[社内クライアントC]  /

リバースプロキシ(サーバーの代理として外から受ける)
[インターネット上の任意のクライアント]  --->  [Nginx(リバースプロキシ)]  --->  [背後の実サーバー群]
種類役割代表例
フォワードプロキシクライアント側に立ち、社内の複数クライアントの代理としてインターネットへアクセスする(キャッシュ・アクセス制御が主目的)Squid
リバースプロキシサーバー側に立ち、外部からのリクエストを代理で受け、背後の実サーバーへ振り分ける(負荷分散・TLS終端が主目的)Nginx

Squidの用途

Squidは社内ネットワークの「出口」に置かれる代表的なフォワードプロキシで、主に次の4つの目的で導入されます。

目的内容
帯域節約のキャッシュ複数のクライアントが同じコンテンツに繰り返しアクセスする場合、一度取得したコンテンツをキャッシュして再利用し、外部回線の帯域とレスポンス時間を節約する
アクセス制御業務に不要なサイトへのアクセスを制限したり、特定の時間帯・部署だけにアクセスを許可したりする
ログによる可視化誰が・いつ・どのURLへアクセスしたかを一元的なログとして記録し、監査や利用状況分析に使う
企業ネットワークでの出口集約社内の全クライアントの外部アクセスを1台(または少数台)のプロキシに集約することで、外部から見た通信元を一元化し、監視・制御のポイントを絞り込める

インストールと基本設定

Squidの設定ファイルは/etc/squid/squid.confです。主要な項目をコメント付きで示します。

/etc/squid/squid.conf の主要部分
http_port 3128                              # プロキシが待ち受けるポート番号(既定3128)
cache_dir ufs /var/spool/squid 100 16 256    # キャッシュ領域の定義(下記参照)
cache_mem 256 MB                             # メモリ上に保持するキャッシュの上限
maximum_object_size 100 MB                   # これより大きいオブジェクトはキャッシュしない
minimum_object_size 0 KB                     # これより小さいオブジェクトはキャッシュ対象外にする下限
access_log /var/log/squid/access.log squid   # アクセスログの出力先とログフォーマット
cache_log /var/log/squid/cache.log           # Squid自体の動作ログ(起動エラー等)の出力先
coredump_dir /var/spool/squid                # クラッシュ時のコアダンプ出力先
refresh_pattern ^ftp:          1440    20%     10080
refresh_pattern .              0       20%     4320   # 最終フォールバックパターン(すべてのURLにマッチ)

cache_dir ufs /var/spool/squid 100 16 256の4つの引数は、順に「ストレージ形式(ufsは伝統的なファイルシステム方式)」「キャッシュ保存先のパス」「確保する最大容量(MB単位、この例では100MB)」「第1階層のサブディレクトリ数(16)」「第2階層のサブディレクトリ数(256)」を表します。ディレクトリを2階層に分割するのは、1つのディレクトリに大量のファイルが集中してファイルシステムの性能が劣化するのを防ぐためです。

refresh_patternの書式はrefresh_pattern [-i] regex min percent maxです。minは、この分数の間は無条件に新鮮(サーバーへの再検証なし)とみなす時間、percentはLast-Modified以降の経過時間に対する割合をもとに新鮮さを推定する係数、maxはこれを超えたら必ずオリジンサーバーへ再検証を行う上限時間(分)です。-iを付けると正規表現が大文字小文字を区別しなくなります。複数のrefresh_patternがある場合、上から順に評価され最初にマッチしたものが使われるため、より具体的なパターンを先に、包括的なパターン(.など)を最後に置きます。

$ sudo squid -k parse           # 設定ファイルの文法チェック(正常時は無出力、終了コード0)
$ sudo systemctl reload squid   # 正常時は無出力

設定ファイルに文法ミスがある場合、-k parseはエラーメッセージを表示して終了コード1を返します。

$ sudo squid -k parse
2026/08/21 09:50:12| FATAL: Bungled squid.conf line 42: htttp_access allow localnet
2026/08/21 09:50:12| Squid Parent: (squid-1) process 4821 exited with status 1

この行のこの値に注目: Bungled squid.conf line 42:のように、エラーになった具体的な行番号と、その行の実際の内容がそのまま表示されます。この例ではhttp_accessがhtttp_accessとタイプミスされており、未知のディレクティブとして解釈できずに起動が拒否されています。reloadを実行する前に必ず-k parseで構文チェックしておかないと、記述ミスのある設定でリロードしてしまい、Squidプロセスがそのまま停止してしまうことがあります。

クライアント側は、ブラウザやOSのプロキシ設定でhttp_portに指定したポートを経由するよう設定します。

ACLの書式

Squidのアクセス制御は、acl <名前> <型> <値>という書式で条件を定義し、http_accessで許可・拒否を決める2段階の仕組みです。よく使う型を一覧にします。

型意味
src送信元のIPアドレス/ネットワーク
dst宛先のIPアドレス
srcdomain送信元の逆引きドメイン名
dstdomain宛先のドメイン名(前方に.を付けるとサブドメインも含む)
dstdom_regex宛先ドメイン名を正規表現でマッチさせる
url_regexURL全体を正規表現でマッチさせる
urlpath_regexURLのうちパス部分だけを正規表現でマッチさせる(ドメイン名を含めない)
port宛先のポート番号
protoプロトコル(HTTP、HTTPS、FTPなど)
methodHTTPメソッド(GET、POST、CONNECTなど)
time曜日・時間帯(例:MTWHF 09:00-18:00。M=月、T=火、W=水、H=木、F=金、A=土、S=日)
maxconn送信元ごとの同時接続数の上限
proxy_auth認証済みユーザー名(REQUIREDで「何らかの形で認証済みであること」を意味する)
arp送信元のMACアドレス(同一ネットワークセグメント内でのみ有効)

値を直接列挙する代わりに、外部ファイルから読み込むこともできます。多数のドメインを管理する場合に、squid.conf本体を肥大化させずに済みます。

squid.conf
acl allowed_sites dstdomain "/etc/squid/allowed_sites.txt"

/etc/squid/allowed_sites.txt(1行に1ドメイン)
.example.com
.partner-example.co.jp

http_accessの評価とルールセットの設計

http_accessのルールは、allow/denyを記述された順に上から評価し、最初にマッチした行でその可否が確定します。それ以降のルールは評価されません。

注意: どのhttp_accessルールにもマッチしなかった場合、Squidの既定動作は「リスト中の最後のルールの逆」になります。つまり最後のルールがdenyで終わっていれば未マッチのリクエストは許可され、逆に最後がallowで終わっていれば未マッチのリクエストは拒否される、という直感に反する挙動です。この曖昧さを避けるため、ルールセットの末尾には必ず明示的なhttp_access deny allを置き、「それ以外は全て拒否」という意図を明確にしておくのが鉄則です。

実用的なルールセットの完成例を示します。社内ネットワークのみ利用を許可し、業務時間帯のみSNSサイトへのアクセスを禁止し、特定のドメインは常時ブロックする、という3つの要件を組み合わせています。

squid.conf
acl local_net src 192.168.1.0/24
acl blocked_sites dstdomain .example-blocked.com
acl sns_sites dstdomain .facebook.com .twitter.com .instagram.com
acl business_hours time MTWHF 09:00-18:00

http_access deny blocked_sites          # 特定ドメインを常時ブロック(時間帯に関わらず)
http_access deny sns_sites business_hours  # 業務時間帯のみSNSを禁止(時間外はこのルールにマッチしない)
http_access allow local_net             # 社内ネットワークからのアクセスを許可
http_access deny all                    # それ以外はすべて拒否

この並び順が重要です。blocked_sitesとsns_sitesによる拒否ルールを、包括的なallow local_netより先に置くことで、社内ネットワークからのアクセスであっても、まずブロック対象・SNS制限の判定が優先されるようになっています。http_access deny sns_sites business_hoursは、sns_sitesとbusiness_hoursの両方の条件を満たした場合(AND条件)にのみマッチするため、業務時間外はこのルールにマッチせず、次のルールの評価に進みます。

認証

特定のユーザーだけにインターネットアクセスを許可したい場合、Squidは外部の認証ヘルパープログラムと連携してBasic認証などを行えます。まずLinuxのhtpasswdコマンドでパスワードファイルを用意します。

$ sudo htpasswd -c /etc/squid/passwords alice
New password:
Re-type new password:
Adding password for user alice

この行のこの値に注目:-cは新規にファイルを作成するオプションです。2人目以降のユーザーを追加する際は-cを付けずに実行しないと、既存のファイルが上書きされて1人目のユーザーが消えてしまいます。

squid.conf でのBasic認証設定例
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
auth_param basic children 5
auth_param basic realm "Proxy Authentication Required"
auth_param basic credentialsttl 2 hours

acl authenticated_users proxy_auth REQUIRED
http_access allow authenticated_users
http_access deny all
パラメータ意味
program認証を実際に行うヘルパープログラムの実行ファイルと引数
children同時に処理できるよう起動しておくヘルパープロセスの数。多いほど同時認証リクエストをさばけるが、メモリ消費が増える
realmクライアントの認証ダイアログに表示される文字列
credentialsttl一度成功した認証情報をキャッシュしておく時間。この間は毎回ヘルパープログラムを呼び出さずに済む

proxy_auth REQUIREDは「何らかの形で認証済みであること」を条件とするACLです。社内に既にLDAPディレクトリがある場合は、ヘルパープログラムをbasic_ldap_authに差し替えることで、同じproxy_auth REQUIREDの枠組みのままLDAP認証に対応できます。

LDAP認証を使う場合のauth_param(概要)
auth_param basic program /usr/lib/squid/basic_ldap_auth -b "ou=people,dc=example,dc=com" \
  -D "cn=admin,dc=example,dc=com" -w adminpassword -h ldap.example.com

この構成にすると、Squidは受け取ったユーザー名・パスワードを毎回LDAPサーバーへ問い合わせて認証を行い、独自のパスワードファイルを二重管理する必要がなくなります。

透過プロキシ(interceptモード)

通常、クライアント側にプロキシのアドレスを明示的に設定する必要がありますが、ネットワーク機器(ルーターやiptables)でクライアントの通信を強制的にSquidへ振り向ける「透過プロキシ」(intercept)という運用もあります。http_port 3128 interceptのように指定し、クライアント側の設定変更なしに全通信をプロキシ経由にできます。

注意: 透過プロキシはHTTP(暗号化されていない通信)でしか成立しません。HTTPS通信では、クライアントはTLSハンドシェイクの中で接続先サーバーの証明書を直接検証するため、途中に割り込むプロキシが正規の証明書を提示できなければ、クライアント側で証明書エラーが発生します。プロキシが中身を見るためには、独自のCA証明書をあらかじめ全クライアントにインストールさせた上で、その場で偽の証明書を発行して通信を復号する「SSL-Bump」という中間者攻撃的な仕組みが別途必要になり、単純な透過プロキシの延長では実現できません。

キャッシュの動作確認

Squidのアクセスログは既定で/var/log/squid/access.logに記録されます。

$ tail -f /var/log/squid/access.log
1692500000.123    45 192.168.1.10 TCP_HIT/200 5432 GET http://example.com/style.css - HIER_NONE/- text/css
1692500001.456   210 192.168.1.11 TCP_MISS/200 8210 GET http://example.com/app.js - DIRECT/93.184.216.34 application/javascript
1692500002.789    38 192.168.1.10 TCP_REFRESH_HIT/304 312 GET http://example.com/style.css - DIRECT/93.184.216.34 text/css
表記意味
TCP_HITキャッシュにある新鮮なコピーをそのまま応答できた
TCP_MISSキャッシュになく、オリジンサーバーへ取得しに行った
TCP_REFRESH_HITキャッシュにあったが鮮度が切れていたため再検証(条件付きGET)を行い、内容に変更がなかった(304応答)ためキャッシュから応答した。オリジンへの再検証は発生したが、本体データの再送信は節約できている

アクセスログの各フィールドの構成は次の通りです。

順序フィールド意味
1タイムスタンプUnixエポック秒(小数部はミリ秒)
2応答時間ミリ秒単位でのリクエスト処理時間
3クライアントIPアドレスリクエスト元のIPアドレス
4結果コードTCP_HIT/200のように、キャッシュ結果とHTTPステータスコードの組み合わせ
5サイズ応答本体のバイト数
6メソッドGET/POSTなどのHTTPメソッド
7URLリクエストされたURL
8ユーザー名認証済みの場合はユーザー名、未認証は-
9階層コード/取得先DIRECT/IPアドレスのように、オリジンへ直接取得しに行ったか、親キャッシュ経由かなどを示す
10コンテンツタイプ応答のMIMEタイプ
$ squidclient mgr:info
Squid Object Cache: Version 5.7
...
Number of clients accessing cache: 12
Hit Ratio (5 min): 42.3%
Hit Ratio (60 min): 38.1%

この行のこの値に注目:squidclient mgr:infoで表示されるHit Ratioが低い場合、cache_dirで確保しているキャッシュ容量が不足している、あるいはキャッシュ対象外のコンテンツ(動的生成ページなど)が多いといった原因が考えられます。

クライアント側の設定

クライアントやパッケージ管理ツールがプロキシ経由で通信するための設定方法は、環境によって異なります。

シェルの環境変数(多くのCLIツールが参照する)(いずれも正常時は無出力)
$ export http_proxy="http://proxy.example.com:3128"
$ export https_proxy="http://proxy.example.com:3128"
$ export no_proxy="localhost,127.0.0.1,.example.com"

no_proxyは、プロキシを経由せず直接アクセスしたい宛先を指定します。社内向けのサーバーまでプロキシ経由にしてしまうと、到達できなくなったり不要な負荷がかかったりするため、忘れずに設定します。

apt(Debian系):/etc/apt/apt.conf.d/95proxy
Acquire::http::Proxy "http://proxy.example.com:3128";
Acquire::https::Proxy "http://proxy.example.com:3128";
yum/dnf(RHEL系):/etc/yum.conf または /etc/dnf/dnf.conf
proxy=http://proxy.example.com:3128

squidコマンドによる運用操作

コマンド用途
squid -k parse設定ファイルの構文チェックのみを行う(プロセスは起動しない)
squid -k reconfigure稼働中のプロセスに設定の再読み込みを指示する。既存の接続を切断せずに新しい設定を反映できる
squid -zcache_dirで定義したキャッシュディレクトリの構造を初期化する。初回構築時や、cache_dirの設定(パスや容量)を変更した際に必要
$ sudo squid -z
Creating Swap Directories
$ sudo systemctl start squid   # 正常時は無出力
注意: squid -zを既存のキャッシュディレクトリに対して実行すると、そのディレクトリ構造が再作成されます。稼働中のSquidと同時に実行するとキャッシュの不整合を招く可能性があるため、初回構築時か、Squidを停止した状態で実行してください。

トラブルシューティング

クライアントから403 Forbiddenが返る場合、原因の多くはACLとhttp_accessの組み合わせにあります。切り分けの基本は、上から順に評価されるルールのどこで拒否が確定しているかを追うことです。

  1. 該当クライアントのIPアドレス・アクセス時刻・アクセス先URLを確認する
  2. squid.confのhttp_access行を上から順に読み、その条件(src、dstdomain、timeなど)にクライアントの状況が一致するかを1行ずつ確認する
  3. 途中にdenyの行があり、そこにマッチしていれば、それ以降のallow行は評価されないため、そこが拒否の原因になる

加えて、Squid自体の起動エラーや内部的な異常は、アクセスログ(access.log)ではなくcache.logに記録されます。設定変更後にSquidが起動しない場合は、まずcache.logを確認します。

$ sudo tail -50 /var/log/squid/cache.log
2026/08/21 10:00:01 kid1| Set Current Directory to /var/spool/squid
2026/08/21 10:00:01 kid1| FATAL: Bungled squid.conf line 42: unrecognized directive

この行のこの値に注目:FATALで始まる行が、起動失敗の直接の原因です。この例では設定ファイルの42行目に認識できないディレクティブがあることを示しており、typoやディレクティブ名の誤りが典型的な原因です。

Nginxのサーバーブロック

/etc/nginx/sites-available/example.com
server {
    listen 80;
    server_name example.com;
    root /var/www/example.com;

    location / {
        try_files $uri $uri/ =404;
    }
}
$ sudo nginx -t                    # 設定ファイルの文法チェック
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx      # 正常時は無出力

設定に文法ミスがある場合、nginx -tはエラー箇所のファイル名・行番号を示して終了コード1を返します。

$ sudo nginx -t
nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/example.com:9
nginx: configuration file /etc/nginx/nginx.conf test failed

この行のこの値に注目: syntax is okとtest is successfulの2行がどちらも表示されて初めて設定が正常です(構文だけは正しくても、参照しているファイルが存在しないなど別の理由でtest failedになることもあります)。エラー時は[emerg]に続けてファイル名と行番号(この例ではexample.com:9)が具体的に示されるため、該当箇所をすぐに特定できます。reloadの前に必ず-tで確認する習慣をつけておくと、設定ミスのままリロードしてNginxが停止する事故を防げます。

Nginxのlocationブロックは複数定義でき、どれにマッチするかには優先順位があります。完全一致(location = /path)が最優先、次に正規表現一致(location ~やlocation ~*)、最後に前方一致(プレフィックス一致)という順で評価されます。複数のlocationブロックを組み合わせる際は、この優先順位を意識しないと意図しないブロックがマッチしてしまうことがあります。

よくある間違い: Apacheのsites-availableに設定ファイルを置いただけでは有効になりません。Debian系ではa2ensiteでsites-enabledにシンボリックリンクを作成する必要があります(Nginxも同様の構成を取ることが多いですが、Nginx自体にはa2ensiteに相当する公式コマンドはなく、ln -sで手動リンクするのが一般的です)。設定ファイルを編集したのに反映されない場合は、まずこのリンクの有無を確認しましょう。

Nginxをリバースプロキシとして使う

Nginxは静的コンテンツの配信だけでなく、背後にあるアプリケーションサーバー(Node.js、Gunicornなど)へリクエストを中継する「リバースプロキシ」としても広く使われます。TLS終端やロードバランシングを前段でまとめて担わせる構成が一般的です。

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

バックエンドが複数台ある場合はupstreamブロックで振り分け先をまとめて定義し、簡易的なロードバランシングも行えます。

upstream app_servers {
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;
}
server {
    location / {
        proxy_pass http://app_servers;
    }
}

フォワードプロキシのSquidが「クライアントの代理」であるのに対し、リバースプロキシのNginxは「サーバーの代理」である、という向きの違いを意識しておくと、両者を混同せずに使い分けられます。実務では、外部公開用にはNginxのリバースプロキシ構成、社内クライアントの出口対策にはSquidのフォワードプロキシ構成、というように役割ごとに使い分けるのが一般的です。

確認クイズ

Q1. クライアント側に立ち、社内の複数クライアントの代理としてインターネットへアクセスするプロキシの種類はどれですか?

解説: フォワードプロキシは、クライアント側に立って複数クライアントの代理としてインターネットへアクセスする方式で、Squidが代表例です。

Q2. cache_dir ufs /var/spool/squid 100 16 256 という設定で、100が表す意味はどれですか?

解説: cache_dirの引数は順に、ストレージ形式・パス・最大容量(MB)・第1階層のサブディレクトリ数・第2階層のサブディレクトリ数を表し、100は最大容量です。

Q3. refresh_patternのmax引数の意味として正しいものはどれですか?

解説: maxは、Last-Modifiedからの経過時間がこの時間(分)を超えたら、無条件にオリジンサーバーへの再検証を行う上限を表します。

Q4. Squidのacl型のうち、URLのパス部分だけを正規表現でマッチさせる型はどれですか?

解説: urlpath_regexは、ドメイン名を含まないURLのパス部分だけを正規表現でマッチさせる型です。url_regexはURL全体を対象にします。

Q5. Squidのhttp_accessルールで、どのルールにもマッチしなかったリクエストへの既定の扱いはどれですか?

解説: どのルールにもマッチしなかった場合、既定動作はリスト中の最後のルールの逆になります。この曖昧さを避けるため、末尾に明示的なhttp_access deny allを置くのが鉄則です。

Q6. acl business_hours time MTWHF 09:00-18:00 というACLのtime型の書式で、Hが表す曜日はどれですか?

解説: time型の曜日表記はM=月、T=火、W=水、H=木、F=金、A=土、S=日です。

Q7. Squidでhtpasswdを使って2人目以降のユーザーをパスワードファイルに追加する際、-cオプションを付けてはいけない理由はどれですか?

解説: -cは新規にファイルを作成するオプションのため、2人目以降の追加時に付けると既存ファイルが上書きされ、既に登録済みのユーザーが消えてしまいます。

Q8. auth_param basic credentialsttl の役割はどれですか?

解説: credentialsttlは、一度成功した認証情報をキャッシュしておく時間を指定します。この間はヘルパープログラムを毎回呼び出さずに済みます。

Q9. 透過プロキシ(interceptモード)がHTTPS通信では単純には成立しない理由はどれですか?

解説: HTTPS通信では、クライアントはTLSハンドシェイクの中で接続先サーバーの証明書を直接検証します。途中に割り込むプロキシが正規の証明書を提示できなければ証明書エラーになるため、単純な透過プロキシでは成立しません。

Q10. 次のアクセスログの一部から読み取れる内容として正しいものはどれですか?
TCP_REFRESH_HIT/304 312 GET http://example.com/style.css

解説: TCP_REFRESH_HITは、キャッシュにあったコンテンツの鮮度が切れていたため条件付きGETで再検証を行い、304応答(変更なし)が返ってきたためキャッシュから応答したことを示します。

Q11. Squidのアクセスログのフィールドのうち、認証済みユーザー名が入る位置に未認証の場合表示される記号はどれですか?

解説: アクセスログのユーザー名フィールドは、認証済みの場合はユーザー名、未認証の場合は-(ハイフン)が表示されます。

Q12. シェルの環境変数no_proxyの役割として正しいものはどれですか?

解説: no_proxyは、プロキシを経由せず直接アクセスしたい宛先(社内サーバーなど)を指定します。設定を忘れると、社内向け通信までプロキシ経由になってしまいます。

Q13. cache_dirの設定(パスや容量)を変更した際に、キャッシュディレクトリの構造を初期化するために実行するコマンドはどれですか?

解説: squid -zは、cache_dirで定義したキャッシュディレクトリの構造を初期化します。初回構築時や設定変更時に必要です。squid -k reconfigureは稼働中プロセスへの設定再読み込み、squid -k parseは構文チェックのみです。

Q14. Squid自体の起動エラーや内部的な異常が記録されるログファイルはどれですか?

解説: cache.logには、Squid自体の起動エラーや内部的な異常(FATALで始まる行など)が記録されます。access.logはクライアントのアクセス記録です。

Q15. Nginxの設定ファイルに文法エラーがないかを確認するコマンドはどれですか?

解説: nginx -t はNginxの設定ファイルの文法をチェックするコマンドです。

Q16. 背後にあるアプリケーションサーバーへリクエストを中継するために、Nginxのlocationブロックで使うディレクティブはどれですか?

解説: proxy_passは、受け取ったリクエストを背後のアプリケーションサーバーへ中継するリバースプロキシの基本ディレクティブです。