Nginx Stream 模組提供了強大的四層(Layer 4)代理功能,可以代理 TCP 和 UDP 流量。與傳統的 HTTP 反向代理不同,Stream 模組直接在傳輸層運作,不需要解析應用層協定,因此具有更高的效能和更廣泛的應用場景。本文將詳細介紹如何在 Ubuntu 22.04 上設定 Nginx Stream 四層代理。
Nginx Stream 模組介紹
什麼是 Nginx Stream 模組?
Nginx Stream 模組是 Nginx 1.9.0 版本開始引入的功能,專門用於處理 TCP 和 UDP 流量的代理轉發。與 HTTP 模組處理七層(應用層)流量不同,Stream 模組運作在四層(傳輸層),直接轉發原始的 TCP/UDP 封包。
Stream 模組的主要功能
| 功能 | 說明 |
|---|
| TCP 代理 | 轉發 TCP 連線到後端伺服器 |
| UDP 代理 | 轉發 UDP 資料報到後端伺服器 |
| 負載平衡 | 在多個後端伺服器間分配流量 |
| SSL/TLS 終止 | 在代理層處理加密連線 |
| SSL 透傳 | 直接傳遞加密流量到後端 |
| 健康檢查 | 監控後端伺服器狀態 |
| 存取控制 | 基於 IP 位址限制存取 |
Stream 模組適用場景
- 資料庫連線代理(MySQL、PostgreSQL、Redis)
- 郵件伺服器代理(SMTP、IMAP、POP3)
- SSH 連線轉發
- DNS 代理(UDP)
- 遊戲伺服器負載平衡
- 任何需要 TCP/UDP 代理的應用程式
四層代理與七層代理差異
OSI 模型層級比較
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| ┌─────────────────────────────────────────────────────────────┐
│ Layer 7 (Application) │ HTTP, HTTPS, FTP, SMTP │
├─────────────────────────────────────────────────────────────┤
│ Layer 6 (Presentation) │ SSL/TLS, Encryption │
├─────────────────────────────────────────────────────────────┤
│ Layer 5 (Session) │ Session Management │
├─────────────────────────────────────────────────────────────┤
│ Layer 4 (Transport) │ TCP, UDP ◄── Stream 模組 │
├─────────────────────────────────────────────────────────────┤
│ Layer 3 (Network) │ IP, ICMP │
├─────────────────────────────────────────────────────────────┤
│ Layer 2 (Data Link) │ Ethernet, MAC │
├─────────────────────────────────────────────────────────────┤
│ Layer 1 (Physical) │ Physical Media │
└─────────────────────────────────────────────────────────────┘
|
四層代理 vs 七層代理
| 特性 | 四層代理(L4) | 七層代理(L7) |
|---|
| 運作層級 | 傳輸層(TCP/UDP) | 應用層(HTTP/HTTPS) |
| 效能 | 較高,不需解析應用協定 | 較低,需解析 HTTP 內容 |
| 功能 | 基於 IP 和 Port 轉發 | 可基於 URL、Header、Cookie 轉發 |
| 靈活性 | 較低,無法檢視應用內容 | 較高,可進行內容修改 |
| 適用場景 | 資料庫、郵件、SSH | Web 應用、API Gateway |
| SSL 處理 | 可終止或透傳 | 通常終止後處理 |
選擇建議
選擇四層代理的情況:
- 代理非 HTTP 協定(如資料庫、郵件)
- 需要最高效能的簡單轉發
- SSL 透傳需求
- 不需要檢視或修改應用層內容
選擇七層代理的情況:
- 需要基於 URL 路由
- 需要修改 HTTP Header
- 需要 WebSocket 支援
- 需要應用層的快取和壓縮
Stream 模組安裝與啟用
檢查 Stream 模組是否已安裝
首先檢查 Nginx 是否已包含 Stream 模組:
1
| nginx -V 2>&1 | grep -o with-stream
|
如果輸出 with-stream,表示模組已安裝。
安裝包含 Stream 模組的 Nginx
在 Ubuntu 22.04 上,預設的 Nginx 套件可能不包含 Stream 模組。需要安裝 nginx-full 或 nginx-extras:
1
2
3
4
5
6
7
8
| # 更新套件列表
sudo apt update
# 安裝 nginx-full(包含 Stream 模組)
sudo apt install nginx-full -y
# 或者安裝 nginx-extras(包含更多模組)
sudo apt install nginx-extras -y
|
驗證安裝
1
2
3
4
5
6
| # 確認 Nginx 版本和模組
nginx -V 2>&1 | grep -E "(version|with-stream)"
# 輸出範例:
# nginx version: nginx/1.18.0 (Ubuntu)
# --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module
|
建立 Stream 設定目錄
為了更好的組織設定檔,建立專用的 Stream 設定目錄:
1
2
3
4
5
| # 建立 stream 設定目錄
sudo mkdir -p /etc/nginx/stream.d
# 確認目錄結構
ls -la /etc/nginx/
|
啟用 Stream 模組
編輯主設定檔 /etc/nginx/nginx.conf,在檔案最後加入 Stream 區塊:
1
| sudo nano /etc/nginx/nginx.conf
|
在檔案結尾(http { } 區塊之外)加入:
1
2
3
4
5
6
7
8
9
10
11
12
| # Stream 模組設定
stream {
# 日誌格式定義
log_format stream_log '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" '
'"$upstream_connect_time"';
# 載入 stream 設定檔
include /etc/nginx/stream.d/*.conf;
}
|
測試設定並重新載入
1
2
3
4
5
6
7
8
| # 測試 Nginx 設定語法
sudo nginx -t
# 重新載入設定
sudo systemctl reload nginx
# 確認 Nginx 狀態
sudo systemctl status nginx
|
TCP 代理基本設定
簡單 TCP 代理
以下範例展示如何設定一個簡單的 TCP 代理,將流量從本機的 3306 埠轉發到遠端 MySQL 伺服器:
建立設定檔:
1
| sudo nano /etc/nginx/stream.d/mysql-proxy.conf
|
加入以下內容:
1
2
3
4
5
6
7
8
9
| # MySQL TCP 代理
server {
listen 3306;
proxy_pass mysql-backend.example.com:3306;
# 超時設定
proxy_connect_timeout 10s;
proxy_timeout 300s;
}
|
MySQL 代理完整範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| # MySQL 資料庫代理設定
upstream mysql_cluster {
server 192.168.1.10:3306 weight=5;
server 192.168.1.11:3306 weight=5;
server 192.168.1.12:3306 backup;
}
server {
listen 3306;
listen [::]:3306;
proxy_pass mysql_cluster;
# 連線設定
proxy_connect_timeout 10s;
proxy_timeout 300s;
# 啟用 TCP keepalive
proxy_socket_keepalive on;
# 日誌設定
access_log /var/log/nginx/mysql-proxy.log stream_log;
error_log /var/log/nginx/mysql-proxy-error.log;
}
|
Redis 代理設定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # Redis 代理設定
upstream redis_servers {
server 192.168.1.20:6379;
server 192.168.1.21:6379;
# 維持持久連線
keepalive 32;
}
server {
listen 6379;
proxy_pass redis_servers;
proxy_connect_timeout 5s;
proxy_timeout 60s;
# 連線限制
proxy_buffer_size 16k;
access_log /var/log/nginx/redis-proxy.log stream_log;
}
|
PostgreSQL 代理設定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # PostgreSQL 代理設定
upstream postgresql_cluster {
# 主資料庫(讀寫)
server 192.168.1.30:5432 weight=10;
# 從資料庫(讀取)
server 192.168.1.31:5432 weight=5;
server 192.168.1.32:5432 weight=5;
}
server {
listen 5432;
proxy_pass postgresql_cluster;
proxy_connect_timeout 10s;
proxy_timeout 600s;
access_log /var/log/nginx/postgresql-proxy.log stream_log;
}
|
SSH 轉發設定
1
2
3
4
5
6
7
8
9
10
11
12
13
| # SSH 連線轉發
server {
listen 2222;
proxy_pass internal-server.local:22;
proxy_connect_timeout 30s;
proxy_timeout 3600s; # SSH 連線可能持續很長時間
# 啟用 TCP keepalive 防止連線中斷
proxy_socket_keepalive on;
access_log /var/log/nginx/ssh-proxy.log stream_log;
}
|
UDP 代理設定
UDP 代理基礎設定
UDP 代理需要使用 udp 參數。以下是 DNS 代理的範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # DNS UDP 代理
upstream dns_servers {
server 8.8.8.8:53;
server 8.8.4.4:53;
}
server {
listen 53 udp;
proxy_pass dns_servers;
proxy_timeout 5s;
proxy_responses 1; # 期望的回應數量
access_log /var/log/nginx/dns-proxy.log stream_log;
}
|
UDP 代理重要參數
| 參數 | 說明 |
|---|
udp | 指定監聽 UDP 協定 |
proxy_responses | 期望從後端接收的 UDP 回應數量 |
proxy_timeout | 等待回應的超時時間 |
reuseport | 允許多個 worker 監聯同一埠 |
DNS 代理完整設定
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
| # DNS 代理(同時支援 UDP 和 TCP)
upstream dns_upstream {
server 8.8.8.8:53 weight=5;
server 8.8.4.4:53 weight=5;
server 1.1.1.1:53 backup;
}
# UDP DNS 代理
server {
listen 53 udp reuseport;
proxy_pass dns_upstream;
proxy_timeout 5s;
proxy_responses 1;
access_log /var/log/nginx/dns-udp.log stream_log;
}
# TCP DNS 代理(用於大型 DNS 回應)
server {
listen 53;
proxy_pass dns_upstream;
proxy_timeout 5s;
access_log /var/log/nginx/dns-tcp.log stream_log;
}
|
Syslog UDP 代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Syslog UDP 代理
upstream syslog_servers {
server 192.168.1.50:514;
server 192.168.1.51:514;
}
server {
listen 514 udp;
proxy_pass syslog_servers;
proxy_timeout 1s;
proxy_responses 0; # Syslog 不需要回應
access_log off; # 避免 log 迴圈
}
|
遊戲伺服器 UDP 代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # 遊戲伺服器 UDP 代理
upstream game_servers {
hash $remote_addr consistent; # 確保同一用戶連到同一伺服器
server 192.168.1.60:27015;
server 192.168.1.61:27015;
server 192.168.1.62:27015;
}
server {
listen 27015 udp reuseport;
proxy_pass game_servers;
proxy_timeout 30s;
proxy_responses 1;
# 緩衝區設定
proxy_buffer_size 64k;
access_log /var/log/nginx/game-server.log stream_log;
}
|
負載平衡設定
負載平衡演算法
Stream 模組支援多種負載平衡演算法:
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
| # 1. Round Robin(預設)- 輪詢
upstream backend_rr {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 2. Least Connections - 最少連線
upstream backend_lc {
least_conn;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 3. IP Hash - 基於用戶端 IP 的一致性雜湊
upstream backend_hash {
hash $remote_addr consistent;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 4. Least Time(Nginx Plus 功能)
# upstream backend_lt {
# least_time connect;
# server 192.168.1.10:8080;
# server 192.168.1.11:8080;
# }
|
權重設定
1
2
3
4
5
| upstream weighted_backend {
server 192.168.1.10:8080 weight=5; # 接收 50% 的流量
server 192.168.1.11:8080 weight=3; # 接收 30% 的流量
server 192.168.1.12:8080 weight=2; # 接收 20% 的流量
}
|
伺服器參數
1
2
3
4
5
6
| upstream backend_params {
server 192.168.1.10:8080 weight=5 max_conns=100 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 weight=3 max_conns=100 max_fails=3 fail_timeout=30s;
server 192.168.1.12:8080 backup; # 備援伺服器
server 192.168.1.13:8080 down; # 標記為離線
}
|
| 參數 | 說明 |
|---|
weight | 伺服器權重(預設為 1) |
max_conns | 最大同時連線數 |
max_fails | 失敗次數上限 |
fail_timeout | 失敗後暫停時間 |
backup | 備援伺服器 |
down | 標記為離線 |
slow_start | 緩慢啟動時間(Nginx Plus) |
完整負載平衡範例
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
| # 資料庫負載平衡設定
upstream mysql_cluster {
least_conn;
# 主伺服器群組
server 192.168.1.10:3306 weight=10 max_conns=500 max_fails=3 fail_timeout=30s;
server 192.168.1.11:3306 weight=10 max_conns=500 max_fails=3 fail_timeout=30s;
# 從伺服器群組
server 192.168.1.20:3306 weight=5 max_conns=200 max_fails=3 fail_timeout=30s;
server 192.168.1.21:3306 weight=5 max_conns=200 max_fails=3 fail_timeout=30s;
# 備援伺服器
server 192.168.1.30:3306 backup;
}
server {
listen 3306;
proxy_pass mysql_cluster;
proxy_connect_timeout 10s;
proxy_timeout 300s;
# 連線限制
proxy_next_upstream on;
proxy_next_upstream_timeout 60s;
proxy_next_upstream_tries 3;
access_log /var/log/nginx/mysql-lb.log stream_log;
}
|
SSL/TLS 終止與透傳
SSL 終止(SSL Termination)
SSL 終止是在 Nginx 代理層解密 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
| # SSL 終止設定
upstream backend_servers {
server 192.168.1.10:3306;
server 192.168.1.11:3306;
}
server {
listen 3307 ssl;
# SSL 憑證
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# SSL 設定
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# 轉發到後端(純文字)
proxy_pass backend_servers;
proxy_connect_timeout 10s;
proxy_timeout 300s;
access_log /var/log/nginx/ssl-termination.log stream_log;
}
|
SSL 透傳(SSL Passthrough)
SSL 透傳直接將加密流量轉發到後端,Nginx 不進行解密:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # SSL 透傳設定
upstream https_backend {
server 192.168.1.10:443;
server 192.168.1.11:443;
}
server {
listen 443;
# 直接透傳 SSL 流量
proxy_pass https_backend;
proxy_connect_timeout 10s;
proxy_timeout 300s;
# 使用 SSL preread 獲取 SNI
ssl_preread on;
access_log /var/log/nginx/ssl-passthrough.log stream_log;
}
|
基於 SNI 的路由
使用 ssl_preread 模組可以根據 SNI(Server Name Indication)進行路由:
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
| # SNI 路由映射
map $ssl_preread_server_name $backend_pool {
default default_backend;
app1.example.com app1_backend;
app2.example.com app2_backend;
db.example.com database_backend;
}
# 後端群組定義
upstream default_backend {
server 192.168.1.10:443;
}
upstream app1_backend {
server 192.168.1.20:443;
server 192.168.1.21:443;
}
upstream app2_backend {
server 192.168.1.30:443;
server 192.168.1.31:443;
}
upstream database_backend {
server 192.168.1.40:3306;
}
# SSL 路由伺服器
server {
listen 443;
ssl_preread on;
proxy_pass $backend_pool;
proxy_connect_timeout 10s;
proxy_timeout 300s;
access_log /var/log/nginx/sni-routing.log stream_log;
}
|
雙向 SSL(mTLS)設定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # mTLS 設定
server {
listen 8443 ssl;
# 伺服器憑證
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# 用戶端憑證驗證
ssl_client_certificate /etc/nginx/ssl/ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;
# SSL 協定設定
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
proxy_pass backend_servers;
proxy_connect_timeout 10s;
proxy_timeout 300s;
access_log /var/log/nginx/mtls.log stream_log;
}
|
轉發至 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
| # 代理層連接 SSL 後端
upstream ssl_backend {
server 192.168.1.10:3307;
}
server {
listen 3306;
proxy_pass ssl_backend;
proxy_ssl on;
# 後端 SSL 設定
proxy_ssl_certificate /etc/nginx/ssl/client.crt;
proxy_ssl_certificate_key /etc/nginx/ssl/client.key;
proxy_ssl_trusted_certificate /etc/nginx/ssl/ca.crt;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
proxy_ssl_session_reuse on;
proxy_connect_timeout 10s;
proxy_timeout 300s;
access_log /var/log/nginx/ssl-backend.log stream_log;
}
|
健康檢查設定
被動健康檢查
Nginx 開源版本支援被動健康檢查,根據連線失敗自動標記伺服器:
1
2
3
4
5
| upstream backend_passive {
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 backup;
}
|
| 參數 | 說明 |
|---|
max_fails | 達到此失敗次數後標記伺服器為不可用 |
fail_timeout | 失敗計數視窗和伺服器不可用持續時間 |
自訂健康檢查腳本
雖然開源版 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
| #!/bin/bash
# /usr/local/bin/nginx-health-check.sh
# 設定
NGINX_CONF="/etc/nginx/stream.d/backend.conf"
SERVERS=("192.168.1.10:3306" "192.168.1.11:3306" "192.168.1.12:3306")
CHECK_INTERVAL=10
TIMEOUT=5
check_server() {
local server=$1
local host=$(echo $server | cut -d: -f1)
local port=$(echo $server | cut -d: -f2)
if nc -z -w$TIMEOUT $host $port 2>/dev/null; then
return 0
else
return 1
fi
}
update_config() {
local server=$1
local status=$2
if [ "$status" == "down" ]; then
sed -i "s/server $server;/server $server down;/" $NGINX_CONF
else
sed -i "s/server $server down;/server $server;/" $NGINX_CONF
fi
nginx -t && systemctl reload nginx
}
while true; do
for server in "${SERVERS[@]}"; do
if check_server $server; then
# 伺服器健康,確保沒有 down 標記
if grep -q "server $server down;" $NGINX_CONF; then
echo "$(date): Server $server is back online"
update_config $server "up"
fi
else
# 伺服器不健康,標記為 down
if ! grep -q "server $server down;" $NGINX_CONF; then
echo "$(date): Server $server is down"
update_config $server "down"
fi
fi
done
sleep $CHECK_INTERVAL
done
|
設定為系統服務:
1
| sudo nano /etc/systemd/system/nginx-health-check.service
|
1
2
3
4
5
6
7
8
9
10
11
12
| [Unit]
Description=Nginx Health Check Service
After=nginx.service
[Service]
Type=simple
ExecStart=/usr/local/bin/nginx-health-check.sh
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
|
啟用服務:
1
2
3
4
| sudo chmod +x /usr/local/bin/nginx-health-check.sh
sudo systemctl daemon-reload
sudo systemctl enable nginx-health-check
sudo systemctl start nginx-health-check
|
使用外部監控工具
搭配 Prometheus 和 Nginx Exporter 進行監控:
1
2
3
4
| # 安裝 nginx-prometheus-exporter
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/
|
在 Nginx 設定中啟用 stub_status:
1
2
3
4
5
6
7
8
9
10
| # 在 http 區塊中加入
server {
listen 127.0.0.1:8080;
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
|
實際應用場景
場景一:MySQL 讀寫分離代理
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
| # MySQL 讀寫分離設定
# 寫入流量 -> 主資料庫
upstream mysql_master {
server 192.168.1.10:3306 max_fails=3 fail_timeout=30s;
server 192.168.1.11:3306 backup;
}
# 讀取流量 -> 從資料庫群組
upstream mysql_slaves {
least_conn;
server 192.168.1.20:3306 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.21:3306 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.22:3306 weight=5 max_fails=3 fail_timeout=30s;
}
# 寫入代理(連接埠 3306)
server {
listen 3306;
proxy_pass mysql_master;
proxy_connect_timeout 10s;
proxy_timeout 300s;
access_log /var/log/nginx/mysql-write.log stream_log;
}
# 讀取代理(連接埠 3307)
server {
listen 3307;
proxy_pass mysql_slaves;
proxy_connect_timeout 10s;
proxy_timeout 300s;
access_log /var/log/nginx/mysql-read.log stream_log;
}
|
場景二:Redis Cluster 代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| # Redis Cluster 代理設定
upstream redis_cluster {
hash $remote_addr consistent;
server 192.168.1.30:6379 max_fails=2 fail_timeout=10s;
server 192.168.1.31:6379 max_fails=2 fail_timeout=10s;
server 192.168.1.32:6379 max_fails=2 fail_timeout=10s;
server 192.168.1.33:6379 max_fails=2 fail_timeout=10s;
server 192.168.1.34:6379 max_fails=2 fail_timeout=10s;
server 192.168.1.35:6379 max_fails=2 fail_timeout=10s;
}
server {
listen 6379;
proxy_pass redis_cluster;
proxy_connect_timeout 5s;
proxy_timeout 60s;
# 提高效能
proxy_socket_keepalive on;
access_log /var/log/nginx/redis-cluster.log stream_log;
}
|
場景三:多租戶資料庫代理
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
| # 基於來源 IP 的多租戶資料庫路由
map $remote_addr $tenant_backend {
default default_db;
~^10\.0\.1\. tenant_a_db;
~^10\.0\.2\. tenant_b_db;
~^10\.0\.3\. tenant_c_db;
}
upstream default_db {
server 192.168.1.100:3306;
}
upstream tenant_a_db {
server 192.168.1.101:3306;
server 192.168.1.102:3306;
}
upstream tenant_b_db {
server 192.168.1.103:3306;
server 192.168.1.104:3306;
}
upstream tenant_c_db {
server 192.168.1.105:3306;
}
server {
listen 3306;
proxy_pass $tenant_backend;
proxy_connect_timeout 10s;
proxy_timeout 300s;
access_log /var/log/nginx/multi-tenant.log stream_log;
}
|
場景四:SSH Jump Host
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
| # SSH Jump Host 設定
# 透過不同埠號連接不同內部伺服器
# 內部 Web 伺服器
server {
listen 2201;
proxy_pass 10.0.1.10:22;
proxy_timeout 3600s;
access_log /var/log/nginx/ssh-web.log stream_log;
}
# 內部資料庫伺服器
server {
listen 2202;
proxy_pass 10.0.1.20:22;
proxy_timeout 3600s;
access_log /var/log/nginx/ssh-db.log stream_log;
}
# 內部應用伺服器
server {
listen 2203;
proxy_pass 10.0.1.30:22;
proxy_timeout 3600s;
access_log /var/log/nginx/ssh-app.log stream_log;
}
|
場景五:郵件伺服器代理
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
| # SMTP 代理
upstream smtp_servers {
server 192.168.1.50:25;
server 192.168.1.51:25;
}
server {
listen 25;
proxy_pass smtp_servers;
proxy_timeout 300s;
access_log /var/log/nginx/smtp.log stream_log;
}
# SMTPS 代理
server {
listen 465 ssl;
ssl_certificate /etc/nginx/ssl/mail.crt;
ssl_certificate_key /etc/nginx/ssl/mail.key;
ssl_protocols TLSv1.2 TLSv1.3;
proxy_pass smtp_servers;
proxy_timeout 300s;
access_log /var/log/nginx/smtps.log stream_log;
}
# IMAP 代理
upstream imap_servers {
server 192.168.1.50:143;
server 192.168.1.51:143;
}
server {
listen 143;
proxy_pass imap_servers;
proxy_timeout 600s;
access_log /var/log/nginx/imap.log stream_log;
}
# IMAPS 代理
server {
listen 993 ssl;
ssl_certificate /etc/nginx/ssl/mail.crt;
ssl_certificate_key /etc/nginx/ssl/mail.key;
ssl_protocols TLSv1.2 TLSv1.3;
proxy_pass imap_servers;
proxy_timeout 600s;
access_log /var/log/nginx/imaps.log stream_log;
}
|
場景六:遊戲伺服器負載平衡
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
| # 遊戲伺服器負載平衡
# 使用一致性雜湊確保玩家連接到同一伺服器
upstream game_tcp {
hash $remote_addr consistent;
server 192.168.1.60:27015 weight=10 max_conns=1000;
server 192.168.1.61:27015 weight=10 max_conns=1000;
server 192.168.1.62:27015 weight=10 max_conns=1000;
server 192.168.1.63:27015 backup;
}
upstream game_udp {
hash $remote_addr consistent;
server 192.168.1.60:27015;
server 192.168.1.61:27015;
server 192.168.1.62:27015;
}
# TCP 連線
server {
listen 27015;
proxy_pass game_tcp;
proxy_timeout 86400s;
proxy_socket_keepalive on;
access_log /var/log/nginx/game-tcp.log stream_log;
}
# UDP 連線
server {
listen 27015 udp reuseport;
proxy_pass game_udp;
proxy_timeout 30s;
proxy_responses 1;
access_log /var/log/nginx/game-udp.log stream_log;
}
|
效能調校
Nginx Worker 設定
在 /etc/nginx/nginx.conf 中優化 worker 設定:
1
2
3
4
5
6
7
8
9
| # 全域設定
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 65535;
use epoll;
multi_accept on;
}
|
系統核心參數調校
1
| sudo nano /etc/sysctl.d/99-nginx-stream.conf
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 網路效能調校
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# TCP 連線設定
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15
# 檔案描述符限制
fs.file-max = 2097152
|
套用設定:
1
| sudo sysctl -p /etc/sysctl.d/99-nginx-stream.conf
|
檔案描述符限制
1
| sudo nano /etc/security/limits.d/nginx.conf
|
1
2
3
4
| nginx soft nofile 65535
nginx hard nofile 65535
* soft nofile 65535
* hard nofile 65535
|
常見問題排解
檢查設定語法
查看日誌
1
2
3
4
5
6
7
8
| # 錯誤日誌
sudo tail -f /var/log/nginx/error.log
# Stream 存取日誌
sudo tail -f /var/log/nginx/mysql-proxy.log
# 即時監控所有日誌
sudo tail -f /var/log/nginx/*.log
|
連線問題排解
1
2
3
4
5
6
7
8
9
10
11
12
| # 檢查 Nginx 是否正在監聽
sudo ss -tlnp | grep nginx
# 檢查防火牆規則
sudo ufw status
sudo iptables -L -n
# 測試連線
nc -zv localhost 3306
# 檢查後端服務狀態
nc -zv 192.168.1.10 3306
|
常見錯誤訊息
| 錯誤 | 可能原因 | 解決方法 |
|---|
connect() failed | 後端伺服器未啟動或無法連線 | 確認後端服務正常運行 |
no live upstreams | 所有後端伺服器都已標記為不可用 | 檢查後端健康狀態 |
upstream timed out | 連線或讀取超時 | 調整 proxy_timeout 設定 |
bind() failed | 埠號已被占用 | 檢查埠號使用情況 |
參考資料