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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ
参加受付中

AI駆動開発、 無料セミナー