Ubuntu 22.04 Nginx WebSocket 代理

Ubuntu 22.04 Nginx WebSocket Proxy Configuration

WebSocket 是現代即時網路應用程式的核心技術,廣泛應用於聊天系統、即時通知、線上遊戲及協作工具等場景。本文將詳細介紹如何在 Ubuntu 22.04 上使用 Nginx 設定 WebSocket 代理,涵蓋從基礎設定到進階的負載平衡、SSL/TLS 終止及監控等完整內容。

WebSocket 協定概述

什麼是 WebSocket?

WebSocket 是一種在單一 TCP 連線上進行全雙工通訊的協定。與傳統的 HTTP 請求-回應模式不同,WebSocket 允許伺服器主動向用戶端推送資料,實現真正的即時通訊。

1
2
3
4
5
6
7
8
傳統 HTTP:
用戶端 --請求--> 伺服器
用戶端 <--回應-- 伺服器
(每次通訊需要新的請求)

WebSocket:
用戶端 <--雙向通訊--> 伺服器
(單一連線持續開啟)

WebSocket 握手過程

WebSocket 連線始於一個 HTTP 升級請求:

1
2
3
4
5
6
GET /ws HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

伺服器回應:

1
2
3
4
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

WebSocket vs HTTP 比較

特性HTTPWebSocket
通訊模式請求-回應全雙工
連線方式短連線長連線
伺服器推送不支援(需輪詢)原生支援
標頭開銷較大較小
適用場景一般網頁瀏覽即時應用

Nginx WebSocket 代理設定

前置需求

確保系統已安裝 Nginx:

1
2
sudo apt update
sudo apt install nginx -y

驗證 Nginx 版本(建議 1.3.13 以上):

1
nginx -v

基本 WebSocket 代理設定

建立 Nginx 設定檔:

1
sudo nano /etc/nginx/sites-available/websocket

加入以下基本設定:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name example.com;

    location /ws/ {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

啟用設定:

1
2
3
sudo ln -s /etc/nginx/sites-available/websocket /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

升級標頭處理

map 指令詳解

map 指令是處理 WebSocket 升級的關鍵,它根據 $http_upgrade 變數的值動態設定 Connection 標頭:

1
2
3
4
map $http_upgrade $connection_upgrade {
    default upgrade;    # 如果有 Upgrade 標頭,設定為 "upgrade"
    ''      close;      # 如果沒有 Upgrade 標頭,設定為 "close"
}

關鍵標頭說明

標頭說明範例值
Upgrade請求升級協定websocket
Connection連線處理方式upgradeclose
Sec-WebSocket-Key用戶端隨機金鑰Base64 編碼字串
Sec-WebSocket-VersionWebSocket 協定版本13

完整標頭設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
location /ws/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;

    # WebSocket 升級標頭
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    # 保留原始請求資訊
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # 用於 WebSocket 應用的額外標頭
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
}

SSL/TLS 終止

為什麼需要 SSL/TLS?

WebSocket 連線分為 ws://(未加密)和 wss://(加密)兩種。在生產環境中,應始終使用 wss:// 以確保資料傳輸安全。

使用 Let’s Encrypt 取得憑證

1
2
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d example.com

手動設定 SSL 終止

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

