老闆!來一個能支援 Socket.io 的 NGINX Reverse Proxy Server 吧!

NGINX 是一個現在相當多人使用的 HTTP 伺服器程式,他能做的事情非常的多,而且重點在於它效率更快更好。但今天這篇文章並不是要來介紹 NGINX 有多好,而是要來帶大家設定 NGINX 的反向代理(Reverse proxy)伺服器,讓你其他不是單純 HTTP 的網站程式(如Node.js)也能夠利用到 NGINX 的眾多好處。

為什麼需要

開始之前我們還是先來了解一下為什麼我們需要反向代理這樣的東西。

很多時候,我們為了隱藏後方真正在執行運算的伺服器程式,以及減輕主要運算伺服器的負擔等需求,我們會需要一個代理伺服器在前方處理來自網際網路的請求。

以下是維基百科對使用反向代理伺服器所列的原因。

  • 加密和SSL加速
  • 負載平衡
  • 快取靜態內容
  • 壓縮
  • 減速上傳
  • 安全
  • 外網發布

設定反向代理

我想我就認為大家都知道 NGINX 的設定檔在哪裡好了,如果找不到的話,以 Ubuntu Server 為例,他們被放在 /etc/nginx/sites-available/ 之中。

好的,再來我們假設我有一個以Node.js撰寫的伺服器程式運作在本機(localhost)的6666連接埠上,然後我不想要讓這個伺服器程式可以直接的從外部透過連接埠連接,只想讓它從正常的管道並且是透過test.single9.net這網址連接進來的話,那麼我的 NGINX 伺服器設定檔會是這個樣子:

  
server {
    listen 80;
    server_name test.single9.net;

    location / {
        proxy_pass http://127.0.0.1:6666;   # 伺服器程式位址與連接埠

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
    }
}

誒嘿,這樣就設定完了最基本的反向代理伺服器了。沒了。

設定 Socket.io

不過事實上這樣子還不夠完善,因為如果只設定這樣的話,我們傳說中的 Socket.io 是無法正常運作的,所以我們還要改成這樣:

server {
    listen 80;
    server_name test.single9.net;

    ## 加入這段 ##
    location ~* \.io {
        proxy_pass http://127.0.0.1:6666;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }

    location / {
        proxy_pass http://127.0.0.1:6666;   # 伺服器程式位址與連接埠
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
    }
}

加入這一段設定的目跟 Socket.io 的結構有點關係,因為 Socket.io 將連線用的路由設定在額外的一個連線位址(/socket.io/),這位址無法正常的NGINX解析並代理,因此我們需要這樣的一個設定。

反向代理IP轉發

設定完反向代理伺服器後,我們又遭遇了一個新的問題:Node.js伺服器程式拿不到正確的客戶端IP位址,一直都是127.0.0.1!

要解決這個問題,我們需要請 NGINX 幫我們設定一些HTTP標頭(HTTP Headers),將反向代理的客戶端IP位址一起附帶到HTTP請求之中。如此一來,我們的伺服器程式便可以透過這個新增的HTTP標頭取得正確的IP位址資訊。

server {
    listen 80;
    server_name test.single9.net;

    location ~* \.io {
        proxy_pass http://127.0.0.1:6666;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header X-Real-IP $remote_addr;                       # 加入 X-Real-IP Header
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   # 加入 X-Forwarded-For Header
        proxy_redirect off;
    }

    location / {
        proxy_pass http://127.0.0.1:6666;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;                       # 加入 X-Real-IP Header
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   # 加入 X-Forwarded-For Header
    }
}

Node.js

Express.js

app.set('trust proxy', true);

app.get("/", (req, res, next) => {
    res.end(req.ip);
});

(按下右下角的 ► 按鈕可以看到執行效果,完整預覽點這裡。)

最後

好的,NGINX反向代理的部分就到這裡結束,希望各位有學到如何設定啦~

下一篇文章,我將會帶各位利用NGINX的反向代理來讓原本由後端伺服器程式輸出的靜態檔案交由NGINX來送出,降低後端伺服器的負擔,讓後端伺服器專心處理他該做的事情。

獨夜:

看評論 (2)

你可能也會有興趣