このページはHAProxyの入口・送り先・監視を分ける入門です。旧設定は保存用で本番利用不可。先に隔離例と検証範囲を読んでください。追加例の対象はHAProxy 3.2 LTSで、実行時のパッチ版はhaproxy -vvで確認します。
先に試す隔離用の完成設定(HAProxy 3.2)
以下は実在サービスへ接続しない教材です。新規の専用コンテナをnetwork none・ホスト公開ポートなしで起動し、その中の127.0.0.1だけを使います。haproxy.cfgとfixtures.cfgの2ファイルを読み取り専用で同じディレクトリに置き、両方を-fで指定します。fixtures.cfgはHAProxy自身が返す合成API/Webで、実アプリではありません。既存の設定ファイルを上書きしないでください。
statsのlab:public-lab-onlyは公開済みの合成資格情報で、本番には使用不可。loopbackでも同一ホスト内の別プロセスは接続可能です。実運用では管理経路の到達制限、固有の秘密値、TLS等の通信保護を設計します。Basic認証だけでは平文HTTPの盗聴対策になりません。stats adminは有効にしません。
haproxy.cfg:受け口・HTTP検査・統計
# HAProxy 3.2: isolated loopback lab, NOT a production configuration.
global
maxconn 128
defaults
mode http
timeout connect 1s
timeout client 5s
timeout server 5s
timeout check 1s
frontend lab_in
bind 127.0.0.1:8080
# Direct clients only: discard their claimed forwarding identity.
http-request del-header Forwarded
http-request del-header X-Real-IP
http-request del-header X-Forwarded-Host
http-request del-header X-Forwarded-Port
http-request del-header X-Forwarded-Prefix
http-request set-header X-Forwarded-Proto http
http-request set-header X-Forwarded-For %[src]
acl api_exact path /api
acl api_child path_beg /api/
use_backend api_servers if api_exact or api_child
default_backend web_servers
backend api_servers
option httpchk
http-check send meth GET uri /readyz ver HTTP/1.1 hdr Host lab.invalid
http-check expect status 200
server api1 127.0.0.1:9101 check inter 200ms fall 2 rise 2
backend web_servers
option httpchk
http-check send meth GET uri /readyz ver HTTP/1.1 hdr Host lab.invalid
http-check expect status 200
server web1 127.0.0.1:9102 check inter 200ms fall 2 rise 2
listen lab_stats
bind 127.0.0.1:8404
stats enable
stats uri /stats
stats hide-version
# PUBLIC synthetic lab values, never reuse as production credentials.
stats auth lab:public-lab-only
fixtures.cfg:同じ隔離プロセス内の合成応答
# Synthetic servers in this same isolated process; no external upstreams.
frontend mock_api
bind 127.0.0.1:9101
http-request return status 200 content-type text/plain string ready if { path /readyz }
http-request return status 200 content-type text/plain lf-string "api xff=%[req.hdr(X-Forwarded-For)] forwarded=%[req.hdr(Forwarded)] real=%[req.hdr(X-Real-IP)] proto=%[req.hdr(X-Forwarded-Proto)] host=%[req.hdr(X-Forwarded-Host)] port=%[req.hdr(X-Forwarded-Port)] prefix=%[req.hdr(X-Forwarded-Prefix)]"
frontend mock_web
bind 127.0.0.1:9102
http-request return status 200 content-type text/plain string ready if { path /readyz }
http-request return status 200 content-type text/plain string web
frontend mock_redirect
bind 127.0.0.1:9103
http-request return status 302 hdr Location /login
frontend mock_unready
bind 127.0.0.1:9104
http-request return status 503 content-type text/plain string not-ready
backend default_http_redirect
option httpchk GET /readyz
server redirect 127.0.0.1:9103 check inter 200ms fall 2 rise 2
backend strict_http_redirect
option httpchk GET /readyz
http-check expect status 200
server redirect 127.0.0.1:9103 check inter 200ms fall 2 rise 2
backend tcp_unready
server unready 127.0.0.1:9104 check inter 200ms fall 2 rise 2
backend http_unready
option httpchk GET /readyz
http-check expect status 200
server unready 127.0.0.1:9104 check inter 200ms fall 2 rise 2
構文確認と機能確認を分ける
コンテナ内の設定配置先を/labとした場合の読取検査です。-cは設定を検査して終了し、通常の待受起動はしません。成功してもバックエンドへの接続・TLS・実トラフィックの動作保証にはなりません。
# Read-only validation inside the dedicated lab container; no service reload.
haproxy -vv
haproxy -c -f /lab/haproxy.cfg -f /lab/fixtures.cfg
次も同じ専用コンテナ内だけで実行する機能確認です。BusyBoxのsh/wget/grep/base64を使い、実サーバーや公開IPへは接続しません。設定検査とは別に、起動後の応答を検査します。
# Run only INSIDE the dedicated network-none lab after both config files load.
set -eu
base=http://127.0.0.1:8080
auth="Authorization: Basic $(printf '%s' 'lab:public-lab-only' | base64)"
attempt=0
until wget -q -O - "$base/api" | grep -q '^api xff=127.0.0.1'; do
attempt=$((attempt + 1))
test "$attempt" -lt 20
sleep 1
done
for path in /api /api/ /api/users '/api?x=1'; do
wget -q -O - "$base$path" | grep -q '^api xff=127.0.0.1'
done
for path in / /apix /apiary /API; do
test "$(wget -q -O - "$base$path")" = web
done
body=$(wget -q -O - --header 'X-Forwarded-For: 203.0.113.77' \
--header 'Forwarded: for=203.0.113.77' \
--header 'X-Real-IP: 203.0.113.77' \
--header 'X-Forwarded-Host: evil.invalid' \
--header 'X-Forwarded-Port: 9' \
--header 'X-Forwarded-Prefix: /evil' \
--header 'X-Forwarded-Proto: https' "$base/api")
test "$body" = 'api xff=127.0.0.1 forwarded= real= proto=http host= port= prefix='
denied=$(wget -S -O - http://127.0.0.1:8404/stats 2>&1 || true)
printf '%s' "$denied" | grep -q 'HTTP/1.1 401'
csv=$(wget -q -O - --header "$auth" 'http://127.0.0.1:8404/stats;csv')
printf '%s' "$csv" | grep -q '^# pxname,svname,'
test "$(wget -q -O - "$base/stats")" = web
printf '%s\n' 'PASS loopback routing, forwarded identity and stats authentication'
専用テストは同じ2設定で新規プロセスを起動し、コンテナ内のHTTPだけで以下を確認します。一般のHAProxyサービスを停止/再起動せず、検査後はテスト自身が作ったコンテナだけを除去します。
| 入力・観測 | この教材の期待結果 |
|---|---|
| /api、/api/、/api/users、/api?x=1 | APIへ。pathはqueryを含まない |
| /apix、/apiary、/API、/ | Webへ。大文字小文字を区別する |
| 偽のX-Forwarded-For / Forwarded / X-Real-IP | 申告値を除去し、直接の接続元127.0.0.1をX-Forwarded-Forへ上書き |
| /statsの未認証・誤認証 / 合成認証 | 401 / 200。外部向けポートなし |
| HTTP検査の302 / expect status 200での302 | 既定ではUP / 明示200ではDOWN |
| 503を返すHTTPサーバへのTCP検査 / HTTPで200限定検査 | TCP接続だけならUP / HTTP検査ではDOWN |
/api境界はここでは正規化していないpath文字列に対する判定です。%2F、連続スラッシュ、アプリ独自のURL正規化や認可まで安全と保証しません。前後の層でURL解釈を揃え、APIの認証・認可は別に実装します。
readinessと可用性の限界
checkだけは通常TCP接続検査で、HTTPが200を返すこととは異なります。option httpchkの既定の成功は2xxと3xxなので、認証画面への302でも正常扱いになり得ます。本例はGET /readyz・HTTP/1.1・Hostとexpect status 200を指定しています。実アプリではreadinessが何を確認するか、仮想HostやTLSの条件、検査の負荷とtimeoutを決めます。200でも依存DB・書込み・全機能の成功を意味するとは限りません。
fall/riseは連続失敗/成功による判定に関わります。DOWN検知には時間がかかり、既存接続や失敗した要求を必ず別サーバーでやり直せるわけではありません。再送は注文等の重複実行を招き得ます。本例は各backendが1台なので、故障時の代替先はなく503になり得ます。実LB冗長化・フェイルオーバー・無停止は未検証です。
転送元IPと運用変更の境界
IP以外の申告もそのまま信頼しません。このHTTP検体はX-Forwarded-Host / Port / Prefixを除去し、X-Forwarded-Protoを実際のhttpに固定します。Host自体の許可検査やアプリのURL生成規則は別に必要です。前段TLS終端やpath変換を追加する場合は、信頼する層と受渡すヘッダーの規約を再設計します。
新例はHAProxyへクライアントが直接接続する前提で、転送元ヘッダーを除去/上書きします。CDN等の前段がある場合、このままではCDNのIPになります。許可した中継元だけから受ける設計、ヘッダーの付与/解釈規約とアプリの信頼設定を合わせ、外部申告の左端IPを無条件に採用しません。TLSや認証を本例が自動付加するわけでもありません。
reloadは配布環境のunitやmaster-worker構成によって反映方法が異なり、restartと同義ではありません。対象ファイルの退避、同じ起動引数での構文検査、承認、反映後の応答/ログ/プロセス確認、切戻しを事前に計画します。この隔離試験では実サービスのreload/restartや旧版の公開statsへアクセスしていません。
比較表を読むとき
HAProxy 3.2にはhttp-request returnのstring/file等で固定応答を返す機能があります。「静的ファイルを一切返せない」とは言えません。ただし汎用Webサーバーの静的配信機能と同一ではありません。nginxとの優劣や固定の処理性能をこの小さな教材から推定しないでください。
公式資料と確認範囲(2026年10月26日)
HAProxy公式の保守ブランチ一覧で3.2 LTSを確認。対象ブランチのHTTP検査、成功条件、path、転送元ヘッダー、統計認証、固定応答、構文検査・プロセス管理を参照しました。検証は隔離した合成HTTPだけで、本番ネットワーク、OSのsystemd、TLS、実アプリのreadiness、性能の試験ではありません。
| この記事の要点 |
|
概要
HAProxy (High Availability Proxy) は、TCP および HTTP に対応した高性能なロードバランサ兼リバースプロキシです。Webサービス等の入口で利用できますが、導入だけで処理性能や無停止を保証するものではありません。ロードバランサ としても リバースプロキシ としても機能し、L4 (TCP) と L7 (HTTP) の両方の振り分けに対応します。親項目は 負荷分散・プロキシ・CDN です。
nginx がリバースプロキシ + 静的配信に強いのに対し、HAProxy は負荷分散と振り分けに特化しており、ヘルスチェック・きめ細かい ACL・充実した統計画面など、ロードバランサとしての機能が豊富なのが特徴です。
仕組み
HAProxy の設定は、役割ごとに分かれたセクションで構成されます。中核となるのは frontend と backend です。
- global: プロセス全体の設定 (最大接続数・ログ出力・実行ユーザなど)。
- defaults: frontend/backend 共通の既定値 (タイムアウト・モードなど)。
- frontend: クライアントからの受け口。どのアドレス:ポートで待ち受け、どの条件でどの backend へ渡すかを定義する。
- backend: 振り分け先のサーバ群。分散アルゴリズム (
roundrobin/leastconn等) とヘルスチェックを定義する。
frontend では ACL (Access Control List) を使って「このパスなら」「このヘッダなら」という条件を定義し、条件に応じて送り先の backend を切り替えられます。server行のcheck等で検査を有効にした送り先は、設定した失敗/成功回数でDOWN/UPを判定します。検知前や処理途中の要求、残存容量、セッションやDBの状態によっては失敗が続きます。自動フェイルオーバーや無停止を保証する機能ではありません。
設定・実用例
次の旧設定は保存用で、本番へコピー・実行しないでください。bind *:8404 は全アドレス待受で認証もなく、統計情報を露出します。bind *:80 も無制限の待受です。path_beg /api は /apix や /apiary も一致し、/api とその配下だけという意図とは異なります。API側のHTTP検査は既定で2xx/3xxを許可し、Web側のcheckだけではTCP接続検査です。「先に試す隔離用の完成設定(HAProxy 3.2)」を参照し、旧アドレスへ接続しないでください。
global
maxconn 20000
log /dev/log local0
defaults
mode http
timeout connect 5s
timeout client 30s
timeout server 30s
# 受け口
frontend http_in
bind *:80
# ACL: パスが /api で始まるか判定
acl is_api path_beg /api
# 条件に応じて backend を切り替え
use_backend api_servers if is_api
default_backend web_servers
# API サーバ群 (最小接続方式 + ヘルスチェック)
backend api_servers
balance leastconn
option httpchk GET /healthz
server api1 10.0.0.31:8000 check
server api2 10.0.0.32:8000 check
# Web サーバ群 (ラウンドロビン + 重み付け)
backend web_servers
balance roundrobin
server web1 10.0.0.41:80 check weight 3
server web2 10.0.0.42:80 check weight 1
# 統計画面 (運用監視用)
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 5s
次の旧コマンドも保存用で、そのまま本番実行しないでください。reloadはrestart(停止して起動)ではありません。実サービスのunit・起動引数・対象ファイルとreloadの実装を確認し、退避・構文検査・承認後の反映・新旧プロセス/実応答の確認・切戻しを分けます。構文成功だけでは到達性や無停止を証明できません。この教材ではsystemctlも本番reload/restartも実行しません。
# 設定ファイルの構文チェック
haproxy -c -f /etc/haproxy/haproxy.cfg
# 反映 (systemd 環境)
sudo systemctl reload haproxy
旧手順の http://<HAProxyのIP>:8404/stats は外部アクセス先として使用しません。統計は接続数・状態・累積エラーカウンタ等を示しますが、カウンタを時間で割らずにエラー率と読み替えないでください。
主な用途
- 大規模な負荷分散: 複数バックエンドへ要求を分散する。実効性能はTLS・接続特性・アプリ等を含めて測定する。
- TCP レベルの中継 (L4): HTTP 以外 (データベース接続・MQ など) も
mode tcpで負荷分散できる。 - 条件付きルーティング: ACL でパス・ホスト・ヘッダ別に backend を切り替える。
- 高可用性: ヘルスチェックで故障機を自動切り離しし、サービス継続性を高める。
- 運用監視: 統計画面で接続状況・サーバ状態を可視化し、障害の早期発見に使う。
nginx との比較
| 観点 | HAProxy | nginx |
|---|---|---|
| 得意分野 | 負荷分散・振り分けに特化 | リバプロ + 静的配信 |
| 対応レイヤ | L4 (TCP) / L7 (HTTP) | 主に L7 (HTTP) ※stream で L4 も可 |
| ヘルスチェック | TCP接続検査・HTTP検査等を設定で選ぶ | 版・module・Open Source/Plusで検査方式を確認 |
| 統計画面 | 標準で stats 画面あり | 標準は簡易 (status のみ) |
| 静的配信 | http-request returnで固定応答やfile指定が可能。汎用静的Webサーバとの用途・制限は別途比較 | 得意 |
注意点
- 統計画面の保護:
/statsは内部情報を晒すため、認証・アクセス元制限を必ずかける。外部公開は厳禁。 - タイムアウトの設定漏れ:
timeoutを適切に設定しないと、滞留したコネクションがリソースを食い潰す。 - SSL 終端の負荷: HAProxy で TLS 終端する場合は CPU 負荷が上がる。証明書と暗号スイートの選定に注意する。
- クライアント IP の引き継ぎ:
option forwardforはヘッダー付与であって送信元の真正性を保証しない。外部入力を信頼せず、信頼する中継元・上書きする層・アプリのtrusted proxyとバックエンドへの到達制限を合わせる。 - 単一障害点: HAProxyが1台なら入口自体が単一障害点になり得る。複数LB、VIP/経路の切替、障害検知、残存容量、データとセッションの継続を別々に設計する。keepalived等を置くだけで切替成功や無停止を保証しない。
関連リンク
子ページはありません
- フォワードプロキシ
- リバースプロキシ
- ロードバランサ
- nginxリバースプロキシ設定
- HAProxy
- CDN
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Django REST FrameworkでAPIを作る|URL接続・入力検証・所有者の認可 2026-10-25 21:03:21
- DjangoモデルをJSONで返す|型・公開フィールド・DRF認可 2026-10-25 20:46:35
- precompile standard library とは(Pythonインストール) 2026-10-25 20:30:17
- ANACONDA NAVIGATORの起動方法 2026-10-25 20:30:17
- DjangoのAjax POST|CSRF・JSON入力検証・DRFの認可 2026-10-25 20:30:16
- Django/MySQLのUnknown column ...id|主キー・実列・別名の確認 2026-10-25 20:08:53
- 【django】limit, offsetの指定方法 2026-10-25 20:08:51
- Djangoの本番で変更が反映されないとき|プロセス・テンプレート・静的配信の確認 2026-10-25 19:40:35
- Django のファイルアップロード|ファイル名と拡張子の取得 2026-10-25 19:40:35
- djangoにおけるHTTPステータスコードの返し方 2026-10-25 19:40:34
- PythonのResponseオブジェクトの中身の確認 2026-10-25 19:17:54
- Python で Cookie を扱う|requests の Session と http.cookies 2026-10-25 19:17:54
- Python で HTTP リクエスト|requests・urllib・httpx と curl の対応 2026-10-25 19:17:53
- Django で SQL ログを出力する方法|django.db.backends と N+1 の発見 2026-10-25 18:59:32
- djangoにおけるログのローテート設定【Python】 2026-10-25 18:59:31