ぷるぷるした直方体

元職業エンジニアの雑記です

Dockerでlocalhostにhttpsアクセスできるプロキシを立てる

OAuthが絡むアプリケーションを開発していると、時折 https://localhost/ でローカルのアプリケーションサーバーにアクセスをしたくなる状況があります。セキュリティ上、リダイレクト先URLの指定が必要で、かつhttpsしか設定できない場合があるためです。

ローカルにプロキシサーバーを立てて解決する手法がありますが、調べてみた限り設定が必要で、かつ手元の環境を汚してしまうものでした。(部屋はともかく)PC内環境美化に力を入れている私としては、何とか余計なインストールは避けたいところ。

そこで、Dockerを使ってSSL Terminationをするプロキシを作成しました。環境を汚さないだけでなく、初回は30秒程度、二回目以降は1秒程度と高速にセットアップすることが可能です。GitHubおよびDockerHubで公開していますので、需要がある方はご利用ください。

github.com

https://hub.docker.com/r/esplo/docker-local-ssl-termination-proxy/hub.docker.com

使い方は簡単ですが、IPの取得箇所はOSに依存しています。ご利用の環境に併せて叩き分けてください。下記のコマンドは、ポート3000番で動いているローカルアプリケーションへのプロキシを作成する場合です。

Mac OSX

docker run -it \
  -e "HOST_IP=`ipconfig getifaddr en0`" \
  -e "PORT=3000" \
  -p 443:443 \
  --rm \
  esplo/docker-local-ssl-termination-proxy

Linux

docker run -it \
  -e "HOST_IP=`hostname -I | awk '{print $1}'`" \
  -e "PORT=3000" \
  -p 443:443 \
  --rm \
  esplo/docker-local-ssl-termination-proxy

Windowsは?

Pull Request、お待ちしております。

以下はこのDockerイメージを作った原因や、どのようにできているかの説明です。

簡単にはhttpsでアクセスできない

ローカルサーバーにhttpsでアクセスできるようにするには、証明書を作ったり、https用の設定をしてあげないといけません。一般的な開発用サーバーはhttpで立ち上がるため、この手順は手間です。

NginxやApacheでプロキシを立てて、localhostにhttpsでアクセス

localhostにhttpsでアクセスしたい時、よく使われるのは「ホストマシンに(直に)NginxやApacheを立てる」という方法です。もちろん実現できますが、このためだけにNginxをインストールする必要があったり、手順が複雑だったり、起動しているかどうか分からなかったりします。Dockerが無い頃は私もよくやってました。

このような課題は、Dockerを使ってブラックボックスにすることで上手く解決できます。しかも起動が高速で分かりやすいため、開発意欲を削がれずに済みます。

Docker内で立てたNginxプロキシの問題点

問題となるのは、Nginxの設定ファイルに、如何にしてホストのIPを埋め込むか という点です。

1点目の厄介は(Dockerコンテナからホストネットワークへアクセスするための)IPの取得です。Docker for Macでは、ネットワークモードがhostだとホストマシンからlocalhostでアクセスができません 1 。結果、bridgeモードでホストのIPを渡す、という手法を取る必要があります。ホストIPはDockerコンテナ内からは取得できないため、起動時に環境変数として渡します。

2点目の厄介は、Nginxの設定ファイルは環境変数を使うように出来ていない、ということです。ありがたいことに、こちらのドキュメントでenvsubstコマンドを使った方法について解説されています。

qiita.com

この方法を利用して環境変数を埋め込みます。他の点に関しては、普通にホストローカルにプロキシサーバーを立てるのと変わりません。

コードの解説

非常にシンプルなので不要な気もしますが、リポジトリのファイルに沿って流れを説明します。

github.com

普通のDockerfile

Nginxを使った、普通のSSL Termination Proxyです。 Nginxの設定ファイルは、image内ではまだテンプレートです。 実際の起動時にentrypoint.shを呼び出すことで、envsubstにより環境変数を置換して本来の設定ファイルになります。

nginx.confでは環境変数名を書いておく

nginx.confでは以下のように、環境変数混じりの指定をしています。 この部分がentrypoint.shで置換されます。実際の設定は極めて単純で、443から指定のポートに転送をするだけです。

http {
  ...
  upstream app {
    server ${HOST_IP}:${PORT};

envsubstを使ってnginx.confを置換する

entrypoint.shでenvsubstを使って置換し、その設定ファイルを使ってNginxを起動します。

envsubst '$$PORT$$HOST_IP' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
nginx

まとめ

簡単にhttps://localhost/にアクセスするためのDockerイメージを作成しました。これを使って労力を抑えて、本来の目的であるアプリケーション開発を楽しんでください。

MacとLinuxで共通してIPを取得するコマンド、ご存知の方はPRください!


  1. 未検証ですが、Linuxなら可能だと思います