httpアプリのhttps化は、haproxyが超絶便利
docker compose使ってると、複数コンテナの組み合わせだけで簡単に機能を構成出来ますよね。
http -> https のターミネーションには、 haproxy がめちゃ便利です。
以下はサンプルコードです。(https化そのものはこの記事のスコープ外としますのでまだの方、ぜひ使い方を調べてみてください。)
version: '3'
services:
haproxy:
image: haproxy:latest
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
- ./certs/haproxy.pem:/etc/ssl/private/haproxy.pem
ports:
- "80:80"
- "443:443"
depends_on:
- webapp
webapp:
image: your_webapp_image
ports:
- "8080:80"
global
log stdout format raw local0
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http-in
bind *:80
bind *:443 ssl crt /etc/ssl/private/haproxy.pem
redirect scheme https code 301 if !{ ssl_fc }
default_backend servers
backend servers
server webapp1 webapp:80 check
docker engine v26 以上に上げると動作しない?
無慈悲な画像ェ...
こっからそれはもうドツボにハマったのですが、まず解決策から
tl:dr; コンテナ内のデフォルトネットワーキングが IPV6になった!
散々迷路に入りながら色々調べたのですが、haproxy コンテナ内から各コンテナへの ping が通ることを確認して、ふと localhost に ping を打ったら...
docker exec -it mai-haproxy-1 bash
root@6272410af66d:/var/lib/haproxy# ping localhost
PING localhost(localhost (::1)) 56 data bytes
64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.038 ms
えっ (::1)
???
そうです、docker engine v26の何かの変更で、haproxyコンテナ内部のネットワーキングのデフォルトが ipv6 になったようで。
僕の環境では次のように、http
-> https
のリダイレクトを実装していたのですが、
この localhost:8080
の部分の通信が闇に吸われて行ってしました。
# http / https で二つのバックエンドを持つ
# 振り分けのために「このコンテナ内でのみ有効なポート」を使うループバックを二つ立ち上げる
backend http_back
mode tcp
server loopback-for-http localhost:8080
backend https_back
mode tcp
server loopback-for-https localhost:8443
こちらを、localhost
-> 127.0.0.1
に置き換えると、
最新の docker v26でも動作するようになりました!
# http / https で二つのバックエンドを持つ
# 振り分けのために「このコンテナ内でのみ有効なポート」を使うループバックを二つ立ち上げる
backend http_back
mode tcp
server loopback-for-http 127.0.0.1:8080
backend https_back
mode tcp
server loopback-for-https 127.0.0.1:8443
しばらく古いバージョンの docker に apt-mark hold
して対応していたのですが、
最新環境でも動くように修正できて良かったです!
この件、気づくまでマジでどツボりましたのでどなたかの役に立てば...