"フロントエンドエンジニアのための" Nginx プロキシサーバーを Docker で運用する方法

SPA の開発において、本番では API が同ドメインにあるので例えば /api/login という形でリクエストを出すが、開発時にはむき出しの、例えば api.com/login にリクエストを投げて開発したい場合がある。

これは webpack devServer の設定で実現できる。

またこの設定を保持したまま、SPA をテスト環境等にステージングするためには、nginx の proxy を設定すればできる。

さらに今回は Docker での運用の具体的な手順も記述する。ステージング環境は zeit と now を使うことで一瞬で構築できる。

## webpack devServer のプロキシ設定で /api を別ドメインに投げる

[https://webpack.js.org/configuration/dev-server/#devserver-proxy](https://webpack.js.org/configuration/dev-server/#devserver-proxy)

```js
module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://api.com',
        pathRewrite: {'^/api' : ''}
      }
    }
  }
};
```
# 別ドメインの API に投げる仕様のまま、テスト環境にステージング

このプロキシ設定で開発しているアプリケーションを、社内確認やテストのためにステージング環境にあげるためには、当然プロキシ設定をもたせた状態で静的ファイルをホスティングしなくてはいけない。そうでないと、/api/ に投げたリクエストは宙に浮くことになる。

そのためには nginx の proxy を使うと早い。以下 nginx の設定。nginx は詳しくないので、もっと効率的なやり方があったり、もしくは無駄な設定をかいていたりするかもしれない。(コメントでご指摘いただけると幸いです)

これによって /api/login に投げたリクエストは api.com/login に投げ直される。またそれ以外のパスでは普通に静的ファイルを返す webserver となる。

```nginx
# 投げる api のドメインを定義
upstream api {
    server api.com;
}

server {
    listen       80;
    server_name  localhost;

    # /api/ にきた場合だけプロキシする
    location /api/ {
        # upstream で定義した api = api.com に投げる設定
        proxy_pass http://api/;
    }

    # ここはそのまま
    # 普通のパスの場合は静的ファイルを普通に返す
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
```

## Docker で nginx を立ち上げて、静的ファイルをホスティングし、/api/ はプロキシする手順

基礎的な設定の説明が終わったので、Docker を使った運用について手順を説明する。

### まず Dockerfile を設定する

この際に重要なのは build したフロント用の静的ファイルを docker 側に送り込むこと (`ADD /dist /usr/share/nginx/html`) と、nginx の設定を送り込むこと (`ADD /deploy/nginx.settings /etc/nginx/conf.d/default.conf`) である。Dockerfile のビルドをする前に、/dist にフロント用静的ファイルをビルドしておき、/settings/nginx.settings に先ほどの nginx のプロキシを設定した設定ファイルを置いておく。

```dockerfile
FROM nginx:latest
RUN apt-get update && apt-get install -y \
    vim \
ADD /dist /usr/share/nginx/html
ADD /settings/nginx.settings /etc/nginx/conf.d/default.conf
```

### Docker image を build する
Dockerfile のあるところで以下を実行

```bash
docker build -t my-nginx .
```

説明が遅くなったが以下のようなディレクトリ構成になっている。

- Dockerfile
- dist/
    - 静的なファイルがある
- settings/
    - nginx.settings

### build したファイルを試しにローカルで実行する

```
docker run -p 80:8080 my-nginx
```

`localhost` にアクセスすれば dist に配置した静的ソースがデリバリされ、/api/ に投げた api は api.com/ に投げ返される。

## Now と Zeit で Docker を実行する

Docker image をステージング環境で使うためには AWS(Amazon Web Service) や GCP(Google Cloud Platform) 等を使うことが多いと思われるが、使ったことが一度もない人にとってはそれなりにハードルがある。

さっと Dockerfile から実行するだけなら [zeit](https://zeit.co/about) と [Now](https://zeit.co/docs) で簡単にできる。

### Zeit と Now について簡単に説明

「Zeit」 は非常に簡単に使用できる cloud computing を提供してくれるサービスで、node と docker を実行でき、もちろん静的ファイルのホスティングすることもできる。例えば React 製の SPA をホスティングするウェブサーバーとして使うことも、node の express 製の API を動かすことも、Docker アプリケーションを実行することもできる。

「now」 は zeit にデプロイするためのサービスで、デスクトップアプリケーションをインストールし、それによって自動的にて提供されるコマンドツールからデプロイをする。

例えば `now /dist` をとするだけで、/dist 内にある静的ファイルをホスティン
グする。とにかくコマンド一発でデプロイできるのが特徴だ。

### now の設定ファイル now.json を作る

簡単なデプロイであれば now 用設定ファイルは必要ないが、今回は作る。

ディレクトリ構成は以下。

- Dockerfile
- dist/
    - 静的なファイルがある
- settings/
    - nginx.settings
- now.json

以下 now の設定ファイル。

```json:now.json
{
  "files": [
    "dist",
    "deploy"
  ]
}
```

files プロパティで、docker add/copy で使用するディレクトリは追加しておく必要がある。これで追加しておかないと Dockerfile のビルド時に見えないため、失敗する。

あとは Dockerfile のある場所で `now` と実行すれば終わり。同ディレクトリに package.json と Dockerfile がある場合にはどちらのアプリケーションをデプロイするか確認されるので、2 を押して Dockerfile を元にデプロイする。

すると now コマンドラインツールが Dockerfile をもとに Docker image をビルドして、このイメージを zeit 上で実行してくれる。ターミナルに示された URL に移動すれば nginx が動いているはずだ。

## まとめ
- 開発中は webpack devServer の設定でプロキシする
- ステージング環境では nginx で静的ファイルをホスティングしつつ、設定で proxy する
- Dockerfile で nginx アプリケーションを作って実行するのが早い
- zeit, now で Dockerfile を即実行できる