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
- 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.
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');