ESC

開始輸入,可搜尋發票、服務、域名、工單,以及 更多...

搜尋... Ctrl+K
Linux 伺服器

Nginx 反向代理配置教程:Node/Python 應用、WebSocket、真實 IP、HTTPS 與 502 排查

6 個步驟 11 分鐘閱讀 29 次閱讀 0
本文目錄

Node.js、Python(Flask/Django/FastAPI)、Go 等應用通常監聽在 127.0.0.1:3000 這類本地埠,不適合直接暴露到公網。本文講解如何用 Nginx 反向代理把域名請求轉發給後端應用,並正確處理 WebSocket、獲取客戶端真實 IP、用 certbot 配置免費 HTTPS,最後整理 502 Bad Gateway 的常見原因。命令適用於 Debian/Ubuntu 與 Rocky Linux/AlmaLinux。

步驟 1:安裝 Nginx 並確認後端應用正常

先確保應用本身能在伺服器本地訪問,否則後面的反向代理一定會報 502。建議應用只監聽 127.0.0.1,由 Nginx 統一對外,並用 systemd 或 pm2 等守護程序保證應用崩潰後自動重啟。

# Debian / Ubuntu
apt update && apt install -y nginx
# Rocky Linux / AlmaLinux
dnf install -y nginx

systemctl enable --now nginx

# Make sure the backend app is listening locally (example: port 3000)
ss -lntp | grep 3000
curl -I http://127.0.0.1:3000

步驟 2:編寫 Nginx 反向代理配置(含 WebSocket)

把域名解析到伺服器 IP 後,新建 /etc/nginx/conf.d/app.conf。map 段讓普通請求和 WebSocket 升級請求都能被正確處理;X-Forwarded-* 頭把客戶端 IP 和原始協議傳給後端;proxy_read_timeout 調大可避免長連線或慢介面被提前斷開。如需上傳大檔案,相應調大 client_max_body_size。

# /etc/nginx/conf.d/app.conf  (included on Debian/Ubuntu and Rocky/AlmaLinux)
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    listen [::]:80;
    server_name app.example.com;

    client_max_body_size 20m;

    location / {
        proxy_pass http://127.0.0.1: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;

        # WebSocket support
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_connect_timeout 10s;
        proxy_read_timeout    300s;
    }
}

步驟 3:檢查配置、過載 Nginx 並放行防火牆

每次修改後先用 nginx -t 檢查語法再過載。Rocky/AlmaLinux 預設開啟 SELinux,會阻止 Nginx 連線後端埠,需要開啟 httpd_can_network_connect。防火牆放行 80 和 443(更多規則見“Linux 防火牆”教程)。

nginx -t && systemctl reload nginx
curl -I -H "Host: app.example.com" http://127.0.0.1

# Rocky/AlmaLinux (SELinux): allow Nginx to connect to backend ports
setsebool -P httpd_can_network_connect 1

# Open HTTP/HTTPS in the firewall
ufw allow 'Nginx Full'                                   # Debian/Ubuntu with ufw
firewall-cmd --permanent --add-service=http --add-service=https
firewall-cmd --reload                                    # Rocky/AlmaLinux

步驟 4:讓後端應用獲取客戶端真實 IP

經過反向代理後,應用看到的來源 IP 都是 127.0.0.1。Nginx 已經通過 X-Real-IP 和 X-Forwarded-For 傳遞真實 IP,還需要讓應用框架“信任”本機代理。如果 Nginx 前面還有 CDN 或負載均衡,則要在 Nginx 中用 real_ip 模組還原,只信任 CDN 的地址段,防止偽造。

// Node.js / Express: trust the proxy on localhost
app.set('trust proxy', 'loopback');
// req.ip now returns the real client IP

# Python Flask / any WSGI app
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)

# Gunicorn
gunicorn --bind 127.0.0.1:8000 --forwarded-allow-ips="127.0.0.1" app:app

# Only if Nginx itself sits behind a CDN or load balancer (http or server block):
set_real_ip_from 203.0.113.0/24;     # the CDN / LB address ranges
real_ip_header X-Forwarded-For;
real_ip_recursive on;

步驟 5:用 certbot 為反向代理配置 HTTPS

certbot 的 nginx 外掛會自動申請 Let's Encrypt 證書、在配置中加入 443 監聽,並用 --redirect 把 HTTP 跳轉到 HTTPS。申請前請確認域名已解析到本機且 80 埠可從公網訪問。證書有效期 90 天,安裝後會自動續期。

# Debian / Ubuntu
apt install -y certbot python3-certbot-nginx
# Rocky Linux / AlmaLinux (EPEL)
dnf install -y epel-release && dnf install -y certbot python3-certbot-nginx

certbot --nginx -d app.example.com --redirect -m [email protected] --agree-tos --no-eff-email

# Renewal runs from a systemd timer; test it:
certbot renew --dry-run
systemctl list-timers | grep -i certbot
使用 HTTPS 後,後端生成的連結若仍是 http://,通常是框架沒有讀取 X-Forwarded-Proto,請按步驟 4 配置信任代理。

步驟 6:Nginx 502 Bad Gateway 常見原因排查

502 表示 Nginx 無法從後端拿到正常響應。先看 Nginx 錯誤日誌,根據關鍵字判斷:連線被拒絕說明應用沒執行或埠不對;Permission denied 多為 SELinux;還要注意 Node 17 以上版本中 localhost 可能解析為 IPv6 的 ::1,導致應用只監聽 [::1]:3000,而 Nginx 連線的是 127.0.0.1。

tail -n 50 /var/log/nginx/error.log

# connect() failed (111: Connection refused)  -> app stopped or wrong port
# connect() ... (13: Permission denied)       -> SELinux: setsebool -P httpd_can_network_connect 1
# upstream prematurely closed connection      -> app crashed / restarted
# upstream timed out (110)                    -> app too slow: raise proxy_read_timeout or fix the app

systemctl status myapp
journalctl -u myapp -n 100 --no-pager
ss -lntp | grep -E ':3000|:8000'      # 127.0.0.1:3000 vs [::1]:3000 ?

常見問題

WebSocket 連線失敗,提示 400 或連線立即斷開?

檢查是否設定了 proxy_http_version 1.1 以及 Upgrade/Connection 兩個頭;如果前面還有 CDN,需要在 CDN 端開啟 WebSocket 支援。空閒連線預設 60 秒斷開,可調大 proxy_read_timeout 或讓應用傳送心跳。

一個伺服器上能反向代理多個應用嗎?

可以。每個域名寫一個 server 塊,指向不同埠即可;也可以在同一域名下用不同 location 路徑轉發。如果需要每個站點使用獨立 IP,可參考“每站獨立 IP(Nginx)”教程。

訪問出現 504 Gateway Timeout?

504 表示後端響應超時。請最佳化慢請求,或適當調大 proxy_read_timeout,並檢查應用日誌是否卡在資料庫或外部介面。

如果按以上步驟操作後問題仍未解決,請提交工單聯絡 IMIDC 7×24 技術支援,並附上伺服器 IP、系統版本、執行過的命令和完整報錯資訊,方便工程師快速定位。

這篇文章有幫助嗎?

相關教程