Hello. It took me more than 2 minutes to find the relevant info online so I decided to put it here for others for a quick reference. I am using Express and node-http-proxy to make a gateway that will also authenticate players for my game and then proxy their WebSocket traffic to the dedicated game server.
tl;dr: Express returns the Node HTTP server instance on which you can listen to an upgrade
event and use the proxy's ws
method.
Code-thing
I'll just share the whole thing:
import process from "process";
import express from "express";
import proxy from "http-proxy";
import cors from "cors";
import { logger } from "./logger.js";
import {
ALLOWED_ORIGIN,
IS_DEVELOPMENT,
PORT,
UPSTREAM_GAME_SERVER,
} from "./config.js";
const app = express();
app.disable("x-powered-by");
app.use(cors({ origin: ALLOWED_ORIGIN }));
app.get("/", (req, res) => {
res.send({ hi: "hello" });
});
const gameProxy = proxy.createProxyServer({});
app.all("/game/*", (req, res) => {
// This is for proxying regular traffic. The option { ws: true } did not work :shrug:
gameProxy.web(req, res, { target: UPSTREAM_GAME_SERVER });
});
// This is probably a bad idea, I should check for IS_PRODUCTION for binding to 0.0.0.0
const HOST = IS_DEVELOPMENT ? "127.0.0.1" : "0.0.0.0";
const http = app.listen(PORT, HOST);
http.on("upgrade", (req, socket) => {
// Papam! Proxy the WebSockets.
gameProxy.ws(req, socket, { target: UPSTREAM_GAME_SERVER });
});
function shutdown(signal: NodeJS.Signals) {
logger.info(`Caught signal ${signal}`);
http.close(() => {
logger.info("The HTTP server was closed");
});
}
process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);
logger.info(`Gateway proxy listening on port ${PORT}, host: ${HOST}`);
logger.info(`Proxying /game to ${UPSTREAM_GAME_SERVER}`);
logger.info(`Allowed origin: ${ALLOWED_ORIGIN}`);
Easy, right?
Some words about the game I'm developing: It's an online persistent-universe single player/cooperative gameplay 4X/resource-management space game targeting an audience that can't afford playing games for long sessions.
I want to separate the game server's logic from the authentication logic and all that, so creating a gateway server that authenticates players and proxies their traffic to the game server under a decorated route seems the way to go.