# HTTPS 伺服器
server {
    listen 443 ssl http2;
    server_name example.com;

    # SSL 憑證
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # SSL 安全設定
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # 安全標頭
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-XSS-Protection "1; mode=block";

    # WebSocket 端點
    location /ws/ {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket 超時設定
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }

    # 一般 HTTP 請求
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

SSL 設定最佳實踐

設定項目建議值說明
ssl_protocolsTLSv1.2 TLSv1.3僅使用安全協定
ssl_session_timeout1dSession 快取時間
ssl_session_cacheshared:SSL:50m共享 Session 快取
ssl_staplingon啟用 OCSP Stapling
HSTSmax-age=31536000強制 HTTPS 一年

負載平衡設定

定義 Upstream 群組

當 WebSocket 應用需要擴展時,可使用 Nginx 負載平衡:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
upstream websocket_backend {
    # IP Hash 確保同一用戶端連到同一伺服器(Session 黏著)
    ip_hash;

    server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:8080 max_fails=3 fail_timeout=30s;
}

upstream http_backend {
    least_conn;

    server 192.168.1.10:3000 weight=3;
    server 192.168.1.11:3000 weight=2;
    server 192.168.1.12:3000 weight=1;
}

負載平衡策略選擇

針對 WebSocket 應用,建議使用以下策略:

策略語法適用場景
IP Haship_hash;需要 Session 黏著的 WebSocket 應用
Least Connectionsleast_conn;連線時間差異大的應用
Round Robin預設無狀態的 WebSocket 應用
Hashhash $request_uri;基於 URI 的分配

完整負載平衡設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

upstream websocket_backend {
    ip_hash;
    server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:8080 backup;
}

upstream http_backend {
    least_conn;
    server 192.168.1.10:3000 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:3000 max_fails=3 fail_timeout=30s;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # WebSocket 負載平衡
    location /ws/ {
        proxy_pass http://websocket_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }

    # HTTP 負載平衡
    location / {
        proxy_pass http://http_backend;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

連線逾時與保活

WebSocket 連線特性

WebSocket 連線是長期持續的,需要特別注意超時設定以避免連線意外中斷。

關鍵超時參數

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
location /ws/ {
    proxy_pass http://websocket_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    # 連線超時 - 與後端建立連線的時間
    proxy_connect_timeout 60s;

    # 讀取超時 - 等待後端回應的時間
    proxy_read_timeout 86400s;  # 24 小時

    # 發送超時 - 傳送請求到後端的時間
    proxy_send_timeout 86400s;  # 24 小時

    # 緩衝區設定
    proxy_buffering off;
    proxy_buffer_size 4k;
    proxy_buffers 4 32k;
    proxy_busy_buffers_size 64k;
}

超時參數說明

參數預設值WebSocket 建議值說明
proxy_connect_timeout60s60s建立連線超時
proxy_read_timeout60s86400s讀取資料超時
proxy_send_timeout60s86400s發送資料超時

TCP Keep-Alive 設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
http {
    # 在 http 區塊中設定 upstream 的 keepalive
    upstream websocket_backend {
        server 192.168.1.10:8080;
        server 192.168.1.11:8080;

        keepalive 32;  # 保持連線數量
        keepalive_timeout 60s;  # 保持連線超時
    }

    server {
        location /ws/ {
            proxy_pass http://websocket_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;

            # 對於 keepalive 連線,需要清除 Connection 標頭
            # 但 WebSocket 需要保留,所以使用 map
        }
    }
}

心跳機制

建議在應用層實作心跳機制:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 用戶端 JavaScript 範例
const ws = new WebSocket('wss://example.com/ws/');
const heartbeatInterval = 30000; // 30 秒

function heartbeat() {
    if (ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify({ type: 'ping' }));
    }
}

ws.onopen = function() {
    setInterval(heartbeat, heartbeatInterval);
};

ws.onmessage = function(event) {
    const data = JSON.parse(event.data);
    if (data.type === 'pong') {
        console.log('Heartbeat received');
    }
};

監控與日誌

設定詳細日誌格式

nginx.conf 中定義自訂日誌格式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
http {
    # WebSocket 專用日誌格式
    log_format websocket '$remote_addr - $remote_user [$time_local] '
                         '"$request" $status $body_bytes_sent '
                         '"$http_referer" "$http_user_agent" '
                         '$request_time $upstream_response_time '
                         '$http_upgrade $http_connection '
                         'upstream: $upstream_addr';

    # JSON 格式日誌(便於分析)
    log_format json_combined escape=json
        '{'
            '"time_local":"$time_local",'
            '"remote_addr":"$remote_addr",'
            '"remote_user":"$remote_user",'
            '"request":"$request",'
            '"status": "$status",'
            '"body_bytes_sent":"$body_bytes_sent",'
            '"request_time":"$request_time",'
            '"http_referrer":"$http_referer",'
            '"http_user_agent":"$http_user_agent",'
            '"http_upgrade":"$http_upgrade",'
            '"upstream_addr":"$upstream_addr",'
            '"upstream_response_time":"$upstream_response_time"'
        '}';
}

套用日誌設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
server {
    listen 443 ssl http2;
    server_name example.com;

    # 存取日誌
    access_log /var/log/nginx/websocket.access.log websocket;
    access_log /var/log/nginx/websocket.json.log json_combined;

    # 錯誤日誌
    error_log /var/log/nginx/websocket.error.log warn;

    location /ws/ {
        proxy_pass http://websocket_backend;
        # ... 其他設定
    }
}

連線狀態監控

啟用 Nginx stub_status 模組:

1
2
3
4
5
6
7
8
9
server {
    listen 127.0.0.1:8080;

    location /nginx_status {
        stub_status on;
        allow 127.0.0.1;
        deny all;
    }
}

查看狀態:

1
curl http://127.0.0.1:8080/nginx_status

輸出範例:

1
2
3
4
Active connections: 291
server accepts handled requests
 16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106

使用 GoAccess 分析日誌

1
2
3
4
5
6
7
8
# 安裝 GoAccess
sudo apt install goaccess -y

# 即時分析
sudo goaccess /var/log/nginx/websocket.access.log -o /var/www/html/report.html --real-time-html

# 生成報告
sudo goaccess /var/log/nginx/websocket.access.log --log-format=COMBINED -o report.html

Prometheus 監控整合

安裝 nginx-prometheus-exporter:

1
2
3
4
5
6
7
# 下載並安裝
wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v0.11.0/nginx-prometheus-exporter_0.11.0_linux_amd64.tar.gz
tar xzf nginx-prometheus-exporter_0.11.0_linux_amd64.tar.gz
sudo mv nginx-prometheus-exporter /usr/local/bin/

# 建立 systemd 服務
sudo nano /etc/systemd/system/nginx-prometheus-exporter.service

服務檔案內容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[Unit]
Description=Nginx Prometheus Exporter
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/nginx-prometheus-exporter -nginx.scrape-uri=http://127.0.0.1:8080/nginx_status
Restart=always

[Install]
WantedBy=multi-user.target

啟動服務:

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable nginx-prometheus-exporter
sudo systemctl start nginx-prometheus-exporter

常見問題排解

1. WebSocket 連線立即斷開

症狀:WebSocket 握手成功後立即斷開連線。

原因proxy_read_timeout 設定過短。

解決方案

1
2
3
4
5
location /ws/ {
    proxy_read_timeout 86400s;
    proxy_send_timeout 86400s;
    # ... 其他設定
}

2. 502 Bad Gateway 錯誤

症狀:WebSocket 連線返回 502 錯誤。

診斷步驟

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 檢查後端服務狀態
sudo systemctl status your-websocket-service

# 確認連接埠是否在監聽
sudo netstat -tlnp | grep 8080

# 測試後端連線
curl -v http://localhost:8080/ws/

# 檢查 Nginx 錯誤日誌
sudo tail -f /var/log/nginx/error.log

常見原因與解決方案

原因解決方案
後端服務未啟動啟動後端服務
連接埠被防火牆阻擋開放對應連接埠
SELinux 限制設定 SELinux 策略

3. WebSocket 握手失敗

症狀:用戶端收到 400 Bad Request。

原因:缺少必要的升級標頭。

解決方案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 確保使用 map 指令
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

location /ws/ {
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    # ... 其他設定
}

4. 負載平衡器後的 Session 問題

症狀:用戶端在不同伺服器間跳轉,造成 Session 遺失。

解決方案:使用 IP Hash 確保 Session 黏著:

1
2
3
4
5
upstream websocket_backend {
    ip_hash;
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
}

5. SSL 握手失敗

症狀wss:// 連線失敗,但 ws:// 正常。

診斷步驟

1
2
3
4
5
# 測試 SSL 連線
openssl s_client -connect example.com:443

# 檢查憑證有效性
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

常見原因

原因解決方案
憑證過期更新憑證
憑證鏈不完整使用 fullchain.pem
SSL 協定不匹配調整 ssl_protocols

6. 連線數量限制

症狀:達到一定連線數後,新連線被拒絕。

解決方案:調整系統限制:

1
2
# 調整系統檔案描述符限制
sudo nano /etc/security/limits.conf

加入:

1
2
3
4
nginx soft nofile 65535
nginx hard nofile 65535
* soft nofile 65535
* hard nofile 65535

調整 Nginx 設定:

1
2
3
4
5
6
7
worker_rlimit_nofile 65535;

events {
    worker_connections 65535;
    use epoll;
    multi_accept on;
}

7. 檢查設定語法

在套用任何變更前,務必驗證設定:

1
2
3
4
5
6
7
8
# 測試設定語法
sudo nginx -t

# 重新載入設定
sudo systemctl reload nginx

# 檢查 Nginx 狀態
sudo systemctl status nginx

完整設定範例

以下是生產環境建議的完整設定:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# /etc/nginx/nginx.conf

user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

events {
    worker_connections 65535;
    use epoll;
    multi_accept on;
}

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

    # 日誌格式
    log_format websocket '$remote_addr - $remote_user [$time_local] '
                         '"$request" $status $body_bytes_sent '
                         '"$http_referer" "$http_user_agent" '
                         '$request_time $upstream_response_time '
                         'upgrade:$http_upgrade upstream:$upstream_addr';

    # 基本設定
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # Gzip 壓縮
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript;

    # WebSocket 升級映射
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    # WebSocket 後端
    upstream websocket_backend {
        ip_hash;
        server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
        server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
        server 192.168.1.12:8080 backup;
        keepalive 32;
    }

    # HTTP 後端
    upstream http_backend {
        least_conn;
        server 192.168.1.10:3000 max_fails=3 fail_timeout=30s;
        server 192.168.1.11:3000 max_fails=3 fail_timeout=30s;
        keepalive 64;
    }

    # HTTP 重定向到 HTTPS
    server {
        listen 80;
        server_name example.com;
        return 301 https://$server_name$request_uri;
    }

    # HTTPS 伺服器
    server {
        listen 443 ssl http2;
        server_name example.com;

        # SSL 設定
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets off;
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 8.8.8.8 8.8.4.4 valid=300s;

        # 安全標頭
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        add_header X-Content-Type-Options nosniff;
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-XSS-Protection "1; mode=block";

        # 日誌
        access_log /var/log/nginx/websocket.access.log websocket;
        error_log /var/log/nginx/websocket.error.log warn;

        # WebSocket 端點
        location /ws/ {
            proxy_pass http://websocket_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_connect_timeout 60s;
            proxy_read_timeout 86400s;
            proxy_send_timeout 86400s;
            proxy_buffering off;
        }

        # 一般 HTTP 請求
        location / {
            proxy_pass http://http_backend;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_connect_timeout 60s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
        }

        # 健康檢查端點
        location /health {
            return 200 'OK';
            add_header Content-Type text/plain;
        }
    }

    # 狀態監控
    server {
        listen 127.0.0.1:8080;

        location /nginx_status {
            stub_status on;
            allow 127.0.0.1;
            deny all;
        }
    }
}

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy