Anarchy In the 1K

NginxでHTTPS対応のフォワードプロキシを構築

 今回の記事の構成は、以下の通りです。構築方法は、「ハンズオン」に記載しています。

背景

 フォワードプロキシとしてNginxの利用を検討しているのですが、HTTPSの通信を行った際に以下のエラーが発生しました。

$ curl --proxy http://localhost:80 https://www.google.com/
curl: (56) Received HTTP code 400 from proxy after CONNECT

 調査の結果、NginxをHTTPS対応のフォワードプロキシとして利用する場合、別途パッチを当てる必要があるようです。その対応を行う際に、調べた内容を以下にまとめます。

調査結果

CONNECTとはなにか

 上述のエラーメッセージに含まれるCONNECTに関して、HTTPのメソッドの1つになります。CONNECTメソッドを用いると、フォワードプロキシが通信内容を意識せずに、クライアントとサーバ間の中継を行う様になります。具体的な通信の流れは以下を御覧ください。

CONNECTメソッドを用いたHTTPS通信の流れ

 How to Use NGINX as an HTTPS Forward Proxy Server - Alibaba Cloud Communityより
f:id:fujiU:20200328194449p:plain

以下の流れで通信が行われます。
(a). クライアントがフォワードプロキシにCONNECTリクエストを行う。
(b)-(c). フォワードプロキシが目的のサーバへのTCPコネクションを確立する。
(d). フォワードプロキシがクライアントへ200 OKを返却する。
(e). フォワードプロキシが、クライアントとサーバ間のHTTPS通信をそのまま中継する。

そもそも、なぜCONNECTメソッドが必要か

 HTTPSでは、HTTPの通信内容がSSLによって暗号化されています。その為、フォワードプロキシは通信内容を把握できず、送信先のサーバも知ることができません。
 そこで上述の流れの通り、CONNECTメソッドを用いることで、フォワードプロキシが通信内容を把握できずとも、クライアントとサーバ間の通信が可能になります。

エラー原因

 今回のエラーに関して、NginxがCONNECTメソッドに対応していないことが、発生の原因になります。

ハンズオン

概要

 Nginxに以下パッチを適用し、CONNECTメソッドを使用可能にします。
GitHub - chobits/ngx_http_proxy_connect_module: A forward proxy module for CONNECT request handling
 下記の「手順」では、Dockerを用いてCentOSのコンテナ上で、Nginxのソースコードを取得し、該当のパッチを適用し、動作確認を行うまでを記載しています。

手順

Nginxのソースコードを取得

$ docker run -it centos:centos7 /bin/bash

// 以降、CentOSのコンテナ内での操作
$ cd /var/tmp
$ yum install -y wget
$ wget http://nginx.org/download/nginx-1.9.2.tar.gz
$ tar -xzvf nginx-1.9.2.tar.gz

パッチを取得し適用

$ yum install -y git
$ git clone https://github.com/chobits/ngx_http_proxy_connect_module.git

$ yum install -y patch
$ cd nginx-1.9.2/
// patchコマンドを発行し、diffファイル(proxy_connect.patch)の内容を元に、ソースコードの書き換えを行う。
$ patch -p1 < /var/tmp/ngx_http_proxy_connect_module/patch/proxy_connect.patch

ソースコードコンパイルし起動

$ yum install -y gcc pcre pcre-devel openssl openssl-devel gd gd-devel
$ ./configure --add-module=/var/tmp/ngx_http_proxy_connect_module
$ make && make install
$ alias nginx=/usr/local/nginx/sbin/nginx
$ nginx

設定ファイルを修正し反映

 /usr/local/nginx/conf/nginx.confファイルのserverコンテキスト内の記載を、以下の通り追記・変更する。

...
http {
  ...
  server {
    listen       80;
    server_name  localhost;
    # ↓追記箇所
    resolver 8.8.8.8; # DNSサーバのIPアドレス
    proxy_connect;
    # ↑追記箇所
    ...
    location / {
      # ↓変更箇所(既存の記述は削除)
      proxy_pass $scheme://$http_host$request_uri;
      # ↑変更箇所
    }
    ...
  }
}
...

 その他の設定に関して、以下URIの「Directive」を御覧ください。
GitHub - chobits/ngx_http_proxy_connect_module: A forward proxy module for CONNECT request handling
 設定の反映の為に以下コマンドを発行します。

$ nginx -s reload

動作確認

 以下の通り、フォワードプロキシ経由でHTTPS通信を行った際に、結果が無事取得できることが確認できます。

$ curl --proxy http://localhost:80 https://www.google.com
<!doctype html><html itemscope=...