配置 Nginx 反向代理 WebSocket


用Nginx給網站做反向代理和負載均衡是廣泛使用的一種Web服務器部署技術。不僅能夠保證后端服務器的隱蔽性,還可以提高網站部署靈活性。

今天我們來講一下,如何用Nginx給WebSocket服務器實現反向代理和負載均衡。

什么是反向代理和負載均衡

  • 反向代理(Reverse Proxy)方式是指以代理服務器來接受Internet上的連接請求,然后將請求轉發給內部網絡上的服務器。並將內部服務器上得到的結果返回給Internet上請求連接的客戶端,此時代理服務器對外就表現為一個服務器。
  • 負載均衡(Load Balancing)建立在現有網絡結構之上,它提供了一種廉價有效透明的方法擴展網絡設備和服務器的帶寬、增加吞吐量、加強網絡數據處理能力、提高網絡的靈活性和可用性。

什么是WebSocket

WebSocket協議相比較於HTTP協議成功握手后可以多次進行通訊,直到連接被關閉。但是WebSocket中的握手和HTTP中的握手兼容,它使用HTTP中的Upgrade協議頭將連接從HTTP升級到WebSocket。這使得WebSocket程序可以更容易的使用現已存在的基礎設施。

WebSocket工作在HTTP的80和443端口並使用前綴ws://或者wss://進行協議標注,在建立連接時使用HTTP/1.1的101狀態碼進行協議切換,當前標准不支持兩個客戶端之間不借助HTTP直接建立Websocket連接。

更多Websocket的介紹可參考「WebSocket教程」一文。

創建基於Node的WebSocket服務

Nginx在官方博客上給出了一個實踐樣例「Using Nginx as a Websocket Proxy」,我們以這個例子來演示WebSocket的交互過程。

這個例子中將會使用到nodejs的一個WebSocket的ws模塊。

安裝node.js和npm

  • Debian/Ubuntu
$ apt-get install nodejs npm
  • RHEL/CentOS
$ yum install nodejs npm

創建nodejs軟鏈

在Ubuntu上創建一個名叫node軟鏈。Centos默認為node,不用在單獨創建了。

# 如果不創建,后面運行wscat時Ubuntu環境中會報錯。
$ ln -s /usr/bin/nodejs /usr/bin/node

安裝ws和wscat模塊

ws是nodejs的WebSocket實現,我們借助它來搭建簡單的WebSocket Echo Server。wscat是一個可執行的WebSocket客戶端,用來調試WebSocket服務是否正常。

$ npm install ws wscat

如果訪問官方倉庫比較慢的話,可用淘寶提供的鏡像服務。

$ npm --registry=https://registry.npm.taobao.org install ws wscat

創建一個簡單的服務端

這個簡單的服務端實現的是向客戶端返回客戶端發送的消息。

$ vim server.js

console.log("Server started");
var Msg = '';
var WebSocketServer = require('ws').Server
    , wss = new WebSocketServer({port: 8010});
    wss.on('connection', function(ws) {
        ws.on('message', function(message) {
        console.log('Received from client: %s', message);
        ws.send('Server received from client: ' + message);
    });
 });

運行這個簡單的echo服務

$ node server.js
Server started

驗證服務端是否正常啟動

$ netstat  -tlunp|grep 8010
tcp6       0      0 :::8010                 :::*                    LISTEN      23864/nodejs

使用wscat做為客戶端測試

wscat命令默認安裝當前用戶目錄node_modules/wscat/目錄,我這里的位置是/root/node_modules/wscat/bin/wscat

輸入任意內容進行測試,得到相同返回則說明運行正常。

$ cd /root/node_modules/wscat/bin/
$ ./wscat --connect ws://127.0.0.1:8010

connected (press CTRL+C to quit)
> Hello
< Server received from client: Hello

> Welcome to www.hi-linux.com
< Server received from client: Welcome to www.hi-linux.com

使用Nginx對WebSocket進行反向代理

安裝Nginx

  • 下載對應軟件包

Nginx從1.3.13版本就開始支持WebSocket了,並且可以為WebSocket應用程序做反向代理和負載均衡。這里Nginx選用1.9.2版本。

$ cd /root
$ wget 'http://nginx.org/download/nginx-1.9.2.tar.gz'
  • 編譯安裝Nginx
$ apt-get install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl make build-essential
$ tar xzvf nginx-1.9.2.tar.gz
$ cd nginx-1.9.2
$ ./configure
$ make && make install

配置Nginx

  • 修改Nginx主配置文件
$ vim /usr/local/nginx/conf/nginx.conf

# 在http上下文中增加如下配置,確保Nginx能處理正常http請求。

http {

  map $http_upgrade $connection_upgrade {
    default upgrade;
    ''   close;
  }

  upstream websocket {
    #ip_hash;
    server localhost:8010;  
    server localhost:8011;
  }

# 以下配置是在server上下文中添加,location指用於websocket連接的path。

  server {
    listen       80;
    server_name localhost;
    access_log /var/log/nginx/yourdomain.log;

    location / {
      proxy_pass http://websocket;
      proxy_read_timeout 300s;

      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_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
		}
	}
}

最重要的就是在反向代理的配置中增加了如下兩行,其它的部分和普通的HTTP反向代理沒有任何差別。

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

這里面的關鍵部分在於HTTP的請求中多了如下頭部:

Upgrade: websocket
Connection: Upgrade

這兩個字段表示請求服務器升級協議為WebSocket。服務器處理完請求后,響應如下報文:

# 狀態碼為101
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade

告訴客戶端已成功切換協議,升級為Websocket協議。握手成功之后,服務器端和客戶端便角色對等,就像普通的Socket一樣,能夠雙向通信。不再進行HTTP的交互,而是開始WebSocket的數據幀協議實現數據交換。

這里使用map指令可以將變量組合成為新的變量,會根據客戶端傳來的連接中是否帶有Upgrade頭來決定是否給源站傳遞Connection頭,這樣做的方法比直接全部傳遞upgrade更加優雅。

默認情況下,連接將會在無數據傳輸60秒后關閉,proxy_read_timeout參數可以延長這個時間或者源站通過定期發送ping幀以保持連接並確認連接是否還在使用。

  • 啟動Nginx

Nginx會默認安裝到/usr/local/nginx目錄下。

$ cd /usr/local/nginx/sbin
$ ./nginx -c /usr/local/nginx/conf/nginx.conf

如果你想以Systemd服務的方式更方便的管理Nginx,可參考「基於Upsync模塊實現Nginx動態配置」 一文。

  • 測試通過Nginx訪問WebSocket服務

上面的配置會使NGINX監聽80端口,並把接收到的任何請求傳遞給后端的WebSocket服務器。我們可以使用wscat作為客戶端來測試一下:

$ cd /root/node_modules/wscat/bin/
$ ./wscat --connect ws://192.168.2.210
connected (press CTRL+C to quit)
> Hello Nginx
< Server received from client: Hello Nginx
> Welcome to www.hi-linux.com
< Server received from client: Welcome to www.hi-linux.com
  • 反向代理服務器在支持WebSocket時面臨的挑戰

WebSocket是端對端的,所以當一個代理服務器從客戶端攔截一個Upgrade請求,它需要去發送它自己的Upgrade請求到后端服務器,也包括合適的頭。

因為WebSocket是一個長連接,不像HTTP那樣是典型的短連接,所以反向代理服務器需要允許連接保持着打開,而不是在它們看起來空閑時就將它們關閉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM