I am working on a Node.js proxy server that routes requests from a website to a localhost endpoint. The website can run either locally or on a cloud instance, so the proxy needs to support both HTTP and HTTPS requests and route them to the HTTP endpoint.
The code below works for almost all use cases, except when Websocket requests originate from an HTTPS address. Here is the code:
import * as express from "express";
import { Server, createServer } from "http";
import { createProxyServer } from "http-proxy";
import { settings } from "./settings"
export let port = 3004;
let server: Server;
export function startServer() {
const URL = settings.URL;
const app = express();
server = createServer(app);
const proxy = createProxyServer({
target: URL,
changeOrigin: !URL.includes("localhost"),
ws: true,
headers: {
// Attach request headers
},
});
server.on("upgrade", function (req, socket, head) {
proxy.ws(req, socket, head, {});
});
app.get("/public/*", function (req, res) {
proxy.web(req, res, {});
});
app.get("/api/*", function (req, res) {
proxy.web(req, res, {});
});
app.post("/api/query", function (req, res) {
proxy.web(req, res, {});
});
server.listen(0, () => {
port = server?.address()?.port;
console.log("Server started");
});
}
export function stopServer() {
if (server) {
server.close();
}
}
The line changeOrigin: !URL.includes("localhost") sets changeOrigin based on the host. It's unnecessary for localhost requests, but required for HTTPS requests.
This code, however, fails for the Websocket requests and returns the following error:
WebSocket connection to 'ws://localhost:61958/api/ws' failed:
//...
ERR read ECONNRESET: Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
at TCP.callbackTrampoline (node:internal/async_hooks:130:17)
If I do not set changeOrigin for the Websocket endpoint via:
server.on("upgrade", function (req, socket, head) {
proxy.ws(req, socket, head, {changeOrigin: false});
});
I get a different kind of error:
ERR Client network socket disconnected before secure TLS connection was established:
Error: Client network socket disconnected before secure TLS connection was established
at connResetException (node:internal/errors:704:14)
at TLSSocket.onConnectEnd (node:_tls_wrap:1590:19)
at TLSSocket.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1358:12)
at process.processTicksAndRejections (node:internal/process/task_queues:83:21)
Any ideas on how to fix this? I feel like I'm overlooking something simple, but can't figure it out.
createSecureServer, notcreateServer. And use a private key and (self-signed) certificate.