0

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.

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 in config.json to the URL at which you access the site. For more information, see this FAQ topic: https://community.nodebb.org/topic/13388"

Also:

"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"
    }
}

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}`);
}
halfer
  • 19,824
  • 17
  • 99
  • 186
danlong
  • 880
  • 1
  • 8
  • 21

1 Answers1

1

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 updating 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.

danlong
  • 880
  • 1
  • 8
  • 21