Node JS HTTP Proxy hanging up

Your code looked fine so I was curious and tried it.

Although you do log a few errors, you don't handle several cases:

  • The server returns a body with no response (cheerio will generate an empty HTML body when this happens)
  • The server returns a response that is not gzipped (your code will silently discard the response)

I made a few modifications to your code.

Change initial options

let proxy = httpProxy.createProxyServer({
    secure: false,
    changeOrigin: true
});
  • Don't verify TLS certificates secure: false
  • Send the correct Host header changeOrigin: true

Remove the if statement and replace it with a ternary

const isCompressed = proxyRes.headers['content-encoding'] === 'gzip';
const decompressed = isCompressed ? await ungzip(buffer) : buffer;

You can also remove the 2 await on cheerio, Cheerio is not async and doesn't return an awaitable.

Final code

Here's the final code, which works. You mentioned that "it looks like node-http-proxy is dying a lot [...] depending on how many times I ran the server." I experienced no such stability issues, so your problems may lie elsewhere if that is happening (bad ram?)

const cheerio = require('cheerio');
const http = require('http');
const httpProxy = require('http-proxy');
const { ungzip } = require('node-gzip');

const host = 'https://github.com';

let proxy = httpProxy.createProxyServer({
    secure: false,
    changeOrigin: true
});
let option = {
    target: host,
    selfHandleResponse: true
};

proxy.on('proxyRes', function (proxyRes, req, res) {

    console.log(`Proxy response with status code: ${proxyRes.statusCode} to url ${req.url}`);
    if (proxyRes.statusCode == 301) {
        throw new Error('You should probably do something here, I think there may be an httpProxy option to handle redirects');
    }
    let body = [];
    proxyRes.on('data', function (chunk) {
        body.push(chunk);
    });
    proxyRes.on('end', async function () {
        let buffer = Buffer.concat(body);
        try {
            let $ = null;
            const isCompressed = proxyRes.headers['content-encoding'] === 'gzip';
            const decompressed = isCompressed ? await ungzip(buffer) : buffer;
            const scriptTag = '<script src="my-customjs.js"></script>';
            $ = cheerio.load(decompressed.toString());
            $('body').append(scriptTag);
            res.end($.html());
        } catch (e) {
            console.log(e);
        }
    });
});

let server = http.createServer(function (req, res) {
    proxy.web(req, res, option, function (e) {
        console.log(e);
    });
});

console.log("listening on port 5051");
server.listen(5051);