複数のWebサーバーを1つのドメインでアクセスさせたい場合 (Nginx でリバースプロキシ)

# はじめに
アクセスするURLに応じて接続先のWebサーバを切り替えたい場合、
つまり `http://hoge.com/XXXX/` というURLに対して
「XXXX」の値毎にアクセスするサーバを変更したい場合、
リバースプロキシを使うことで解決できる。

図にするとこのような感じ。各 Web app は全て別のサーバー上に存在する。
![proxy.jpg](https://qiita-image-store.s3.amazonaws.com/0/58390/360befad-143c-8edf-43d3-2e4abece2d55.jpeg)

今回は Nginx を用いてリバースプロキシを構築する。

# Nginx とは
[Nginx 公式](http://nginx.org/ja/#basic_http_features)

・基本的な HTTP 機能（静的なWebサーバ）
・Webアプリケーションと連携することで動的なページもOK
・C10K問題への対応（Apacheで問題になった）
・ロードバランシングができる。
・リバースプロキシになる。

# 仮想環境の準備
## 作るもの
以下の合計3台の仮想環境を用意する。
Proxy サーバー (proxy_server): 1台
Web サーバー (web_server1, web_server2): 2台

VirtualBox + Vagrant を利用する。
OS は CentOS 6.5 を選択。

## 作成手順
VirtualBox と Vagrant をそれぞれインストールした後、
作業用ディレクトと Vagrantfile を作成する。

```
$ mkdir ~/vagrant/nginx_proxy_test
$ cd ~/vagrant/nginx_proxy_test
$ vagrant init
```

作成された Vagrantfile を下記のように編集。
3台分のサーバーをまとめて1つのファイルで管理する。
マシン名は proxy_server、web_server1、web_server2 とした。

```ruby:Vagrantfile
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # 全マシンで共通の設定
  config.vm.box = "centos6.5"
  config.vm.box_url = "https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box"
  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--memory", "1024"]
  end

  # Proxy サーバー用の設定
  config.vm.define :proxy_server do |proxy_server|
    proxy_server.vm.network "private_network", ip: "192.168.33.100"
  end

  # Web サーバー1の設定
  config.vm.define :web_server1 do |web_server1|
    web_server1.vm.network "private_network", ip: "192.168.33.101"
  end

  # Web サーバー2の設定
  config.vm.define :web_server2 do |web_server2|
    web_server2.vm.network "private_network", ip: "192.168.33.102"
  end
end
```

下記コマンドで全マシンをまとめて初期設定 & 起動できる。

```
$ vagrant up
```

各マシンにログインする際は下記のように指定する。

```
$ vagrant ssh proxy_server
```

シャットダウンする際は下記のようにすれば全マシンがまとめて終了する。

```
$ vagrant halt
```

# Web sever の構築
## 作るもの
192.168.33.101 にアクセスした際、
下記の出力が以下のURLで見えるように設定する。

```
192.168.33.101/     ->  "Sample web app root 1"
192.168.33.101/app  ->  "Sample web app /app 1"
```
下記コマンドで web_server1 にログインして作業を行う。

```
$ vagrant ssh web_server1
```

## Nginx のインストール
下記コマンドでインストール。

```
$ sudo yum install -y nginx
$ sudo service nginx start
```

## サンプルコンテンツ作成とログ出力先の作成
Webコンテンツを置くドキュメントルートは、`/var/www/` 以下とする。
サンプルhtmlは `/var/www/sample_web_app` 以下に置く。
またログは `/var/log/nginx/sample_web_app` 以下に出力する。

```
$ sudo mkdir /var/www
$ sudo mkdir /var/www/sample_web_app
$ sudo mkdir /var/www/sample_web_app/app
$ sudo mkdir /var/log/nginx/sample_web_app
```

```html:sample_web_app/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
          "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
  <head>
    <title>Web server 1</title>
    </head>
  <body>
    <p>Sample web app root 1</p>
    </body>
</html>
```

```html:sample_web_app/app/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
          "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
  <head>
    <title>Web server 1</title>
    </head>
  <body>
    <p>Sample web app /app 1</p>
    </body>
</html>
```

## Nginx の設定
次に、nginxの設定ファイルを編集。
`/etc/nginx/nginx.conf` を下記のように記述する。

```ruby:nginx.conf
user              nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    keepalive_timeout  65;
    include /etc/nginx/conf.d/*.conf;
}
```

次に `/etc/nginx/conf.d/` 以下の `default.conf` をリネームした後、
に `*.conf` ファイルを作成する。

```
$ sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bk 
$ sudo emacs /etc/nginx/conf.d/192.168.33.101.conf
```

```ruby:192.168.33.101.conf
server {
    listen 80 default_server;
    server_name 192.168.33.101;

    access_log  /var/log/nginx/sample_web_app/access.log main;
    error_log   /var/log/nginx/sample_web_app/error.log;

    client_max_body_size 10M;

    root    /var/www/sample_web_app;
    index   index.html index.htm;
}
```

下記コマンドで nginx をリスタート。

```
$ sudo service nginx restart
```

## アクセスした結果見えるもの
[http://192.168.33.101/](http://192.168.33.101/) にアクセスした際、
`Sample web app root 1`
[http://192.168.33.101/app](http://192.168.33.101/app) にアクセスした際、
`Sample web app /app 1`
がそれぞれ出力されていればOK。

同様の手順で web_server2 も構築する
(hoge 1 -> hoge 2, 192.168.33.101 -> 192.168.33.102 と置き換えて読めばOK)。

最終的に下記のようになるはず。

```
192.168.33.101/        ->  "Sample web app root 1"
              /app     ->  "Sample web app /app 1"
192.168.33.102/        ->  "Sample web app root 2"
              /app     ->  "Sample web app /app 2"
```

# Proxy sever の構築
## 作るもの
次は 192.168.33.100 にアクセスした際、
Web server1 or Web server2 に転送し
下記のコンテンツが以下のURLで見えるように設定する。

```
192.168.33.100/          ->  "Sample proxy root"
192.168.33.100/web1      ->  "Sample web app root 1"
192.168.33.100/web1/app  ->  "Sample web app /app 1"
192.168.33.100/web2      ->  "Sample web app root 2"
192.168.33.100/web2/app  ->  "Sample web app /app 2"
```

以下の作業は下記コマンドで proxy_server にログインして行う。

```
$ vagrant ssh proxy_server
```

## Nginx のインストール
下記コマンドでインストール。

```
$ sudo yum install -y nginx
$ sudo service nginx start
```

## サンプルコンテンツ作成とログ出力先の作成
Webコンテンツを置くドキュメントルートは、`/var/www/` 以下とする。
サンプルhtmlは `/var/www/sample_proxy` 以下に置く。
またログは `/var/log/nginx/sample_proxy` 以下に出力する。

```
$ sudo mkdir /var/www
$ sudo mkdir /var/www/sample_proxy
$ sudo mkdir /var/log/nginx/sample_proxy
```

```html:sample_proxy/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
          "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
  <head>
    <title>Proxy server</title>
    </head>
  <body>
    <p>Sample proxy root</p>
    </body>
</html>
```

## Nginx の設定
次に、nginxの設定ファイルを編集。
`/etc/nginx/nginx.conf` を下記のように記述する。

```ruby:nginx.conf
user              nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    keepalive_timeout  65;
    include /etc/nginx/conf.d/*.conf;
}
```

次に `/etc/nginx/conf.d/` 以下の `default.conf` をリネームした後、
に `*.conf` ファイルを作成する。

```
$ sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bk 
$ sudo emacs /etc/nginx/conf.d/192.168.33.101.conf
```

```ruby:192.168.33.101.conf
server {
    listen 80 default_server;
    server_name 192.168.33.100;

    access_log  /var/log/nginx/sample_proxy/access.log main;
    error_log   /var/log/nginx/sample_proxy/error.log;

    client_max_body_size 10M;

   	root       /var/www/sample_proxy;
    index      index.html index.htm;

    location / {
    }

    location /web1 {
        proxy_pass http://192.168.33.101/
    }

    location /web1/app {
        proxy_pass http://192.168.33.101/app
    }

    location /web2 {
		proxy_pass http://192.168.33.102/
    }

    location /web2/app {
		proxy_pass http://192.168.33.102/app
    }
}
```

下記コマンドで nginx をリスタート。

```
$ sudo service nginx restart
```

[http://192.168.33.100/](http://192.168.33.100/) 
[http://192.168.33.100/web1](http://192.168.33.100/web1) 
[http://192.168.33.100/web1/app](http://192.168.33.100/web1/app) 
[http://192.168.33.100/web2](http://192.168.33.100/web2) 
[http://192.168.33.100/web2/app](http://192.168.33.100/web2/app) 

クライアントマシンから上記URLへアクセスした結果が
下記の通りになっているのを確認できればOK。

```
192.168.33.100/          ->  "Sample proxy root"
192.168.33.100/web1      ->  "Sample web app root 1"
192.168.33.100/web1/app  ->  "Sample web app /app 1"
192.168.33.100/web2      ->  "Sample web app root 2"
192.168.33.100/web2/app  ->  "Sample web app /app 2"
```

# おわりに
無事、アクセスするURLに応じて接続先のWebサーバを切り替えられた。
Nginx のお勉強ちゃんとしたほうが良さそうだったので資料を漁った。
下記の資料がよくまとまっていたので学習が捗った。

・Nginx の紹介
[http://www.slideshare.net/ttkzw/nginx-intro](http://www.slideshare.net/ttkzw/nginx-intro)

・Nginx 入門
[http://www.slideshare.net/ttkzw/nginx-primer](http://www.slideshare.net/ttkzw/nginx-primer )