nginx(1.4.3)のproxyでWebとWebSocketのポート共有させてみました。
    以下、同時に試した項目です。
- WebSocketのproxy(ws://~) → OK
 - WebSocketのproxy(wss://~) → OK
 - Webのproxy(http://~) → OK
 - Webのproxy(https://~) → OK
 - マルチドメイン(ただし、SSLは1ドメインのみ) → OK
 
【動作確認ブラウザ】
- Chrome 30.0 → OK
 - Safari (iOS6.1) → OK
 - Safari 6.0.5 → OK
 - Mozilla Firefox 24.0 → OK
 - IE 8.0 → NG
 - IE 10.0 → OK
 
その他の条件:
- Webサーバ(Apache)とWebSocketサーバの前にnginxを配置、同一ドメインに対する接続をWebサーバとWebSocketサーバへ振り分ける。
 - WebSocketのポートはWebと同じポートを使用し、振り分けはパス/ws/の場合にWebSocketサーバとする。
 - SSLはnginxで処理しWebサーバとWebSocketサーバへはhttpおよびwsで接続する。
 
【ファイアウォール → nginx → web/websocketサーバのURL】
- SSLなし
http://domain:80/ → http://domain:8080/ → http://127.0.0.1:80/
ws://domain:80/ws/ → ws://domain:8080/ws/ → ws://127.0.0.1:8000/ws/ 
- SSLあり
https://domain:443/ → https://domain:443/ → http://127.0.0.1:80/
wss://domain:443/ws/ → wss://domain:443/ws/ → ws://127.0.0.1:8000/ws/ 
Apacheの設定変更なしとするためファイアウォールで80から8080へポート転送し、nginxで8080を受けるようにしています。nginxで80を受けてApacheへ8080で渡すもよいでしょう。
WebSocketサーバのポート8000は、単なる思い付きですので適当なポートをどうぞ。
/etc/nginx/nginx.confの設定
--------------------------------------------------------------------------------
user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
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;
    gzip  on;
    include /etc/nginx/conf.d/*.conf;
}
--------------------------------------------------------------------------------
/etc/nginx/conf.d/proxy.confの設定
--------------------------------------------------------------------------------
# ヘッダの設定                                                                  
proxy_redirect                          off;
proxy_set_header Host                   $host;
proxy_set_header X-Real-IP              $remote_addr;
proxy_set_header X-Forwarded-Proto      $scheme;
proxy_set_header X-Forwarded-Host       $host;
proxy_set_header X-Forwarded-Server     $host;
proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
# タイムアウトの設定                                                            
proxy_connect_timeout 60;
proxy_read_timeout    90;
proxy_send_timeout    60;
# バッファサイズの設定                                                          
proxy_buffering  on;
proxy_buffer_size       8k;
proxy_buffers           100 8k;
# キャッシュの設定                                                              
proxy_cache_path      /var/cache/nginx/domain.co.jp levels=1:2 keys_zone=cache_domain.co.jp:15m inactive=7d max_size=1000m;
proxy_temp_path       /var/cache/nginx/temp;
proxy_cache_valid     200 2h;
proxy_cache_valid     302 2h;
proxy_cache_valid     301 4h;
proxy_cache_valid     any 1m;
    upstream any_web {
        ip_hash;
        server 127.0.0.1:80;
#       server 192.168.0.1:80 weight=5;
#       server 192.168.0.2:80 weight=5;
    }
    upstream any_websocket {
        ip_hash;
        server 127.0.0.1:8000;
#       server 192.168.0.1:8000;
    }
    server {
        listen       8080;
        server_name  host.domain1 host.domain2 host.domain3;
        location /ws/ {
            proxy_pass http://any_websocket;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
        location / {
            proxy_pass http://any_web;
            proxy_redirect default;
        }
    }
    server {
        listen       443;
        server_name  host.domain1;
        ssl on;
        ssl_certificate      /etc/pki/tls/certs/server.crt;
        ssl_certificate_key  /etc/pki/tls/certs/server.key;
        location /ws/ {
            proxy_pass http://any_websocket;
            proxy_redirect http:// https://;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
        location / {
            proxy_pass http://any_web;
            proxy_redirect http:// https://;
        }
    }
--------------------------------------------------------------------------------
これでWebとWebSocket共存しマルチドメインも動作できました。
SSLは、マルチドメインでもどれか一つのドメインのみ対応しています。
設定(#コメント部分)を少し変えれば、下図の小規模冗長構成にしてWebサーバのロードバランシングに対応できるようになります。
WebSocketについては、ステートフルのためWebサーバのようにリクエスト単位のロードバランシングはできませんが、負荷をみながらパス(上記/ws/部分)またはportを切り替えて接続先を制御することにより接続単位のロードバランシングを実現できます。
Mailサーバをnginxでproxyするのも良いですが、今回はWebとWebSocketにフォーカスしています。
【環境】
- CentOS Linux 6.3
 - nginx 1.4.3
 - Apache 2.2.15
 - PHP WebSocket (websocket draft hybi-10,13をサポート)
https://github.com/lemmingzshadow/php-websocket - PHP 5.3.3
 
nginxのインストール(CentOS 6.3)
- リポジトリを追加
 
# vi /etc/yum.repos.d/nginx.repo
------------------------------------------------------
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
------------------------------------------------------
- YUMで「nginx」をインストール
 
yum install nginx-1.4.3-1.el6.ngx.x86_64
SSL証明書(自己証明書)の作成
cd /etc/pki/tls/certs
make server.key
openssl rsa -in server.key -out server.key
make server.csr
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) [Default City]: ←指定なし
Organization Name (eg, company) [Default Company Ltd]: ←指定なし
Organizational Unit Name (eg, section) []: ←指定なし
Common Name (eg, your name or your server's hostname) []:host.domain1
Email Address []:postmaster@host.domain1
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: ←指定なし
An optional company name []: ←指定なし
これで
  /etc/pki/tls/certs/server.crt
  /etc/pki/tls/certs/server.key
が作成されます。
nginx起動
service nginx start
で起動されます。
自動起動は、nginxのインストールで設定されていましたので特に必要ありません。
        
コメントする