Websocket error with NodeBB running through a proxy server
-
I'm trying to run NodeBB through a node.js reverse proxy (https://docs.nodebb.org/configuring/proxies/node/)
I've followed every tutorial, hint/tip I can but am still experiencing issues with websocket connections to my NodeBB server, causing session problems, can't log in etc.
I hope someone can point me in the right direction to fix this.
My setup is as follows:
App 1 - http://www.mywebsite.co.uk/
- Node.js & Express
- Routing for API & frontend website
- Nothing out of the ordinary
- Full code snippet at bottom of post
I am using the 'http-proxy' npm module to proxy anyone who loads http://mywebsite.co.uk/forum to http://www.myforum.co.uk/forum
This part is working, assets load as expected.
However, there is a part of NodeBB which uses websockets to poll the forum for functionality purposes, user sessions. This part is not proxying correctly, or at least the NodeBB response is not correct and therefore giving me lots of errors:"You are accessing the forum from an unknown origin. This will likely
result in websockets failing to connect. To fix this, set the"url"
value inconfig.json
to the URL at which you access the site. For
more information, see this FAQ topic:
https://community.nodebb.org/topic/13388"
"Looks like your connection to NodeBB was lost, please wait while we
try to reconnect."And, in the network panel, lots of 'pending' requests which eventually fail with an empty response from NodeBB.
http://mywebsite.co.uk/forum/socket.io/?EIO=3&transport=polling&t=MgJQSMk
App 2 - http://www.myforum.co.uk/forum
This app is a basic NodeBB installation running, with one plugin - (https://github.com/julianlam/nodebb-plugin-session-sharing)
The config JSON file looks like this (note the URL is my frontend app's URL as per the instructions when proxying.
{ "url": "http://www.mywebsite.co.uk/forum", "secret": "secret", "database": "postgres", "port": "4567", "postgres": { "host": "HOST", "port": "PORT", "password": "PASSWORD", "database": "DATABASE" } }
I'd really appreciate if anyone can help out. Thanks.
App 1 code:
// app const express = require("express"); const app = express(); app.use(require('cookie-parser')()); app.use(require('body-parser').urlencoded({ extended: true })); app.use(require('express-session')({ secret: 'secret', resave: true, saveUninitialized: true })); // app.use((req, res, next) => { res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader( "Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, PATCH, DELETE" ); res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); next(); }); // serve the content app.use(express.static("dist")); // Frontend app.set('view engine', 'pug'); // serve out the api // app.use ... // Server set up const httpProxy = require('http-proxy'); const HttpProxyRules = require('http-proxy-rules'); // Forum urls let rules = { rules: { '/forum': 'http://www.myforum.co.uk/forum', '/forum/*': 'http://www.myforum.co.uk/forum', }, }; const proxyRules = new HttpProxyRules(rules); const proxy = httpProxy.createProxy(); app.use(function (req, res, next) { try { if (req.url.includes("socket.io") === true) { // console.log("SOCKET.IO", req.url) return proxy.web(req, res, { target: 'wss://www.myforum.co.uk', ws: true, changeOrigin: true }, function (e) { // console.log('PROXY ERR', e) // next(); }); } else { var target = proxyRules.match(req); if (target) { // console.log("TARGET", target, req.url) return proxy.web(req, res, { target: target, changeOrigin: true }, function (e) { // console.log('PROXY ERR', e) }); } else { next(); } } } catch (e) { // res.sendStatus(500); res.json({ error: e }); } }); // Frontend routes // app.use ... // HTTP const http = require('http'); // Create server mainserver = http.createServer(app); const PORT = process.env.PORT || 3000; mainserver.listen(PORT); mainserver.on('listening', onListening); mainserver.on('error', function (error, req, res) { let json; console.log('proxy error', error); if (!res.headersSent) { res.writeHead(500, { 'content-type': 'application/json' }); } json = { error: 'proxy_error', reason: error.message }; res.end(JSON.stringify(json)); }); function onListening() { console.log(`Listening on :${PORT}`); }
-
To resolve this, I changed the Proxy module I was using. It uses less code to implement and works with websockets. I think the NodeBB Node.js proxy documentation is out of date so I'll be submitting a PR with the new method I found.
Working code is as follows:
/** * Proxy forum */ const proxy = require('http-proxy-middleware'); // Forum Proxy app.use( '/forum', proxy({ target: 'http://www.myforum.co.uk/forum', changeOrigin: true, ws: true, }) );
Another potential GOTCHA here is that this Prixy setup needs to be declared ABOVE the 'body-parser' module (if it's being used). The wrong order will prevent post requests from being proxied.