Quantcast
Channel: https – Gea-Suan Lin's BLOG
Viewing all articles
Browse latest Browse all 267

用 Caddy 在同一個 Port 同時服務網站與 HTTPS Proxy

$
0
0

目標是希望把 Port 443 同時用在 HTTPS 網站以及 HTTPS Proxy (i.e. 瀏覽器到 Proxy 中間有加密的協定),其中 HTTPS Proxy 是跑 Squid,本來是用 nginx 做這件事情 (透過 ngx_stream_ssl_preread_modulessl_preread_server_name 判斷 hostname),但遇到了 nginx 無法動態決定是否要啟用 proxy_protocol 的問題:「How to set the proxy_protocol to 'on' in a conditional manner in nginx?」,不確定是 bug 還是 feature。

第二個問題是 Squid 對 proxy protocol 的支援是透過 require-proxy-header 指定在 http_port 上的,而 https_port 不支援這個參數,也就是說在配合這個情境下,如果還想讓 Squid 可以記錄正確的 IP address 資訊,就需要讓 nginx 解 TLS,用 HTTP Proxy 協定丟進 Squid,這個也就是 TLS termination。

最後遇到的問題是 nginx 這邊的「網站端 vhost」會記錄到錯誤的 IP address,永遠是 127.0.0.1,這個問題卡了一年多沒解我就放掉了,剛好發現 Raspbery Pi 3B 上面跑的是 32-bit 版的 OS,就想說趁著重裝 64-bit 版的 OS 後改用 Caddy

Caddy 這邊目前是透過 github.com/mholt/caddy-l4 這個模組實作「讀取 TLS SNI 資訊決定後續行為」,我是透過 xcaddy 編譯 Caddy 裝起來的,裝好後需要的設定是這樣:

        layer4 {
                :443 {
                        @proxytwhinet tls sni proxy-tw-hinet.gslin.com
                        route @proxytwhinet {
                                tls {
                                        connection_policy {
                                                alpn http/1.1
                                        }
                                }
                                proxy {
                                        proxy_protocol v1
                                        upstream 127.0.0.1:3128
                                }
                        }

                        route {
                                proxy {
                                        proxy_protocol v1
                                        upstream 127.0.0.1:444
                                }
                        }
                }
        }
        servers 127.0.0.1:444 {
                listener_wrappers {
                        proxy_protocol {
                                allow 127.0.0.1/32
                                fallback_policy require
                        }
                        tls
                }
        }

看到 proxy-tw-hinet.gslin.com 後往 127.0.0.1:3128 丟,其他的都往 127.0.0.1:444 丟。

這邊有個比較特別的是針對 proxy-tw-hinet.gslin.com 要強制走 HTTP/1.1 協定,這是因為 Squid 這端的 http_port 不吃 HTTP/2,而 Firefox 連 HTTPS Proxy 時讀到 Caddy 透過 ALPN 說可以用 h2,於是就不會通,所以針對這個 domain 我只收 HTTP/1.1。

再來就是網站的部分,127.0.0.1:444 都要吃 proxy protocol 的 IP address 資訊。

而每個網站實際定義的部分則是這樣,裡面把不相關的設定都刪掉了:

proxy-tw-hinet.gslin.com:444 {
        tls caddytls@gslin.com
        [...]
}

rent-hinet.gslin.com:444 {
        tls caddytls@gslin.com
        [...]
}

接下來是 Squid 這邊,主要就是 require-proxy-header 以及允許哪些來源的 IP address 才是合法的:

http_port 3128 require-proxy-header
proxy_protocol_access allow localhost

當初就只差記錄正確的 IP address,為了做到改下去這包工程好大,但總算是都搞定了...


Viewing all articles
Browse latest Browse all 267

Latest Images

Trending Articles