Docker でサービスのスタック (Unifi、PHP、Nginx、Certbot) を設定しようとしています。Unifi と PHP はバックエンド サービスであり、Nginx はそれらをリバース プロキシ モードで提供し、Certbot は定期的に実行されて Nginx の SSL 証明書を取得します。
ほぼ動作しています。すべての GET リクエストが機能し、Unifi が提供するページを表示できます。ただし、AJAX 経由のすべての POST リクエストは、CORS が原因で 403 エラーをスローします。
今のところ、CORS ヘッダーの操作方法やエラーの原因についてはあまり詳しくありません。原因はブラウザ、Nginx、それとも unifi でしょうか? ただし、設定を変更できるのは Nginx だけです。
ブラウザ インスペクタ/ネットワーク モニタからのすべての AJAX 投稿リクエストで表示されるエラーは次のとおりです。
POST
scheme https
host example.com:8443
filename /api/stat/device
Address (server_ip_address):8443
Status 403 Forbidden
Version HTTP/2
Transferred 141 B (0 B size)
Referrer Policy strict-origin-when-cross-origin
RESPONSE HEADERS
content-length 0
content-type text/plain
date Fri, 17 Sep 2021 00:59:09 GMT
server nginx
X-Firefox-Spdy h2
REQUEST HEADERS
Accept application/json, text/plain, */*
Accept-Encoding gzip, deflate, br
Accept-Language en-US,en;q=0.5
Connection keep-alive
Content-Length 0
Cookie unifises=(random token here); csrf_token=(random token here)
DNT 1
Host example.com:8443
Origin https://example.com:8443
Referer https://example.com:8443/setup/configure/controller-name
Sec-Fetch-Dest empty
Sec-Fetch-Mode cors
Sec-Fetch-Site same-origin
TE trailers
User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
X-Csrf-Token (random token here)
Nginx の設定は次のとおりです。
# enbables GZIP compression
gzip on;
# compression level (1-9)
# 6 is a good compromise between CPU usage and file size
gzip_comp_level 6;
# minimum file size limit in bytes to avoid negative compression
gzip_min_length 256;
# compress data for clients connecting via proxies
gzip_proxied any;
# directs proxies to cache both the regular and GZIp versions of an asset
gzip_vary on;
# disables GZIP compression for ancient browsers
gzip_disable "msie6";
server {
listen 80;
listen [::]:80;
server_name example.com;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/certbot/;
}
# Redirect relevant Unifi paths Unifi Address and Port
location / {
rewrite ^ https://$host:8443$request_uri?;
}
}
server {
listen 8443 ssl http2;
listen [::]:8443 ssl http2;
server_name example.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 1.0.0.1 208.67.222.222 208.67.220.220;
location / {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
proxy_pass https://unifi:8443/;
proxy_set_header Authorization "";
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Ssl on;
proxy_http_version 1.1;
proxy_buffering off;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
auth_basic "Restricted";
proxy_set_header Referer "";
}
}
Stack Exchange 内外で、把握しきれないほど多くのガイドを探すのに疲れたので、私の設定は今やこんなに乱雑になっています。
では、CORS による失敗なしに XHR リクエストを処理するには、Nginx をどのように変更すればよいのでしょうか?
編集 1: Nginx の listen ポートに 8443 に加えてポート 443 を追加しました。443 経由で Unifi にアクセスし、unifi:8443 にプロキシすると、期待どおりに動作します。ただし、8443 で透過的に動作する必要があります。
編集 2: わずかに変更した構成で、別の「仲介者」Nginx コンテナーを追加してみました。元の Nginx コンテナーのポート 8443 へのリクエストをポート 443 の 2 番目のコンテナーにプロキシし、それを 8443 の Unifi にリバース プロキシしました。以前のように「仲介者」プロキシがない場合と同じ結果です。つまり、Web -> 8443 の Nginx --> 443 の Nginx -> 8443 の Unfi です。この構成は機能せず、非効率的であるため削除しました。