67
61

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

NginxのリバースプロキシでWebソケットを通す際の設定

Last updated at Posted at 2019-12-24

Webソケットを利用するサービスをNginx経由で動作させるための最低限の設定と、設定項目の意味を整理しました。

前提

本記事はnginxの設定方法をある程度知っていることを前提としています。
ディレクティブの説明などは別の記事をご参照ください。

一般公開しない、開発・分析用途を想定しています。
セキュリティやパフォーマンスについては考慮していないのでご注意ください。

具体例として、データ分析で人気のJupyterLabをNginx経由で利用するためのコードをベースに記事にしました。

Webソケットを使わない設定

まずは、シンプルな転送設定を確認します。
サブドメイン経由のアクセスをJupyterLabのサーバーへ転送しているだけです。

server {
    listen 80;
    server_name jupyter.sample.domain;
    
    location / {
        proxy_pass   http://jupyterlab:8888;
    }
}

この場合、ログインはできるのですがWebソケットによる通信を開始できず、サービス内のシェル機能や肝心の分析機能が動きません。

Webソケットが使える転送設定

次のように変更するとWebソケットが利用可能になります。

map $http_upgrade $connection_upgrade { 
    default upgrade;
    ''      close;
} 

server {
    listen 80;
    server_name jupyter.sample.domain;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade; 
    proxy_set_header Connection $connection_upgrade;

    location / {
        proxy_pass   http://jupyterlab:8888;
    }
}

詳しい説明は公式のWebSocket proxyingにも記載があります。
日本語ではこちらの記事が詳しいです。

追加項目の解説

以降、順を追って追加した項目を説明します。

map

ある変数の内容に応じて、別の変数の値を決めたいときに使用する機能です。
if文で置き換える事も可能です。

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

$http_upgradeの値が空('')の場合は、
$connection_upgrade = close

それ以外の場合は、
$connection_upgrade = upgrade

という処理が行われています。

参考:nginxにおけるmapとその応用

proxy_http_version 1.1;

HTTPプロトコルバージョンを指定します。

webソケットに必要なkeep-aliveはバージョン1.1以降で利用可能ですが、デフォルトでは1.0なので明示的に指定する必要があります。下記の「proxy_set_header Upgrade」や「proxy_set_header Connection」も1.1以降でのみ利用可能なヘッダ設定です。

proxy_set_header Host $host;

ホスト情報をプロキシサーバのものではなく、接続元のものに書き換えます。

これはWebソケットの利用に必ず必要な設定ではありませんが(先に挙げた公式の記事の設定例には入っていません)、JupyterLabでは無いとwebソケットの接続に失敗したので追加しました。

proxy_set_header Upgrade $http_upgrade;

プロトコルスイッチという仕組みで通信プロトコルをHTTP/1.1からwebsocketに変更します。

プロコルスイッチはHTTP/1.1から利用可能になった仕組みです。
先ほどの公式の記事に記載があります。

ここで紹介しているUpgradeと次のConnectionは、Hop-by-hopヘッダと呼ばれる特殊なヘッダ情報です。通常のEnd-to-endヘッダは情報を最終的な宛先に届けるために使用するのに対し、Hop-by-hopヘッダは(存在する場合は)プロキシに対して値を渡すために使用されます。

参考:HTTPプロキシでのヘッダ制御

proxy_set_header Connection $connection_upgrade;

送信先にコネクションを維持するか否かを伝えるためのヘッダーです。

ここでは、$http_upgradeの値に応じて設定済みの、「upgrade」あるいは「close」を設定しています。

おまけ

追加項目の説明は以上ですが、少し重めな設定を記載します。
筆者自身、下記の設定をそのまま使っているわけではありませんが、うまくいかない時のトライ&エラー用も兼ねて載せておきます。

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name jupyter.sample.domain;
    
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_read_timeout 600s;
    # proxy_set_header Connection "";
    
    proxy_set_header X-Real-IP $remote_addr;
    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_set_header X-Forwarded-Proto $http_x_forwarded_proto;
    proxy_set_header X-Frame-Options SAMEORIGIN;
    proxy_buffering on;
    proxy_buffers 256 16k;
    proxy_buffer_size 16k;
    # proxy_set_header X-Forwarded-For $remote_addr;

    # GCPのLBへ転送する際に発生したセキュリティ対応
    # proxy_set_header X-Content-Type-Options nosniff;
    proxy_hide_header X-Content-Type-Options;

    # セキュリティを強化するため、元々なかったヘッダを追加する場合に利用
    # add_header X-Frame-Options SAMEORIGIN;
    # add_header X-XSS-Protection "1; mode=block";
    # add_header X-Content-Type-Options nosniff;
    # add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' https://gravatar.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; object-src 'none'";
    
    client_max_body_size 50M;
    
    location / {
        proxy_pass   http://jupyterlab:8888;

        access_log /var/log/nginx/jupyterlab_access.log flush=5s;
        error_log /var/log/nginx/jupyterlab_error.log flush=5s;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
    
    # include /etc/nginx/proxy.d/*.conf;
} 

参考資料

Nginxのリバースプロキシ設定関連

Nginxを用いたWebSocketサーバのReverseProxy構成及びSSL/TLS接続

Nginxによるリバースプロキシの設定方法

proxy関連の設定リファレンス(公式)

Webソケットをリバプロする(公式)

HTTPヘッダーについて

IANAの資料

X-Forwarded-For

nginxでX-Forwarded-Forの値に$proxy_add_x_forwarded_forを安易に使わない

HTTP ヘッダー(MDN)

HTTP(wikipedia)

HTTPプロキシでのヘッダ制御

Webソケットについて

WebSocketについて調べてみた。

Websocket(wikipedia)

67
61
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
61

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?