Simple HTTP | HTTPS | WS | WSS reverse proxy
npm install fimiproxysimple HTTP | HTTPS | WS | WSS reverse proxy in node.js. currently supports:
- reverse proxy using incoming request's x-forwarded-host or host header to pre-configured origin servers. see Host and X-Forwarded-Host
- proxy incoming http: or https: request to origin http: or https: servers
- proxy incoming ws: or wss: request to origin ws: or wss: servers
- supports graceful shutdowns
- supports round-robin origin server selection
- supports force upgrade http: to https: and ws: to wss:
- supports forced redirects for host migration
- supports URL parts preservation during redirects
- for global installation npm i fimiproxy -g
- for local installation npm i fimiproxy
- for local dev-dependency installation npm i fimiproxy -D
replace npm with yarn or any other package manager of choice.
``json`
{
"exposeHttpProxy": false,
"httpPort": "",
"exposeHttpsProxy": false,
"httpsPort": "",
"exposeWsProxyForHttp": false,
"exposeWsProxyForHttps": false,
"httpsPublicKeyFilepath": "",
"httpsPrivateKeyFilepath": "",
"httpsPublicKey": "",
"httpsPrivateKey": "",
"debug": false,
"routes": [
{
"origin": [
{
"originHost": "",
"originPort": "",
"originProtocol": "http:"
},
{
"originHost": "",
"originPort": "",
"originProtocol": "ws:"
}
],
"incomingHostAndPort": "",
"forceUpgradeHttpToHttps": false,
"forceUpgradeWsToWss": false,
"forceRedirect": false,
"usePermanentRedirect": false,
"redirectHost": "",
"redirectURLParts": false,
"overrideHost": ""
}
],
"forceUpgradeHttpToHttps": false,
"forceUpgradeWsToWss": false,
"usePermanentRedirect": false,
"redirectHost": "",
"redirectURLParts": false
}
- exposeHttpProxy — set to true to expose an HTTP server, requires httpPort to be set if trueexposeHttpsProxy
- — set to true to expose an HTTPS server, requires httpsPort, httpsPublicKey OR httpsPublicKeyFilepath, httpsPrivateKey OR httpsPrivateKeyFilepath to be set if trueexposeWsProxyForHttp
- — set to true to expose a WebSocket server for HTTP requests, requires httpPort and exposeHttpProxy to be set if trueexposeWsProxyForHttps
- — set to true to expose a WebSocket server for HTTPS requests, requires httpsPort and exposeHttpsProxy to be set if truehttpPort
- — port HTTP server should listen on, when exposeHttpProxy is truehttpsPort
- — port HTTPS server should listen on, when exposeHttpsProxy is truehttpsPublicKeyFilepath
- — filepath to TLS certificate (public key) used with HTTPS serverhttpsPrivateKeyFilepath
- — filepath to TLS private key used with HTTPS serverhttpsPublicKey
- — TLS certificate (public key) string used with HTTPS server. takes precedence over httpsPublicKeyFilepathhttpsPrivateKey
- — TLS private key string used with HTTPS server. takes precedence over httpsPrivateKeyFilepathdebug
- — set to true to enable debug logging for troubleshootingforceUpgradeHttpToHttps
- — set to true to force upgrade all http: requests to https: requests globallyforceUpgradeWsToWss
- — set to true to force upgrade all ws: requests to wss: requests globallyusePermanentRedirect
- — set to true to use permanent redirect globally. The proxy server will return a 308 redirect response to the client instead of the default 307 temporary redirect responseredirectHost
- — default host to redirect to globally, e.g. when upgrading to HTTPS or WSS, or if the incoming host is no longer supported and all requests to it should be redirected somewhere else. if not set, the proxy server will redirect to the incoming x-forwarded-host or host header fieldredirectURLParts
- — controls which URL parts are preserved during redirects. Can be true (preserve all parts), false (preserve only host), or an object specifying which parts to preserve (see Route-level Configuration below)
- routes — array of incoming host to origin protocol, host, and port mappingsorigin
- — array of origin server host, port, and protocol (supports round-robin load balancing)originHost
- — origin host or IP addressoriginPort
- — origin port numberoriginProtocol
- — origin protocol. one of http:, https:, ws:, or wss:. don't forget the : at the endincomingHostAndPort
- — incoming host:port pattern to match for proxying to origin server. picked from HTTP host header field. Examples: example.com:80, api.example.com, *.example.com (wildcards supported)forceUpgradeHttpToHttps
- — set to true to force upgrade http: requests to https: requests for this routeforceUpgradeWsToWss
- — set to true to force upgrade ws: requests to wss: requests for this routeforceRedirect
- — set to true to force redirect all requests to this route to the redirectHost. useful for permanent host migrationsusePermanentRedirect
- — set to true to use permanent redirect for this route. The proxy server will return a 308 redirect response to the client instead of the default 307 temporary redirect responseredirectHost
- — host to redirect to for this route, e.g. when upgrading to HTTPS or WSS, or when forceRedirect is enabled. if not set, the proxy server will redirect to the incoming x-forwarded-host or host header fieldredirectURLParts
- — controls which URL parts are preserved during redirects for this route. Can be:true
- — preserve all URL parts (protocol, pathname, search, username, password)false
- — preserve only the host{ "protocol": true, "pathname": true, "search": false, "username": false, "password": false }
- An object with specific parts: overrideHost
- — if set, the proxy will override the host and x-forwarded-host header fields in requests sent to the origin server. useful for testing or when a specific host is required (e.g., for OAuth callbacks)
`json`
{
"exposeHttpProxy": true,
"httpPort": "80",
"exposeHttpsProxy": true,
"httpsPort": "443",
"httpsPublicKeyFilepath": "/path/to/cert.pem",
"httpsPrivateKeyFilepath": "/path/to/key.pem",
"routes": [
{
"origin": [
{
"originHost": "localhost",
"originPort": 3000,
"originProtocol": "http:"
}
],
"incomingHostAndPort": "example.com",
"forceUpgradeHttpToHttps": true
}
]
}
`json`
{
"exposeHttpsProxy": true,
"httpsPort": "443",
"httpsPublicKey": "-----BEGIN CERTIFICATE-----\n...",
"httpsPrivateKey": "-----BEGIN PRIVATE KEY-----\n...",
"routes": [
{
"origin": [
{
"originHost": "backend1.internal",
"originPort": 8080,
"originProtocol": "http:"
},
{
"originHost": "backend2.internal",
"originPort": 8080,
"originProtocol": "http:"
}
],
"incomingHostAndPort": "api.example.com"
}
]
}
`json`
{
"exposeHttpProxy": true,
"httpPort": "80",
"routes": [
{
"origin": [],
"incomingHostAndPort": "old-domain.com",
"forceRedirect": true,
"redirectHost": "new-domain.com",
"usePermanentRedirect": true,
"redirectURLParts": {
"pathname": true,
"search": true
}
}
]
}
`json`
{
"exposeHttpsProxy": true,
"httpsPort": "443",
"exposeWsProxyForHttps": true,
"httpsPublicKeyFilepath": "/path/to/cert.pem",
"httpsPrivateKeyFilepath": "/path/to/key.pem",
"routes": [
{
"origin": [
{
"originHost": "websocket-server.internal",
"originPort": 8080,
"originProtocol": "ws:"
}
],
"incomingHostAndPort": "ws.example.com",
"forceUpgradeWsToWss": true
}
]
}
- if installed globally, run fimiproxy ./path/to/config.jsonnpm exec fimiproxy ./path/to/config.json
- if installed locally, run npx -y fimiproxy ./path/to/config.json
- for one-time run, run
`typescript
import fimiproxy from "fimiproxy"
// start fimiproxy
await fimiproxy.startFimiproxyUsingConfig({
/* config / {
exposeHttpProxy: true,
exposeHttpsProxy: true,
httpPort: "80",
httpsPort: "443",
debug: false,
routes: [{
origin: [{
originHost: "localhost",
originPort: 3000,
originProtocol: "https:",
}],
incomingHostAndPort: "www.example.com",
forceUpgradeHttpToHttps: true,
overrideHost: "localhost:3000"
}],
httpsPublicKey: "-----BEGIN CERTIFICATE-----\n...",
httpsPrivateKey: "-----BEGIN PRIVATE KEY-----\n...",
},
/* shouldHandleGracefulShutdown / true,
/* exitProcessOnShutdown / true,
});
// end fimiproxy
await fimiproxy.endFimiproxy(/* exitProcessOnShutdown / true);
`
- startFimiproxyUsingConfig — start fimiproxy using configconfig: FimiproxyRuntimeConfig
- — see configuration aboveshouldHandleGracefulShutdown
- — defaults to true. if true, will listen for SIGINT and SIGTERM, and attempt to gracefully shut down the proxy serverexitProcessOnShutdown
- — defaults to true. if shouldHandleGracefulShutdown is true, will call process.exit() after graceful shutdown. your process may not shut down after SIGINT and SIGTERM if not true. currently untested behaviour (if process will shutdown or not) when set to false and shouldHandleGracefulShutdown is truestartFimiproxyUsingConfigFile
- — start fimiproxy using config read from filepathfilepath: string
- — file at filepath should be a json file, see configuration section abovestartFimiproxyUsingProcessArgs
- — start fimiproxy using filepath picked from process.argv[2] see https://nodejs.org/docs/latest/api/process.html#processargv. example, node your-script.js ./path/to/config.jsonendFimiproxy
- — gracefully end fimiproxyexitProcess
- — defaults to true. calls process.exit() if true
Use fimiproxy to proxy local development servers with SSL termination:
`bash`
fimiproxy dev-config.json
Route different subdomains to different microservices:
- api.example.com → backend API servicews.example.com
- → WebSocket servicecdn.example.com
- → static file server
Gradually migrate from old domain to new domain while preserving SEO:
- Use forceRedirect with usePermanentRedirect: trueredirectURLParts
- Preserve URL paths and query parameters with
Distribute traffic across multiple backend servers using round-robin selection.
Set debug: true in your configuration or use the FIMIPROXY_DEBUG=true environment variable to see detailed logs.
1. EADDRINUSE Error: Port already in use
- Check if another process is using the port: lsof -i :PORT
- Use different ports in your configuration
2. SSL Certificate Issues:
- Ensure certificate files exist and are readable
- Verify certificate format (PEM)
- Check certificate expiration
3. WebSocket Connection Issues:
- Ensure exposeWsProxyForHttp or exposeWsProxyForHttps is enabled
- Verify origin server supports WebSocket protocol
- Check for protocol mismatch (ws vs wss)
4. Host Header Issues:
- Use overrideHost if the origin server expects specific host headersincomingHostAndPort
- Check that matches the actual request host
- Cannot sustain multiple start calls, because current state is managed using a module-global variable. We'll eventually transition to a class-based encapsulation system, so stick around (if you're versed in Typescript, you can contribute to this effort). Multiple start calls will either lead to existing servers being garbage collected or memory leak, I haven't tested it. So, call endFimiproxy before making another start call. Start calls are calls to startFimiproxyUsingConfig, startFimiproxyUsingConfigFile, or startFimiproxyUsingProcessArgs`
- Round-robin load balancing is simple rotation, not weighted or health-checked