bouncy HTTP Proxy and Router
bouncy is a low-level Node.js library that provides HTTP proxy and routing capabilities by wrapping `net.Server`. It allows programmatic redirection of raw HTTP traffic based on request headers (like `Host`), paths, or methods. Developers define routing logic within a callback function, gaining fine-grained control over request and response streams for tasks like load balancing or host-based multiplexing. Version `3.2.2` was published in October 2014, and the project shows no significant activity since then, indicating it is abandoned. It differs from higher-level HTTP frameworks by operating directly with Node.js's `net` and `tls` modules, offering a more primitive, stream-oriented approach to proxying.
Common errors
-
TypeError: bouncy is not a function
cause Attempting to use `bouncy` in a modern Node.js ESM context with `import bouncy from 'bouncy';` without proper configuration.fixEnsure your project is configured for CommonJS, or use `const bouncy = require('bouncy');` in a CommonJS module. If you must use ESM, consider a dynamic `import('bouncy')` after `require` is globally defined, or use a bundler that handles CJS-to-ESM conversion. -
Error: self-signed certificate in certificate chain (or similar SSL/TLS error)
cause Incorrect or incomplete SSL/TLS configuration (`opts.key`, `opts.cert`) for an HTTPS proxy, or issues with certificate authorities.fixVerify that `opts.key` and `opts.cert` point to valid SSL certificate and private key files. For self-signed certificates in development, you might need to use `NODE_TLS_REJECT_UNAUTHORIZED=0` (not for production) or configure your client to trust the self-signed certificate. -
RangeError: 'port' option should be a number
cause Providing a non-numeric value or an invalid port number to the `bounce()` function or `server.listen()`.fixEnsure that the port argument passed to `bounce()` or `server.listen()` is a valid integer between 1 and 65535. For example, `bounce(8001);` not `bounce('8001');` (though `bouncy`'s sugar syntax might handle string ports, it's best practice to use numbers).
Warnings
- breaking The `bouncy` package is abandoned and has not been updated since 2014. It is unlikely to receive security patches, bug fixes, or compatibility updates for newer Node.js versions or HTTP standards. Using it in production environments is highly discouraged due to potential security vulnerabilities and lack of maintenance.
- gotcha When configuring an HTTPS router using `bouncy`, `opts.key` and `opts.cert` are required. For environments with multiple SSL certificates requiring Server Name Indication (SNI), `opts.SNICallback` must be provided, following Node.js `tls.createServer` documentation. Misconfiguration can lead to failed HTTPS connections or certificate errors.
- gotcha The callback function passed to `bouncy` receives different arguments based on its arity. A function declared with two arguments (`function (req, bounce)`) will not receive the `res` (response) object, which is crucial for sending direct responses or modifying headers before bouncing. To access `res`, the function must be declared with three arguments (`function (req, res, bounce)`).
- gotcha `bouncy` operates at a relatively low level, directly piping streams. This means it doesn't automatically handle higher-level HTTP features or complex middleware chains common in modern web frameworks. Custom logic for things like authentication, rate limiting, or advanced request manipulation must be implemented manually within the `bouncy` callback.
Install
-
npm install bouncy -
yarn add bouncy -
pnpm add bouncy
Imports
- bouncy
import bouncy from 'bouncy';
const bouncy = require('bouncy'); - server.listen
bouncy.listen(8000);
server.listen(8000);
- bounce callback arity (req, res, bounce)
bouncy(function (req, bounce) { /* ... */ }); // If you need 'res'bouncy(function (req, res, bounce) { /* ... */ });
Quickstart
const bouncy = require('bouncy');
const http = require('http');
// Create a simple backend server 1
const backend1 = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`Hello from backend 8001 (Host: ${req.headers.host}, Path: ${req.url})`);
});
backend1.listen(8001, () => console.log('Backend 8001 listening.'));
// Create a simple backend server 2
const backend2 = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`Hello from backend 8002 (Host: ${req.headers.host}, Path: ${req.url})`);
});
backend2.listen(8002, () => console.log('Backend 8002 listening.'));
// Create the bouncy proxy server
const proxyServer = bouncy(function (req, res, bounce) {
console.log(`Incoming request for Host: ${req.headers.host}, URL: ${req.url}`);
if (req.headers.host === 'beep.example.com') {
console.log('Routing to 8001');
bounce(8001);
} else if (req.headers.host === 'boop.example.com') {
console.log('Routing to 8002');
bounce(8002, { path: '/custom-path' }); // Example of path modification
} else if (req.url === '/admin') {
// Example of direct response from proxy without bouncing
res.statusCode = 200;
res.end('Admin dashboard via proxy.');
} else {
console.log('No route found, sending 404.');
res.statusCode = 404;
res.end('No such host or route found.');
}
});
proxyServer.listen(8000, () => console.log('Proxy server listening on port 8000.'));
console.log('\nTo test, use curl or modify your /etc/hosts file:\n');
console.log(' curl -H "Host: beep.example.com" http://localhost:8000');
console.log(' curl -H "Host: boop.example.com" http://localhost:8000');
console.log(' curl http://localhost:8000/admin');
console.log(' curl http://localhost:8000/unknown-host');