Docker Composeを使ってNginxのSSLリバースプロキシを起動する


Nginxのnginx.confではLuaなどを使わないと環境変数を読み込めません。Dockerのリンクを使う場合はコンテナの起動時に設定された環境変数をsedなどで置換する起動スクリプトを用意してnginx.conf使っていました。Docker Composeのlinksを使うとコンテナの/etc/hostsエントリを作成してくれます。

OpenResty

Nginxのリバースプロキシは後でLuaでHTTPヘッダの制御やAPIのアクセスコントロールをしたいのでOpenRestyを使います。Dockerイメージはtenstartups/openrestyがミニマルで良さそうです。

コンテナを個別に起動する場合

最初にDocker Composeではなく通常のDockerの使い方でリバースプロキシとHTTPサーバーをdocker runでそれぞれ起動します。
OpenRestyで使うSSL証明書はDockerホスト上に自己署名で作成します。

$ mkdir -p /opt/nginx/certs
$ cd /opt/nginx/certs
$ openssl genrsa -out server.key 4096
$ openssl req -new -batch -key server.key -out server.csr
$ openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt

nginx.confも同様にDockerホスト上に用意してコンテナの/opt/nginxディレクトリをコンテナにマウントします。proxy_passのプロキシ先はnode-staticのコンテナを用意します。node-staciはDockerホストにポートマップします。今回は確認用なのでDockerホストを固定で指定しておきます。

/opt/nginx/nginx.conf
daemon off;
worker_processes  1;

events {
    worker_connections  256;
}

http {
    server {
        listen 80;
        return 301 https://$host$request_uri;
    }

    server {

        listen 443;
        server_name www.example.com;

        access_log /proc/self/fd/1;
        error_log /proc/self/fd/2;

        ssl_certificate           /etc/nginx/certs/server.crt;
        ssl_certificate_key    /etc/nginx/certs/server.key;

       ssl on;
       ssl_prefer_server_ciphers on;
       ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
       ssl_ciphers "ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!EXPORT:!DES:!3DES:!MD5:!DSS";

        location / {
            proxy_set_header        Host $host;
            proxy_set_header        X-Real-IP $remote_addr;
            proxy_set_header        X-Forwarded-Host $host;
            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header        X-Forwarded-Proto $scheme;
            proxy_pass                 http://10.3.0.165:8080;
            proxy_redirect http:// https://;
        }
    }
}

HTTPサーバー (node-static)

node-staticのDockerイメージを用意します。

~/node_apps/node-static/Dockerfile
FROM google/nodejs-runtime
VOLUME /app/public

app.jsは8080ポートでLISTENして起動します。

~/node_apps/node-static/app.js
var static = require('node-static');
var file = new static.Server('./public');

require('http').createServer(function (request, response) {
    request.addListener('end', function () {
        file.serve(request, response);
    }).resume();
}).listen(8080);

console.log("Server running at http://localhost:8080");

package.jsonからnode-staticのパッケージをインストールします。

~/node_apps/node-static/package.json
{
  "name": "node-static-app",
  "description": "node-static app",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "node-static": "0.7.6"
  },
  "scripts": {"start": "node app.js"}
}

index.htmlはふつうのHello Worldです。

~/node_apps/node-static/public/index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>hello world</title>
  </head>
  <body>
   <p>hello world</p>
  </body>
</html>

node-staticのイメージをビルドして起動します。

$ cd  ~/node_apps/node-static/p
$ docker pull google/nodejs-runtime
$ docker build -t node-static .
$ docker run --name node-static \
  -d \
  -p 8080:8080 \
  -v $PWD/public:/app/public \
  node-static

openrestyのコンテナを起動します。

$ docker pull tenstartups/openresty
$ docker run --name nginx \
  -d \
  -p 80:80 \
  -p 443:443 \
  -v /opt/nginx:/etc/nginx \
  tenstartups/openresty

Dockerコンテナからcurlに--insecureフラグを付けてOpenRestyがSSLターミネーションとリバースプロキシが動作していることを確認します。

$ curl https://localhost --insecure
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>hello world</title>
  </head>
  <body>
   <p>hello world</p>
  </body>
</html>

Docker Composeを使う場合

次にDocker Composeを使って2つのコンテナをオーケストレーションしてみます。docker-compose.ymlを用意します。openrestyコンテナにnodestaticコンテナをリンクします。

~/node_apps/node-static/docker-compose.yml
nodestatic:
  restart: always
  build: .
openresty:
  restart: always
  image: tenstartups/openresty
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - /opt/nginx:/etc/nginx 
  links:
    - node-static

Docker Composeのlinksを使うとコンテナの/etc/hosts経由で名前解決できるようになります。nginx.confのプロキシ先のホスト名をDocker Composeでリンクしたコンテナの名前に変更します。

/opt/nginx/nginx.conf
            proxy_pass                 http://nodestatic:8080;

docker-composeコマンドから2つのコンテナをupします。

$ docker-compose up -d
Creating nodestatic_nodestatic_1...
Creating nodestatic_openresty_1...

以下のようにコンテナが起動しました。

$ docker-compose ps
         Name                     Command                    State                     Ports
-----------------------------------------------------------------------------------------------------
nodestatic_nodestatic_1   /nodejs/bin/npm start     Up                        8080/tcp
nodestatic_openresty_1    ./entrypoint nginx -c     Up                        0.0.0.0:443->443/tcp,
                          /etc ...                                            0.0.0.0:80->80/tcp

Dockerホストからcurlでリバースプロキシを確認します。

$ curl https://localhost --insecure
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>hello world</title>
  </head>
  <body>
   <p>hello world</p>
  </body>
</html>