3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【docker-compose】nginxでリバースプロキシを実装する

Last updated at Posted at 2021-05-22

背景

これの続きとして、docker-registryへhttpsで接続できるようにしたい。
nginxでリバースプロキシを構築して上記を実現する予定ですが、そもそもリバースプロキシを使ったことがないため、実際に導入してイメージをつかんでみます。
docker-composeを使います。

環境

  • AWSのEC2
  • 使ったAMIはamzn2-ami-hvm-2.0.20210126.0-x86_64-gp2

dockerバージョン

$ docker --version
Docker version 20.10.4, build d3cb89e
$ docker-compose --version
docker-compose version 1.27.4, build 40524192

構成図

docker-compose_reverseproxy.png

前提

  • https接続のための証明書が取得済みであること。
    本環境ではletsencryptで発行したSSL証明書を使います。
  • docker,docker-composeが使えること

フォルダ構成

フォルダ構成
.
|-- cert
|   |-- fullchain.pem # サーバ証明書
|   `-- privkey.pem # 秘密鍵
|-- docker-compose.yaml
|-- reverseproxy
|   `-- nginx.conf
|-- web1
|   `-- index.html
|-- web2
|   `-- index.html
`-- web3
    `-- index.html

webサーバのindex.htmlは↓です。

各フォルダのindex.html
$ cat web{1..3}/index.html
<h1>this is web1</h1>
<h1>this is web2</h1>
<h1>this is web3</h1>

docker-compose.yaml

以下を使用しました

docker-compose.yaml
version: "3.9"
services:
  reverse-proxy:
    image: nginx:1.20
    extra_hosts:
      - "host.docker.internal:host-gateway" # 注1
    ports:
      - 5043:443
    volumes:
      - ./cert/fullchain.pem:/etc/nginx/conf.d/fullchain.pem:ro
      - ./cert/privkey.pem:/etc/nginx/conf.d/privkey.pem:ro
      - ./reverseproxy/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./reverseproxy/.htpasswd:/etc/nginx/.htpasswd:ro
  web1:
    image: nginx:1.20
    extra_hosts:
      - "host.docker.internal:host-gateway" # 注1
    ports:
      - 6043:80
    volumes:
      - ./web1/index.html:/usr/share/nginx/html/index.html
  web2:
    image: nginx:1.20
    extra_hosts:
      - "host.docker.internal:host-gateway" # 注1
    ports:
      - 7043:80
    volumes:
      - ./web2/index.html:/usr/share/nginx/html/index.html
  web3:
    image: nginx:1.20
    extra_hosts:
      - "host.docker.internal:host-gateway" # 注1
    ports:
      - 8043:80
    volumes:
      - ./web3/index.html:/usr/share/nginx/html/index.html

nginx.conf

リバースプロキシとして動作させるnginxのconfファイルは以下です。

nginx.conf
events { # 注2
    worker_connections  1024;
}

http {
  server {
      listen 443 ;
      ssl on ; # 注3
      ssl_protocols TLSv1.3; # 注4
      ssl_certificate /etc/nginx/conf.d/fullchain.pem;
      ssl_certificate_key /etc/nginx/conf.d/privkey.pem;
      server_name  localhost;

      location /web1 {
          proxy_pass http://host.docker.internal:6043/; # 注1
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-for $remote_addr;
          auth_basic_user_file /etc/nginx/.htpasswd; # 注5
          auth_basic "basic ninnsyou";
    }
      location /web2 {
          proxy_pass http://host.docker.internal:7043/; # 注1
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-for $remote_addr;
          auth_basic_user_file /etc/nginx/.htpasswd;
          auth_basic "basic ninnsyou";
    }
      location /web3 {
          proxy_pass http://host.docker.internal:8043/; # 注1
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-for $remote_addr;
          auth_basic_user_file /etc/nginx/.htpasswd;
          auth_basic "basic ninnsyou";
    }
      error_page   500 502 503 504  /50x.html;
      location = /50x.html {
          root   /usr/share/nginx/html;
      }
  }
}

注を付けた箇所の説明をします。

注1 host.docker.internal について

ここを参考にさせていただきました。

extra_hosts:
  - "host.docker.internal:host-gateway"

とすることで、コンテナからホストへのアクセスを実現しています。  

extra_hostsはドメインとIPアドレスに紐づけを行います。/etc/hostsのようなものです。
host.docker.internal はホストにアクセスするための特別なドメインであり、host-gatewayを選択すればホストにアクセスできる様です。
githubのページから手順の参考にしましたが、公式のドキュメントには現時点でlinux向けの記載はなさそうです。
(docker for Windows , docker for MACについては記載があります)

注1 localhostの指定はOK?

localhost:6043と指定してもうまくいきません。
リバースプロキシコンテナのlocalhost:6043に転送され、ホストの6043に転送されるわけではないからです。
上記のhost.docker.internalや、ホストのIPアドレスを指定しましょう。

dockerのネットワーク、DNSについてはいずれまとめて調べてみたいですね。

注2 nginx.conf eventsブロックについて

ここの記載がないとリバースプロキシコンテナが立ち上がりません。(そもそもnginxが動作しない)
何らかの値を入れれば問題なく通りそうです。

