Docker 上の nginx で Mattermost と  Knowledge と Joomla をリバースプロキシさせてみた Ver.1

## はじめに

Docker はいろんな Web アプリをサクッと使い始めるのにとっても便利。でも、アプリごとにポート番号違いの URL というのはわかりにくいしかっこ悪い。
リバースプロキシで URL を整備したいと思うのは必然で、リバースプロキシといえば、[nginx](https://nginx.org/) でしょ。ということで、nginx も Docker コンテナで立てて、個々のアプリを繋げてみた。

→ **[Ver.2](https://qiita.com/k1tajima/items/a63d4928c31279bcfbb5) として書き直した方法の方がおすすめです。**

## 構成

* Docker 上で nginx と各種サービスを実行
    + [nginx](https://hub.docker.com/_/nginx/)
    + [Mattermost](https://hub.docker.com/r/mattermost/mattermost-preview/)
    + [Knowledge](https://hub.docker.com/r/koda/docker-knowledge/)
    + [Joomla!](https://hub.docker.com/r/bitnami/joomla/)
* [docker-compose](https://docs.docker.com/compose/install/#install-compose)
* OS: Debian

## ポイントと落とし穴

* 今回の方法で同一サーバー上に複数 Web アプリを動作させる場合、コンテキストパス付き URL に対応した Web アプリであることが条件。
* Docker に配置した Web アプリへ nginx から転送するには、転送先として `localhost` の代わりに `docker0` の IP アドレスを指定。
* Web アプリに応じて proxy_set_header ほかの調整が必要。
  Mattermost については [こちら](https://docs.mattermost.com/install/config-proxy-nginx.html)を参照。
* 共通の proxy_set_header を server ディレクティブに記述してみたが、うまく機能しなかったので、location ディレクティブに記述。

## 設定

### nginx

* Docker Image - <https://hub.docker.com/_/nginx/>
* conf ファイル設定の基本形は次の通り。

    ```configuration
    server {
      listen       80;
      server_name  docker.example.com;

      set $docker0 172.17.0.1;
    # set $docker0 192.168.0.1;   docker0 bridge のIPを変更している場合

      location /service/ {
        proxy_set_header        Host                $host;
        proxy_set_header        X-Real-IP           $remote_addr;
        proxy_set_header        X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto   $scheme;
        proxy_set_header        X-Frame-Options     SAMEORIGIN;
        proxy_pass              http://$docker0:18080/service/;
      # proxy_pass              http://$docker0:18080;    # 上の行と同義
      }
    }
    ```

    > 参考：
    > * <http://nginx.org/en/docs/beginners_guide.html#proxy>
    > * <http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass>
    > * <https://docs.docker.com/v17.09/engine/userguide/networking/#default-networks>

* proxy_pass 末尾のスラッシュ `/` 有無による違いを理解しておく。
    > 参考： <https://qiita.com/master-of-sugar/items/6dc7c03a1f600c1ec24a>

* location に正規表現を用いる場合、記述順だけでなく優先順位に留意。
    > 参考： <https://server-setting.info/centos/nginx-location-check.html>

* proxy_pass Host には \$http_host の代わりに \$host を指定
    > 参考： <https://qiita.com/no1zy_sec/items/dfccd91cf76bf73b7754>

### Mattermost

* Docker Image - <https://hub.docker.com/r/mattermost/mattermost-preview/>
* Mattermost V5 以上であることが条件。
    * V4 はコンテキストパス付 URL に非対応のため、今回の方法ではリバースプロキシ対応にできない。
* 次のドキュメントを参考に、proxy_set_header ほかを設定する。
    * <https://docs.mattermost.com/install/config-proxy-nginx.html>

### Knowledge

* Docker Image - <https://hub.docker.com/r/koda/docker-knowledge/>
* コンテキストパス（正確にはサーブレットパス）付き URL とするために、アプリケーションのファイル名を変更。
    * /usr/local/tomcat/webapps/ROOT.war -> knowledge.war

    > 参考： <https://qiita.com/nk-tamago/items/52932e2106c9f493754c#起動後のカスタマイズ>

### Joomla!

* Docker Image - <https://hub.docker.com/r/bitnami/joomla/>
* コンテキストパス付き URL とするために、アプリケーション格納先フォルダを変更。
    * /opt/bitnami/joomla -> /opt/bitnami/joomla/joomla
    
    > 参考： <https://docs.joomla.org/J3.x:Installing_Joomla/ja#Downloading_and_Uploading_Joomla.21_Package_Files>

---

## サンプル: reverseproxy.conf

```configuration

# ref=http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
server {
    listen       80;
    server_name  docker.example.com;

    set $docker0 172.17.0.1;
    # set $docker0 192.168.0.1;

    # ref=https://docs.mattermost.com/install/config-proxy-nginx.html
    location ~ /mattermost/api/v[0-9]+/(users/)?websocket$ {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        client_max_body_size 50M;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Frame-Options SAMEORIGIN;
        proxy_buffers 256 16k;
        proxy_buffer_size 16k;
        client_body_timeout 60;
        send_timeout 300;
        lingering_timeout 5;
        proxy_connect_timeout 90;
        proxy_send_timeout 300;
        proxy_read_timeout 90s;
        proxy_pass http://$docker0:8065;
    }

    location /mattermost/ {
        client_max_body_size 50M;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Frame-Options SAMEORIGIN;
        proxy_buffers 256 16k;
        proxy_buffer_size 16k;
        proxy_read_timeout 600s;
        proxy_http_version 1.1;
        proxy_pass http://$docker0:8065;
    }

    location /knowledge/ {
        proxy_set_header        Host                $host;
        proxy_set_header        X-Real-IP           $remote_addr;
        proxy_set_header        X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto   $scheme;
        proxy_set_header        X-Frame-Options     SAMEORIGIN;
        proxy_pass              http://$docker0:18080;
    }

    location /joomla/ {
        proxy_set_header        Host                $host;
        proxy_set_header        X-Real-IP           $remote_addr;
        proxy_set_header        X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto   $scheme;
        proxy_set_header        X-Frame-Options     SAMEORIGIN;
        proxy_pass              http://$docker0:28080;
    }

    # ref=http://nginx.org/en/docs/beginners_guide.html
    location / {
        root    /var/www;
    }
}
```