HAProxyの設定|haproxy.cfgの書き方とヘルスチェック
HAProxy(エイチエープロキシ)は、TCP と HTTP のロードバランサー(複数のサーバーに通信を振り分ける仕組み)です。設定ファイル haproxy.cfg は、global・defaults・frontend(受け口)・backend(振り分け先)の4つの部分で書きます。
frontend web
bind :80
default_backend app
backend app
balance roundrobin
option httpchk GET /health
server app1 10.0.0.11:8080 check
server app2 10.0.0.12:8080 check
check を付けたサーバーは、ヘルスチェックに失敗すると振り分け先から外れます。 手元で inter 1s fall 2(1秒ごと・2回失敗で外す)にして1台の /health を 503 にすると、約1.6秒で外れ、残りの台だけに振り分けられました。
| 確かめたこと | 結果 |
|---|---|
balance roundrobin(3台) |
app1 → app2 → app3 → app1 … の順 |
1台の /health を 503 に |
約1.6秒で DOWN。残り2台に振り分け |
/health を 200 に戻す |
約1.7秒で UP(rise 2) |
| 全台が使えない | 503 Service Unavailable(No server is available…) |
check なしで止まった台に当たる |
約3秒後に 503(3回の再試行) |
確認環境:HAProxy 2.8.16(Ubuntu 24.04 の apt パッケージ 2.8.16-0ubuntu0.24.04.3)を動かし、裏のサーバーには Python の HTTP サーバーを3台立てて確かめました。既定値とキーワードの意味は、HAProxy 2.8 の Configuration Manual で確かめています(確認日 2026年10月13日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「HAProxyの設定|haproxy.cfgの書き方とヘルスチェック」
インストールと版
sudo apt install haproxy
haproxy -v
# HAProxy version 2.8.16-0ubuntu0.24.04.3 2026/06/19 - https://haproxy.org/
# Status: long-term supported branch - will stop receiving fixes around Q2 2028.
Ubuntu 24.04 の apt で入るのは 2.8 系で、haproxy -v の表示では長期サポート(LTS)の版です。設定ファイルは /etc/haproxy/haproxy.cfg に置かれ、systemctl reload haproxy で読み直します。
| コマンド | すること |
|---|---|
haproxy -c -f haproxy.cfg |
設定の検査(Configuration file is valid) |
haproxy -f haproxy.cfg |
前面で起動 |
haproxy -f haproxy.cfg -sf <旧PID> |
新しい設定で起動し、旧プロセスを終わらせる(無停止の入れ替え) |
systemctl reload haproxy |
systemd で入れたときの再読み込み |
haproxy -vv |
ビルドオプション(OpenSSL・Lua・QUIC など)の表示 |
haproxy.cfg の完成形
動かした設定です。ポートは確認用に 47280 などにしています。
global
log stdout format raw local0 info
stats socket /run/haproxy/admin.sock mode 600 level admin
maxconn 2000
defaults
mode http
log global
option httplog
option forwardfor
timeout connect 5s
timeout client 30s
timeout server 30s
frontend web
bind 127.0.0.1:47280
acl is_api path_beg /api
use_backend api_servers if is_api
default_backend web_servers
backend web_servers
balance roundrobin
option httpchk
http-check send meth GET uri /health
http-check expect status 200
default-server inter 1s fall 2 rise 2
server app1 127.0.0.1:47201 check
server app2 127.0.0.1:47202 check
server app3 127.0.0.1:47203 check
backend api_servers
balance leastconn
server app1 127.0.0.1:47201 check
server app2 127.0.0.1:47202 check
listen stats
bind 127.0.0.1:47284
stats enable
stats uri /stats
stats refresh 5s
stats auth admin:changeme
4つのセクションの役割
| セクション | 役割 | 主な設定 |
|---|---|---|
global |
プロセス全体 | log・maxconn・stats socket・user・daemon |
defaults |
以降の frontend・backend の既定 | mode・timeout・option httplog |
frontend |
受け口(どのポートで受けるか) | bind・acl・use_backend・default_backend |
backend |
振り分け先(どのサーバーへ送るか) | balance・server・option httpchk |
listen |
frontend と backend を1つにまとめたもの | stats ページなどに使う |
defaults の timeout は必ず書く
timeout を書かずに haproxy -c を通すと、次の警告が出ました。
[WARNING] (5496) : config : missing timeouts for frontend 'f'.
| While not properly invalid, you will certainly encounter various problems
| with such a configuration. To fix this, please ensure that all following
| timeouts are set to a non-zero value: 'client', 'connect', 'server'.
| timeout | 意味 |
|---|---|
timeout connect |
裏のサーバーへの接続を待つ時間 |
timeout client |
クライアントからのデータを待つ時間(無通信) |
timeout server |
裏のサーバーからの応答を待つ時間(無通信) |
timeout http-request |
HTTP リクエストのヘッダーを受け取り終わるまでの時間 |
timeout check |
ヘルスチェックの応答を待つ追加の時間 |
ACL でパスごとに振り分ける
acl 名前 条件 で条件に名前を付け、use_backend 振り分け先 if 名前 で使います。今回は /api で始まるパスを api_servers に送りました。
acl is_api path_beg /api
acl is_admin hdr(host) -i admin.example.com
use_backend api_servers if is_api
use_backend admin_servers if is_admin
default_backend web_servers
| よく使う条件 | 当たるもの |
|---|---|
path_beg /api |
パスが /api で始まる |
path_end .jpg |
パスが .jpg で終わる |
path -m reg ^/v[0-9]+/ |
正規表現 |
hdr(host) -i example.com |
Host ヘッダー(-i は大文字小文字を区別しない) |
src 10.0.0.0/8 |
接続元 IP |
method POST |
HTTP メソッド |
balance(振り分け方)の一覧
HAProxy 2.8 の Configuration Manual に載っているアルゴリズムです。
| balance | 振り分け方 | 向いている場面 |
|---|---|---|
roundrobin |
重みに従って順番に(重みを動的に変えられる) | 一般的な Web |
static-rr |
順番に(重みは起動時に固定) | 台数が多いとき |
leastconn |
接続数がいちばん少ない台 | 長い接続(DB・WebSocket) |
first |
空きのある先頭の台から詰める | 台数を減らしたいとき |
source |
接続元 IP のハッシュで固定 | Cookie を使えないとき |
uri |
URI のハッシュで固定 | キャッシュサーバー |
url_param <名前> |
URL パラメーターの値で固定 | ユーザー ID で固定 |
hdr(<名前>) |
ヘッダーの値で固定 | |
random / random(<回数>) |
ランダム(複数回引いて空いている台) | 台数が多いとき |
rdp-cookie |
RDP の Cookie で固定 | リモートデスクトップ |
hash <式> |
任意の式のハッシュで固定 |
roundrobin の web_servers に6回送ると app1 app2 app3 app1 app2 app3、leastconn の api_servers に1つずつ送ると app1 app2 app1 app2 … でした。
打ち間違えると、haproxy -c で次のエラーになりました。
[ALERT] (5493) : config : parsing [b.cfg:10] : balance only supports 'roundrobin', 'static-rr', 'leastconn', 'source', 'uri', 'url_param', 'hdr(name)' and 'rdp-cookie(name)' options.
ヘルスチェックの書き方
TCP チェックと HTTP チェック
server 行に check だけを書くと、TCP で接続できるかだけを見ます。 option httpchk を足すと、HTTP のリクエストを送り、ステータスコードで判定します。
| 書き方 | 確かめる内容 | stats の表示 |
|---|---|---|
server … check だけ |
TCP で接続できるか | L4OK |
option httpchk + check |
HTTP の応答(既定は 2xx・3xx が正常) | L7OK(200) |
+ http-check expect status 200 |
200 のときだけ正常 | L7OK |
+ http-check expect string OK |
本文に OK が含まれるか |
L7OK |
マニュアルでは、option httpchk を引数なしで書くと OPTIONS / HTTP/1.0 を送ります。ヘルスチェック用のパスを決めているなら、次のどちらかで書きます。
# 書き方1(http-check send)
option httpchk
http-check send meth GET uri /health ver HTTP/1.1 hdr Host app.example.com
http-check expect status 200
# 書き方2(1行で)
option httpchk GET /health
inter・fall・rise(間隔と回数)
| キーワード | 意味 | 既定値(マニュアル) |
|---|---|---|
inter |
チェックの間隔 | 2000ms(2秒) |
fall |
何回続けて失敗したら DOWN にするか | 3 |
rise |
何回続けて成功したら UP に戻すか | 2 |
fastinter |
状態が変わりかけているときの間隔 | 未設定なら inter |
downinter |
DOWN の台を見る間隔 | 未設定なら inter |
既定のままだと、DOWN になるまで最大でおよそ inter × fall = 6秒かかる計算です。default-server に書くと、その backend の全 server に効きます。
実測:台を落として、振り分けが変わるまで
inter 1s fall 2 rise 2 で、app2 の /health だけ 503 を返すようにしました。管理ソケットの show stat を0.25秒ごとに見た結果です。
15:49:24.916 /health を 503 に切り替え
15:49:24.947 UP
15:49:26.531 DOWN ← 約1.6秒
そのときのログです。理由(Layer7 wrong status)と、残りの台数が出ます。
[WARNING] (3823) : Server web_servers/app2 is DOWN, reason: Layer7 wrong status, code: 503, info: "Service Unavailable", check duration: 0ms. 2 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
DOWN のあとは app3 app1 app3 app1 … と、2台だけに振り分けられました。/health を 200 に戻すと、約1.7秒(rise 2)で UP に戻り、3台の順番に戻りました。
一方、TCP チェックだけの api_servers の app2 は UP のままで、振り分けも続きました。 アプリが 503 を返していても、TCP の接続はできるからです。アプリの状態で外したいときは option httpchk が要ります。
プロセスごと止めたときは、理由が変わりました。
[WARNING] (3823) : Server web_servers/app3 is DOWN, reason: Layer4 connection problem, info: "Connection refused", check duration: 0ms. 2 active and 0 backup servers left.
| ログの reason | 意味 | stats の check_status |
|---|---|---|
Layer7 wrong status, code: 503 |
HTTP のステータスが期待と違う | L7STS |
Layer4 connection problem, info: "Connection refused" |
ポートが閉じている(プロセス停止) | L4CON |
Layer4 timeout |
応答がない(ネットワーク・高負荷) | L4TOUT |
アプリ側の /health に何を返させるかは、関連記事「ヘルスチェック設計|livenessとreadinessの違いと実装例」で扱っています。
全台が使えないとき
全台が DOWN または保守中(MAINT)だと、HAProxy 自身が 503 を返しました。
HTTP/1.1 503 Service Unavailable
content-length: 107
cache-control: no-cache
content-type: text/html
<html><body><h1>503 Service Unavailable</h1>
No server is available to handle this request.
</body></html>
ログでは、サーバー名が <NOSRV> になります。
127.0.0.1:54032 [13/Oct/2026:15:49:41.099] web web_servers/<NOSRV> 0/-1/-1/-1/0 503 217 - - SC-- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
backup を付けた予備の台を置くと、通常の台が全部落ちたときだけ使われます。
server app1 10.0.0.11:8080 check
server app2 10.0.0.12:8080 check
server sorry 10.0.0.99:8080 check backup
check なしで止まった台に当たると、約3秒待たされた
check を付けない backend に、止まっている台(dead)を混ぜました。
| 設定 | 止まった台に当たったリクエスト |
|---|---|
check なし |
3,009ms 待って 503。ログの再試行回数は 3 |
check なし + option redispatch |
すぐ 200。ログの再試行欄は +1(別の台に振り直した印) |
127.0.0.1:39156 [13/Oct/2026:15:49:54.445] web3 nocheck_servers/dead 0/0/-1/-1/3009 503 217 - - SC-- 1/1/0/0/3 0/0 "GET / HTTP/1.1"
127.0.0.1:41694 [13/Oct/2026:15:50:10.505] web3 nocheck_servers/app1 0/0/0/4/4 200 212 - - ---- 1/1/0/0/+1 0/0 "GET / HTTP/1.1"
マニュアルでは、同じ台への再試行の前に min(timeout connect, 1秒) の待ち時間が入ります。既定の再試行は3回なので、約3秒です。check を付けておけば、止まった台は振り分け先から外れるので、この待ちは起きにくくなります。 option redispatch は、再試行のときに別の台へ振り直す設定です。
Cookie で同じ台に固定する(スティッキーセッション)
ログイン状態をサーバーのメモリに持つアプリでは、同じ利用者を同じ台に送り続けます。
backend sticky_servers
balance roundrobin
cookie SRVID insert indirect nocache
server app1 127.0.0.1:47201 check cookie a1
server app2 127.0.0.1:47202 check cookie a2
初回の応答に set-cookie: SRVID=a1; path=/ が付きました。Cookie を付けて4回送ると、4回とも同じ台でした。
| オプション | 意味(マニュアル) |
|---|---|
insert |
HAProxy が Cookie を足す |
indirect |
有効な Cookie を持つクライアントには出し直さない。裏へ送るリクエストからは Cookie を消す |
nocache |
Cookie を入れる応答をキャッシュさせない |
indirect を付けたので、裏のアプリが受け取ったリクエストには SRVID の Cookie がありませんでした。 アプリから見ると、HAProxy の Cookie は見えません。
stats ページ
listen stats の設定で、ブラウザから状態を見られます。
$ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:47284/stats
401
$ curl -s -u admin:changeme http://127.0.0.1:47284/stats | grep -o '<title>[^<]*'
<title>Statistics Report for HAProxy
URL の末尾に ;csv を付けると CSV で取れます。 監視の仕組みに取り込むときに使えます。先頭行は # pxname,svname,qcur,qmax,scur,… で、後で出てくる管理ソケットの show stat と同じ列でした。主な列を抜き出すと次のとおりです。
$ echo "show stat" | socat stdio /run/haproxy/admin.sock | cut -d, -f1,2,18,37,38
# pxname,svname,status,check_status,check_code
web,FRONTEND,OPEN,,
web_servers,app1,UP,L7OK,200
web_servers,app2,UP,L7OK,200
web_servers,app3,UP,L7OK,200
api_servers,app1,UP,L4OK,
| stats の設定 | 意味 |
|---|---|
stats uri /stats |
表示する URL |
stats auth ユーザー:パスワード |
Basic 認証 |
stats refresh 5s |
自動更新の間隔 |
stats admin if TRUE |
画面から台を保守中にできる(認証と組み合わせる) |
stats ページは管理用なので、bind を内部のアドレスに限るか、認証を付けます。
管理ソケットで台を保守中にする
global の stats socket … level admin で、実行中の HAProxy に命令を送れます。socat を使う例が多く、ここでは同じことを Python で送りました。
echo "set server web_servers/app1 state maint" | socat stdio /run/haproxy/admin.sock
echo "set server web_servers/app1 state ready" | socat stdio /run/haproxy/admin.sock
echo "show servers state" | socat stdio /run/haproxy/admin.sock
app1 を maint にすると、web_servers の振り分けは残りの台だけになり、ready で戻りました。デプロイのときに1台ずつ外す手順に使えます。
| 命令 | 意味 |
|---|---|
show stat |
stats と同じ内容を CSV で |
show servers state |
各サーバーの状態 |
set server <backend>/<server> state maint |
保守中(振り分けない) |
set server <backend>/<server> state drain |
新しい接続だけ止める |
set server <backend>/<server> state ready |
通常に戻す |
set server <backend>/<server> weight 50 |
重みを変える |
ログの読み方(option httplog)
127.0.0.1:48056 [13/Oct/2026:15:49:16.505] web web_servers/app1 0/0/0/1/1 200 212 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
| 部分 | 例 | 意味 |
|---|---|---|
| frontend・backend/server | web web_servers/app1 |
どこで受けて、どの台へ送ったか |
TR/Tw/Tc/Tr/Ta |
0/0/0/1/1 |
受信・待ち・接続・応答・合計の時間(ms)。-1 は到達せず |
| ステータス・バイト数 | 200 212 |
|
| 終了状態 | ---- / SC-- |
S=サーバー側が拒否・切断、C=接続待ちの段階 |
| 接続数・再試行 | 1/1/0/0/0 |
actconn/feconn/beconn/srv_conn/retries |
SC-- と Tc が -1 のときは、裏の台につながっていません。ポートの間違い・プロセスの停止を疑います。
よくあるエラー
| エラー | 原因 | 直し方 |
|---|---|---|
unable to find required default_backend: 'nobe' |
backend 名の打ち間違い | 名前を合わせる |
balance only supports 'roundrobin', … |
アルゴリズム名の打ち間違い | 一覧の名前にする |
missing timeouts for frontend |
timeout がない(警告) |
defaults に3つ書く |
503 No server is available to handle this request. |
全台 DOWN・MAINT | stats でチェック結果を見る |
3秒ほど待って 503(SC--、再試行 3) |
check なしで止まった台 |
check を付ける・option redispatch |
上の文面は、haproxy -c と curl で再現したものです。
よくある質問
Q. HTTPS はどう受けますか。
A. bind :443 ssl crt /etc/haproxy/certs/site.pem のように書きます。PEM には証明書と秘密鍵をまとめて入れます。HTTP から HTTPS へは、マニュアルの例にある redirect scheme https if !{ ssl_fc } で移せます。
Q. nginx と HAProxy はどちらを使えばいいですか。 A. 両方ともリバースプロキシとロードバランサーに使えます。HAProxy は振り分け・ヘルスチェック・stats・管理ソケットの機能が厚く、nginx は静的ファイルの配信や Web サーバーとしての機能を持ちます。nginx 側の設定は、関連記事「Nginxリバースプロキシ設定|proxy_passの書き方と502/504対処」で扱っています。
Q. AWS では ALB と HAProxy のどちらを使いますか。 A. ALB は AWS が運用するロードバランサーで、ヘルスチェックや振り分けの考え方は HAProxy と同じです。ALB の作り方は、関連記事「ALBをAWS CLIで作成|ターゲットグループ・リスナー・ルール設定」で扱っています。
Q. 設定を変えたら、つながっている接続は切れますか。
A. -sf <旧PID> で新しいプロセスを起動すると、旧プロセスは新しい接続の受付をやめ、処理中の接続を終えてから終了します。今回も新旧を入れ替えたあと、旧プロセスが終わっていました。
まとめ
haproxy.cfgは global・defaults・frontend・backend。defaultsに timeout を3つcheckだけは TCP のチェック。アプリの状態で外すならoption httpchk- 既定は
inter 2s・fall 3・rise 2。inter 1s fall 2で 約1.6秒で DOWN になった - 全台ダウンは 503
<NOSRV>。checkなしだと再試行で約3秒待って 503 - 同じ台への固定は
cookie … insert indirect nocache。stats は;csvで取り込める
参考・出典
確認日はいずれも 2026年10月13日です。
- HAProxy 2.8 Configuration Manual:https://docs.haproxy.org/2.8/configuration.html
- HAProxy 2.8 Management Guide(stats socket の命令):https://docs.haproxy.org/2.8/management.html
- HAProxy ドキュメント一覧:https://docs.haproxy.org/
- Ubuntu パッケージ haproxy(noble):https://packages.ubuntu.com/noble/haproxy
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「HAProxyの設定|haproxy.cfgの書き方とヘルスチェック」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。