events記載なし
$ head -n 3 reverseproxy/nginx.conf
#events {
#    worker_connections  1024;
#}
$ docker-compose up -d
$ docker-compose logs reverse-proxy
...
reverse-proxy_1  | /docker-entrypoint.sh: Configuration complete; ready for start up
reverse-proxy_1  | 2021/05/22 06:01:11 [emerg] 1#1: no "events" section in configuration
reverse-proxy_1  | nginx: [emerg] no "events" section in configuration
$
events記載あり
$ head -n 3 reverseproxy/nginx.conf
events {
    worker_connections  1024;
}
$ docker-compose up -d
$ docker-compose logs reverse-proxy
...
reverse-proxy_1  | /docker-entrypoint.sh: Configuration complete; ready for start up
$

知らなかったです。

注3 nginx.conf SSLの記載箇所

最初以下の様にしていました。
起動すると非推奨だと怒られました。動作はします。

nginx.conf
  server {
      listen 443 ;
      ssl on ;
[docker] $ docker-compose logs reverse-proxy
...
reverse-proxy_1  | 2021/05/22 06:18:48 [warn] 1#1: the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in /etc/nginx/nginx.conf:8
reverse-proxy_1  | nginx: [warn] the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in /etc/nginx/nginx.conf:8
reverse-proxy_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
reverse-proxy_1  | /docker-entrypoint.sh: Configuration complete; ready for start up

過去のバージョンと記法が異なっているのでしょうか。
ドキュメントにある通り、以下の記載にしましょう

nginx.conf
server {
    listen 443 ssl;

注4 TLS1.3に限定する

安全性を考慮してTLS1.3の通信に限定しました。
以下の様に記載したらTLS1.3を使わない通信は弾いてくれます。

nginx.conf
  server {
      ssl_protocols TLSv1.3;
疎通確認
[test@test-server ~]$ curl --tlsv1.2 -u test:test https://example.test:5043/web3
curl: (35) Peer reports incompatible or unsupported protocol version.
[test@test-server ~]$ curl --tlsv1.3 -u test:test https://example.test:5043/web3
<h1>this is web3</h1>

注5 nginxにbasic認証を付ける

ドキュメントを参考にしました。
以下の記載で認証を実現しています。htpasswdファイルをあらかじめ用意しておきましょう。

nginx.conf
      location /web1 {
          auth_basic_user_file /etc/nginx/.htpasswd;
          auth_basic "basic ninnsyou"; 

コンテナ起動、疎通確認

それでは起動してみます。
docker-compose.yamlがあるディレクトリで行います。

$ docker-compose up -d
Creating network "reverse-proxy_ssl_default" with the default driver
Creating reverse-proxy_ssl_web1_1          ... done
Creating reverse-proxy_ssl_web3_1          ... done
Creating reverse-proxy_ssl_reverse-proxy_1 ... done
Creating reverse-proxy_ssl_web2_1          ... done
$ docker-compose ps
              Name                             Command               State               Ports
----------------------------------------------------------------------------------------------------------
reverse-proxy_ssl_reverse-proxy_1   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:5043->443/tcp, 80/tcp
reverse-proxy_ssl_web1_1            /docker-entrypoint.sh ngin ...   Up      0.0.0.0:6043->80/tcp
reverse-proxy_ssl_web2_1            /docker-entrypoint.sh ngin ...   Up      0.0.0.0:7043->80/tcp
reverse-proxy_ssl_web3_1            /docker-entrypoint.sh ngin ...   Up      0.0.0.0:8043->80/tcp

問題なく起動していそうです。別ホストからcurlで確認してみましょう

$ curl --tlsv1.3 -u test:test https://example.test:5043/web1
<h1>this is web1</h1>
$ curl --tlsv1.3 -u test:test https://example.test:5043/web2
<h1>this is web2</h1>
$ curl --tlsv1.3 -u test:test https://example.test:5043/web3
<h1>this is web3</h1>

# -u basic認証を行う。ユーザとパスワードを指定

問題なさそうです。アクセスログも確認してみます。
(見やすくするために出力を並び替えています。)

$ docker-compose logs | grep curl
web1_1           | 172.27.0.1 - test [22/May/2021:07:14:19 +0000] "GET / HTTP/1.0" 200 22 "-" "curl/7.29.0" "<クライアントIP>"
web2_1           | 172.27.0.1 - test [22/May/2021:07:14:22 +0000] "GET / HTTP/1.0" 200 22 "-" "curl/7.29.0" "<クライアントIP>"
web3_1           | 172.27.0.1 - test [22/May/2021:07:07:12 +0000] "GET / HTTP/1.0" 200 22 "-" "curl/7.29.0" "<クライアントIP>"
reverse-proxy_1  | <クライアントIP> - test [22/May/2021:07:14:23 +0000] "GET /web3 HTTP/1.1" 200 22 "-" "curl/7.29.0"

うまくいっていますね!ちなみにアクセス元の172.27.0.1は前述したgatewayです。
確認は以下の様にできますが、説明については別の機会にしたいと思います。

$ docker network inspect reverse-proxy_ssl_default | jq ".[] | {IPAM}[].Config[].Gateway"
"172.27.0.1"

# reverse-proxy_ssl_defaultは今回のdocker-composeで作ったネットワークです。

最後に

以上となります。
docker-registryも無事に構築できるとうれしいです。

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?