私的サーバー構築日誌：nginx on docker でリバースプロキシ

# 能書き

[私的サーバー構築日誌：仕切り直し](https://qiita.com/katz_engineer/items/1f21de2bd9072c260ae6)からの自宅サーバー構築の続きです。

今後、家庭内サーバーとして様々なWebサービスを立ち上げるつもりです。立ち上がるといいな… とりあえずGitLabが立ち上がる事は確定事項です。

複数のWebサーバーをDockerで立ち上げる場合には、リバースプロキシを設定しバーチャルホストの形で運用するのが定番でしょう。家庭内で私一人が使うならポート番号を振り分けても良いんですが、折角なので勉強を兼ねて、リバースプロキシに挑戦してみます。

と言っても難しい事は無いですし、記事のネタとしても同案多数のようですが。

# 目標

- Dockerコンテナでリバースプロキシを立てる
    - リバースプロキシの動作確認の為に、DockerコンテナでWebサーバーを2つ立て、表示内容で区別できるようにする

# 参考文献

## 家庭内DNS

- [私的サーバー構築日誌：LAN内DNSサーバー Unbound - Qiita](https://qiita.com/katz_engineer/items/f2198e5cb7b222d4180e) … 我が家の家庭内DNSです。バーチャルホストを動かす為に、少し追記が必要になります。

## nginx

- [Web（ブラウザ）と Nginx（プロキシ）間で HTTPS で通信する - docker-composeでNginx（リバースプロキシ）を立てて、ローカルでHTTPS通信をやってみた](https://note.com/shift_tech/n/n7d5113e5e471) … docker compose でnginxサーバーを立てるのに、これを参考にしました。
- [Docker - 私的サーバー構築日誌：Docker on ZFS - Qiita](https://qiita.com/katz_engineer/items/1896ae5fdc64de324ce8#docker) … 手前味噌ながら、最小の手間でnginxのdockerコンテナを立てるには、これが一番かと。
- [nginxでデフォルトのバーチャルホストを設定する方法 - Linux入門](https://webkaru.net/linux/nginx-default-server/)

後はnginxの設定を見ながら試行錯誤してます。

# nginxサーバー1

まず、我が家のサーバーのIPアドレスは```172.16.1.2```です。

```console:ホスト側
HOST_IPADDR=172.16.1.2
```

1つ目のWebサーバーを立てます。基本的な設定ばかりなので、解説無しで一気に行きます。

```console:ホスト側
cd
mkdir docker-nginx1
cd docker-nginx1
mkdir -p config/nginx
mkdir -p data/nginx
mkdir html
```

```console:ホスト側
cat <<___ >docker-compose.yml
version: "3.9"
services:
  nginx1:
    image: nginx:latest
    container_name: nginx1
    ports:
      - 20080:80
    volumes:
      - ./config/nginx:/etc/nginx/conf.d
      - ./data/nginx:/var/log/nginx
      - ./html:/usr/share/nginx/html
___
cat <<___ >config/nginx/1st.conf
server {
    listen        80;
    server_name   _;
    server_tokens off;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
___
```

```console:ホスト側
cat <<___ >html/index.html
<!DOCTYPE html>
<html lang="ja">
 <head>
 <meta charset="UTF-8" />
 <title>1st nginx</title>
</head>
<body>
 <h1>1st</h1>
 <p>hello,world</p>
</body>
</html>
___
```

```console:ホスト側
docker compose up -d
```

動作確認。

```console:ホスト側
curl http://$HOST_IPADDR:20080/
```

# nginxサーバー2

2つ目のWebサーバーです。

```console:ホスト側
cd
mkdir docker-nginx2
cd docker-nginx2
mkdir -p config/nginx
mkdir -p data/nginx
mkdir html
```

```console:ホスト側
cat <<___ >docker-compose.yml
version: "3.9"
services:
  nginx1:
    image: nginx:latest
    container_name: nginx2
    ports:
      - 20081:80
    volumes:
      - ./config/nginx:/etc/nginx/conf.d
      - ./data/nginx:/var/log/nginx
      - ./html:/usr/share/nginx/html
___
cat <<___ >config/nginx/2nd.conf
server {
    listen        80;
    server_name   _;
    server_tokens off;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
___
```

```console:ホスト側
cat <<___ >html/index.html
<!DOCTYPE html>
<html lang="ja">
 <head>
 <meta charset="UTF-8" />
 <title>2nd nginx</title>
</head>
<body>
 <h1>2nd</h1>
 <p>hello,world</p>
</body>
</html>
___
```

```console:ホスト側
docker compose up -d
```

動作確認。

```console:ホスト側
curl http://$HOST_IPADDR:20081/
```

# proxy

いよいよ本命のリバースプロキシです。

```console:ホスト側
cd
mkdir docker-proxy
cd docker-proxy
mkdir -p config/nginx
mkdir -p data/nginx
mkdir html
```

ここで```proxy_pass```の転送先URLとして「```localhost```」と書くと問題が発生します。

どうやら```localhost```にはIPv6の関係で2つのIPアドレスが割り当てられており、それが原因との事。そこでIPアドレスを1つだけ指定するようにします。

```127.0.0.1```と書いても良いんですが。今回はホストマシンのIPアドレスを指定してみます。

```console:ホスト側
cat <<___ >docker-compose.yml
version: "3.9"
services:
  proxy:
    image: nginx:latest
    container_name: proxy
    ports:
      - 80:80
    volumes:
      - ./config/nginx:/etc/nginx/conf.d
      - ./data/nginx:/var/log/nginx
      - ./html:/usr/share/nginx/html
___
cat <<___ >config/nginx/default.conf
server {
    listen        80 default_server;
    server_name   _;
    server_tokens off;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
___
cat <<___ >config/nginx/1st.conf
server {
    listen        80;
    server_name   1st.home;
    server_tokens off;

    location / {
        proxy_pass http://$HOST_IPADDR:20080;
    }
}
___
cat <<___ >config/nginx/2nd.conf
server {
    listen        80;
    server_name   2nd.home;
    server_tokens off;

    location / {
        proxy_pass http://$HOST_IPADDR:20081;
    }
}
___
```

```console:ホスト側
docker compose up -d
```

# 家庭内DNS

[家庭内DNSを設定](https://qiita.com/katz_engineer/items/f2198e5cb7b222d4180e#内向きdns)します。

```1st.home```と```2nd.home```を追記します。Webサーバーを立てていない```3rd.home```も追記している点に注意。後で動作確認する時に使います。

```console:ホスト側
cd /etc/unbound/unbound.conf.d/
cat | sudo tee -a machines.list >/dev/null <<___
local-data: "1st.home. 3600000 IN A $HOST_IPADDR"
local-data: "2nd.home. 3600000 IN A $HOST_IPADDR"
local-data: "3rd.home. 3600000 IN A $HOST_IPADDR"
___
```

念の為に文法チェック。

```console:ホスト側
unbound-checkconf
```

```Unbound```に設定を読み込ませます。

```console:ホスト側
sudo systemctl restart unbound
```

# 動作確認

動作確認その1。

```console:ホスト側
curl http://1st.home/
```

```1st.home```に設定した```index.html```が表示されます。

```console:ホスト側
$ curl http://1st.home/
<!DOCTYPE html>
<html lang="ja">
 <head>
 <meta charset="UTF-8" />
 <title>1st nginx</title>
</head>
<body>
 <h1>1st</h1>
 <p>hello,world</p>
</body>
</html>
```

動作確認その2。

```console:ホスト側
curl http://2nd.home/
```

```1st.home```とは別に立てたWebサーバー```2nd.home```にアクセスしています。

```console:ホスト側
$ curl http://2nd.home/
<!DOCTYPE html>
<html lang="ja">
 <head>
 <meta charset="UTF-8" />
 <title>2nd nginx</title>
</head>
<body>
 <h1>2nd</h1>
 <p>hello,world</p>
</body>
</html>
```

動作確認その3。proxyを設定していないドメインを指定されたら、proxyのデフォルト設定に従ってエラーが表示されます。

```console:ホスト側
curl http://3rd.home/
```

```console:ホスト側
$ curl http://3rd.home/
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
```

# 仕舞い

今回は実験だけです。動作確認が終わったら、各設定を削除しましょう。

```console:ホスト側
cd
cd docker-proxy
docker compose down
cd ../docker-nginx2
docker compose down
cd ../docker-nginx1
docker compose down
cd ..
sudo rm -r docker-nginx1 docker-nginx2 docker-proxy
```

```console:ホスト側
cd /etc/unbound/unbound.conf.d
sudo sed -i -e"/1st.home./d" -e"/2nd.home./d" -e"/3rd.home./d" machines.list
```

```console:ホスト側
sudo systemctl restart unbound
```

nginxでリバースプロキシの基本的な設定を試みました。設定に関して碌に解説していませんが、基本的な設定なので問題は無いでしょう。
SSL化はまた後日になります。