箱のプログラミング日記。

えんじにあ奮闘記

Nginxをリバースプロキシで使う場合のCORS設定

f:id:y_hakoiri:20191102121915j:plain

NginxのCORS周りの設定においてリバースプロキシとして使用する場合の情報が少なかったのでメモ。

前提

サーバーの構成はこんな感じ

server_architecture

アプリケーションへのリクエストを捌くために、webサーバーとしてNginxを、アプリケーションサーバーとしてPumaを使っている。

アプリケーションサーバーとして何を使うかは関係なくて、とりあえずNginxがプロキシとして動いている場合を想定。

nginxのconfファイル

The way nginx and its modules work is determined in the configuration file. By default, the configuration file is named nginx.conf and placed in the directory /usr/local/nginx/conf, /etc/nginx, or /usr/local/etc/nginx.

引用:Beginner’s Guide

自分の環境の場合は/etc/nginxに設置されているようだった。

~~省略~~
http {
    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;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    gzip on;
    gzip_http_version 1.0;
    gzip_proxied any;
    gzip_min_length 500;
    gzip_disable "MSIE [1-6]\.";
    gzip_types text/plain text/xml text/css
    text/comma-separated-values
    text/javascript application/x-javascript
    application/atom+xml;

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

    include /etc/nginx/sites-enabled/*;
}

見てみるとhttpディレクティブの最後にincludeディレクティブで/etc/nginx/sites-enabled/*;とあり、こちらの設定も読み込んでいることがわかる。

デフォルトのconfファイルにはあまり細かな設定は書かずにincludeしてくるのが良いとのこと。

$ ls -ln /etc/nginx | grep sites
drwxr-xr-x 2 0 0 4096  8月 13 20:42 sites-available
drwxr-xr-x 2 0 0 4096  8月  5 21:11 sites-enabled

よくみると似たような名前のディレクトリがあるものの、

$ ls -ln /etc/nginx/sites-available/
合計 12
-rw-r--r-- 1 0 0 2360  8月 13 20:42 hoge.net.conf
$ ls -ln /etc/nginx/sites-enabled/
合計 0
lrwxrwxrwx 1 0 0 35  4月  5  2018 hoge.net.conf -> ../sites-available/hoge.net.conf

片方はシンボリックリンクだった。

どうやらシンボリック側からincludeするのが通例らしい。

includeされている方のconfを見てみると

~~省略~~
server {
    listen       80 default_server;
    server_name  hoge.net;

    # ヘルスチェック
    location /health {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://hoge-puma;
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        ~中略~
        proxy_pass http://hoge-puma;
    }

    # 静的ファイル
    location ~ ^/(img|assets|cvtest|images|uploads|javascripts|stylesheets|swfs|system)/ {
        gzip_static on;
        expires     max;
        add_header  Cache-Control public;
    }
}

大体こんな感じ。

serverディレクティブの中でlocationディレクティブを書いている。

imageなどの静的ファイルはそのままnginxで捌いているが、アプリケーションへのリクエストはpumaに渡していることがわかる。

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        ~中略~
        proxy_pass http://hoge-puma;
    }

今回は特定のパスへのリクエストのみCORSの設定を追加したいので、locationディレクティブを新しく追加するか、location /の中でif文で分岐するかのどちらかになりそう。

CORSの設定を追加

修正すべき箇所がわかったので、実際に設定を追加していく

~~省略~~
server {
    listen       80 default_server;
    server_name  hoge.net;

    # ヘルスチェック
    location /health {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://hoge-puma;
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        ~中略~
        proxy_pass http://hoge-puma;
    }

    # ここに追加
    location = /fuga {
        # CORS
        add_header Access-Control-Allow-Origin "*";
        add_header Access-Control-Allow-Methods "POST, GET, OPTIONS";
        add_header Access-Control-Allow-Headers "Origin, Authorization, Accept";
        add_header Access-Control-Allow-Credentials true;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_hide_header 'Access-Control-Allow-Origin';
        proxy_pass http://hoge-puma;
    }

    # 静的ファイル
    location ~ ^/(img|assets|cvtest|images|uploads|javascripts|stylesheets|swfs|system)/ {
        gzip_static on;
        expires     max;
        add_header  Cache-Control public;
    }
}

最初に追加したヘッダは下記の4つ。

# CORS
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "POST, GET, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, Authorization, Accept";
add_header Access-Control-Allow-Credentials true;
  • Access-Control-Allow-Origin...CORSリクエストを許可するクライアントドメインを指定する。どこからでも許可する場合は"*"を指定
  • Access-Control-Allow-Methods...CORSリクエストを許可するHTTPメソッドを指定。OPTIONSについてはプリフライトリクエストに対応

で、一度ここまで設定しただけで検証したところエラーが消えず困っていたところ、

proxy_hide_header 'Access-Control-Allow-Origin';

こちらも必要みたいだった。

参考

NGINX Reverse Proxy and Access-Control-Allow-Origin issue - Stack Overflow

Nginxで同一オリジンポリシーを突破する

CORSまとめ - Qiita