|
|
@@ -0,0 +1,229 @@ |
|
|
Set up nginx proxy to nodejs websocket |
|
|
* * * |
|
|
Tài liệu này trình bày hai cách cấu hình, `https ở nginx -> wss nodejs` hoặc từ `https ở nginx -> ws` ở nodejs |
|
|
|
|
|
Để điều hướng request từ cổng 443 vào websocket server (demo bằng nodejs) |
|
|
|
|
|
* Yêu cầu, chạy nginx 1.4 trên ubuntu |
|
|
|
|
|
# From https to wss |
|
|
* nginx nghe cổng 443, toàn bộ request `wss://domain.com/ws` sẽ được chuyển về `wss://127.0.0.1:2910` |
|
|
tức là cả nginx và nodejs websocket server đều chạy https |
|
|
|
|
|
file websocketserver.js |
|
|
``` |
|
|
import * as https from 'https'; |
|
|
import * as fs from 'fs'; |
|
|
import * as websocket from 'websocket'; |
|
|
|
|
|
export class WS { |
|
|
private httpserver; |
|
|
|
|
|
public constructor(keypath:string, certpath:string) { |
|
|
var option = { |
|
|
key: fs.readFileSync(keypath), |
|
|
cert: fs.readFileSync(certpath) |
|
|
}; |
|
|
|
|
|
this.httpserver = https.createServer(option, function (req, res) { |
|
|
res.writeHead(404); |
|
|
res.end(); |
|
|
}); |
|
|
} |
|
|
|
|
|
public run() { |
|
|
var me = this; |
|
|
|
|
|
this.httpserver.listen(2910, function () { |
|
|
console.log('Websocket server / OK / ' + 2910); |
|
|
}); |
|
|
|
|
|
var wsServer = new websocket.server({ |
|
|
httpServer: me.httpserver, |
|
|
autoAcceptConnections: false |
|
|
}); |
|
|
|
|
|
function originIsAllowed(origin:string) { |
|
|
// put logic here to detect whether the specified origin is allowed. |
|
|
return true; |
|
|
} |
|
|
|
|
|
wsServer.on('request', function (request) { |
|
|
if (!originIsAllowed(request.origin)) { |
|
|
// Make sure we only accept requests from an allowed origin |
|
|
request.reject(); |
|
|
console.log((new Date()) + 'Connection from origin ' + request.origin + ' rejected.'); |
|
|
return; |
|
|
} |
|
|
console.log('new coming'); |
|
|
var connection = request.accept('proto', request.origin); |
|
|
connection.on('message', function (message) { |
|
|
console.log('received: ' + message); |
|
|
}); |
|
|
|
|
|
connection.on('close', function (reasonCode, description) { |
|
|
console.log('closed'); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
new WS('./key.pem', './cert.cert').run(); |
|
|
``` |
|
|
cấu hình nginx |
|
|
``` |
|
|
upstream websocket { |
|
|
server 127.0.0.1:2910; |
|
|
} |
|
|
|
|
|
server { |
|
|
charset utf-8; |
|
|
listen 443; |
|
|
|
|
|
server_name domain.com; |
|
|
ssl on; |
|
|
ssl_certificate /etc/ssl/certs/chained.pem; |
|
|
ssl_certificate_key /etc/ssl/private/domain.key; |
|
|
ssl_session_timeout 5m; |
|
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; |
|
|
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-G\ |
|
|
CM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES\ |
|
|
128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA; |
|
|
ssl_session_cache shared:SSL:50m; |
|
|
ssl_dhparam /etc/ssl/certs/dhparam.pem; |
|
|
ssl_prefer_server_ciphers on; |
|
|
|
|
|
access_log /home/thanhpk/tmp/meotrics-access443.log; |
|
|
error_log /home/thanhpk/tmp/meotrics-error443.log; |
|
|
|
|
|
location /ws { |
|
|
proxy_pass https://websocket; |
|
|
proxy_http_version 1.1; |
|
|
proxy_set_header Upgrade $http_upgrade; |
|
|
proxy_set_header Connection $connection_upgrade; |
|
|
} |
|
|
} |
|
|
``` |
|
|
nginx sẽ gửi request tới https://127.0.0.1:2910/ws, tuy nhiên sẽ bị chặn lại bởi key và cert của nodejs chưa đăng ký -> cần tự xác thực một certificate dùng trong server. |
|
|
|
|
|
Gõ lệnh sau đây ở ubuntu |
|
|
|
|
|
``` |
|
|
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.crt -days 100 -nodes |
|
|
``` |
|
|
|
|
|
Nhập thông tin cho certificate, chú ý, khi nhập _Common Name (eg, your name or your FQDN of the server)_ phải điền `127.0.0.1`. Nếu bỏ qua bước này, sinh lại certificate và nhập lại. |
|
|
|
|
|
Sau khi sinh, sẽ có 2 file key.pem và cert.crt |
|
|
vào terminal gõ |
|
|
``` |
|
|
apt-get install ca-certificates |
|
|
cp cert.crt /usr/share/ca-certificates |
|
|
dpkg-reconfigure ca-certificates |
|
|
``` |
|
|
Chọn ask, rồi tìm và tích chọn _cert.crt_ để báo cho hệ thống biết _cert.crt_ là một cert hợp lệ. |
|
|
|
|
|
Cuối cùng, chạy nodejs server bằng cách gõ `node websocketserver.js` vào terminal. Thử lại bằng cách vào trình duyệt Chrome, bật cửa số console, gõ |
|
|
|
|
|
``` |
|
|
var ws = new WebSocket('wss://domain.com/ws', 'proto'); |
|
|
``` |
|
|
Cửa số terminal chạy nodejs sẽ hiển thị thông tin kết nối. |
|
|
|
|
|
# From https to ws |
|
|
nginx chạy https:443 còn nodejs chạy ws bình thường, khi cấu hình kiểu này, ko cần bước tự ký nữa |
|
|
|
|
|
file websocketserver.js |
|
|
``` |
|
|
import * as http from 'http'; |
|
|
import * as fs from 'fs'; |
|
|
import * as websocket from 'websocket'; |
|
|
|
|
|
export class WS { |
|
|
private httpserver; |
|
|
|
|
|
public constructor() { |
|
|
this.httpserver = https.createServer(function (req, res) { |
|
|
res.writeHead(404); |
|
|
res.end(); |
|
|
}); |
|
|
} |
|
|
|
|
|
public run() { |
|
|
var me = this; |
|
|
|
|
|
this.httpserver.listen(2910, function () { |
|
|
console.log('Websocket server / OK / ' + 2910); |
|
|
}); |
|
|
|
|
|
var wsServer = new websocket.server({ |
|
|
httpServer: me.httpserver, |
|
|
autoAcceptConnections: false |
|
|
}); |
|
|
|
|
|
function originIsAllowed(origin:string) { |
|
|
// put logic here to detect whether the specified origin is allowed. |
|
|
return true; |
|
|
} |
|
|
|
|
|
wsServer.on('request', function (request) { |
|
|
if (!originIsAllowed(request.origin)) { |
|
|
// Make sure we only accept requests from an allowed origin |
|
|
request.reject(); |
|
|
console.log((new Date()) + 'Connection from origin ' + request.origin + ' rejected.'); |
|
|
return; |
|
|
} |
|
|
console.log('new coming'); |
|
|
var connection = request.accept('proto', request.origin); |
|
|
connection.on('message', function (message) { |
|
|
console.log('received: ' + message); |
|
|
}); |
|
|
|
|
|
connection.on('close', function (reasonCode, description) { |
|
|
console.log('closed'); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
new WS().run(); |
|
|
``` |
|
|
cấu hình nginx |
|
|
``` |
|
|
upstream websocket { |
|
|
server 127.0.0.1:2910; |
|
|
} |
|
|
|
|
|
server { |
|
|
charset utf-8; |
|
|
listen 443; |
|
|
|
|
|
server_name domain.com; |
|
|
ssl on; |
|
|
ssl_certificate /etc/ssl/certs/chained.pem; |
|
|
ssl_certificate_key /etc/ssl/private/domain.key; |
|
|
ssl_session_timeout 5m; |
|
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; |
|
|
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-G\ |
|
|
CM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES\ |
|
|
128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA; |
|
|
ssl_session_cache shared:SSL:50m; |
|
|
ssl_dhparam /etc/ssl/certs/dhparam.pem; |
|
|
ssl_prefer_server_ciphers on; |
|
|
|
|
|
access_log /home/thanhpk/tmp/meotrics-access443.log; |
|
|
error_log /home/thanhpk/tmp/meotrics-error443.log; |
|
|
|
|
|
location /ws { |
|
|
proxy_pass http://websocket; |
|
|
proxy_http_version 1.1; |
|
|
proxy_set_header Upgrade $http_upgrade; |
|
|
proxy_set_header Connection $connection_upgrade; |
|
|
} |
|
|
} |
|
|
``` |
|
|
chạy nodejs server bằng cách gõ |
|
|
node websocketserver.js, |
|
|
|
|
|
vào trình duyệt, bật cửa số console, gõ |
|
|
var ws = new WebSocket('wss://domain.com/ws', 'proto'); |