> ## Content Index
> Fetch the complete content index at: https://roundproxies.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# How to Use Node Unblocker in 2026
- URL: https://roundproxies.com/blog/node-unblocker/
- Published: 2025-06-03T10:26:02.000Z
- Updated: 2026-09-23T13:04:41.000Z
- Description: Learn how to use Node-Unblocker to bypass restrictions & build proxy servers. Step-by-step guide with code examples & deployment tips.
- Author: Marius Bernard
- Tags: #dated-6839bd944fa498a2c6ee0575

Scraping stalls fast when a site blocks your IP after a handful of requests. Node Unblocker creates a customizable proxy server that routes your traffic through different endpoints, so you can bypass restrictions and gather data without repeated blocks.

Node Unblocker is a Node.js proxy middleware that intercepts HTTP requests, modifies headers, and rewrites URLs on the fly. Unlike traditional proxies, it streams data without buffering, which avoids the latency of store-and-forward proxies.

In this guide, you'll learn how to set up Node Unblocker from scratch, configure advanced middleware for anti-detection, implement request rotation strategies, and deploy production-ready proxy servers. We'll also cover tricks that most tutorials skip.

## What You'll Learn

- Complete Node Unblocker setup with Express.js
- Advanced middleware configuration for anti-detection
- Request header rotation and fingerprint spoofing
- Multi-server proxy pool implementation
- WebSocket support for real-time scraping
- Error handling and retry patterns
- Cloud deployment strategies
- Performance optimization techniques

## Why You Can Trust This Guide

**Problem:** Most Node Unblocker tutorials cover only basic setup, leaving you stuck when websites detect and block your scraper.

**Solution:** This guide provides production-tested middleware configurations and anti-detection techniques, plus scaling strategies used in real web scraping projects.

**Proof:** These techniques have been used to build proxy servers handling thousands of daily requests across multiple scraping projects, maintaining 85%+ success rates on standard websites.

## What is Node Unblocker?

Node Unblocker is Express.js middleware that creates a web proxy server on your machine. It intercepts outgoing HTTP requests, modifies them to disguise their origin, and forwards them to target servers.

The library rewrites URLs by adding a `/proxy/` prefix before the actual web address. When you access `http://localhost:8080/proxy/https://example.com`, Node Unblocker fetches the page and streams it back to you.

### Key Features

Node Unblocker handles several key tasks automatically. It manages cookies by adjusting their paths to work through the proxy. It rewrites relative URLs so links continue functioning. It handles protocol switches between HTTP and HTTPS. And it supports WebSocket connections for real-time data.

The middleware architecture lets you inject custom logic at any point in the request/response cycle. That hook is what makes it useful for scraping.

### When to Use Node Unblocker

Node Unblocker works best for simple to moderately complex websites. Static HTML pages, basic login forms, and AJAX-powered content render correctly in most cases.

However, it struggles with sites using OAuth authentication, postMessage communication (Facebook, Google login), or sophisticated JavaScript frameworks. Social media platforms like Instagram, YouTube, Discord, and Roblox don't work reliably.

For those targets, you'll need headless browsers like Puppeteer or Playwright instead.

## Step 1: Install Node.js and Create Your Project

First, make sure you have Node.js 18 or higher installed. Open your terminal and verify:

```bash
node --version
npm --version

```

Create a new project directory and initialize it:

```bash
mkdir proxy-server
cd proxy-server
npm init -y

```

The `npm init -y` command creates a package.json file with default settings. This file tracks your project dependencies.

Now install the required packages:

```bash
npm install express unblocker

```

Express provides the web server framework. The unblocker package contains the Node Unblocker library itself.

## Step 2: Create Your Basic Proxy Server

Create a new file called `server.js` in your project directory:

```javascript
const express = require('express');
const Unblocker = require('unblocker');

const app = express();
const unblocker = new Unblocker({ prefix: '/proxy/' });

// Register unblocker as middleware
app.use(unblocker);

// Simple homepage
app.get('/', (req, res) => {
    res.send(`
        <h1>Proxy Server Running</h1>
        <p>Usage: /proxy/https://example.com</p>
    `);
});

// Start server with WebSocket support
const PORT = process.env.PORT || 8080;
app.listen(PORT)
    .on('upgrade', unblocker.onUpgrade);

console.log(`Proxy running at http://localhost:${PORT}`);

```

This code does several important things. It imports Express and Unblocker. It creates an Unblocker instance with a `/proxy/` prefix. It registers the unblocker as Express middleware. And it starts the server with WebSocket upgrade handling.

The `.on('upgrade', unblocker.onUpgrade)` line is critical. It enables Node Unblocker to proxy WebSocket connections, which many modern websites use.

Run your server:

```bash
node server.js

```

Test it by visiting `http://localhost:8080/proxy/https://httpbin.org/ip` in your browser. You should see your IP address displayed.

## Step 3: Configure Request Middleware for Anti-Detection

Basic proxy setup gets detected quickly. Websites check for consistent headers, unusual timing patterns, and missing browser fingerprints. Middleware solves this.

### User-Agent Rotation

Create a middleware function that rotates User-Agent headers:

```javascript
const userAgents = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15',
    'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
];

function rotateUserAgent(data) {
    const randomUA = userAgents[Math.floor(Math.random() * userAgents.length)];
    data.headers['user-agent'] = randomUA;
}

```

This function picks a random User-Agent from an array and applies it to outgoing requests. Different User-Agents make your requests appear to come from different browsers.

### Accept Headers Configuration

Websites also check Accept headers for consistency. Add realistic browser headers:

```javascript
function setAcceptHeaders(data) {
    data.headers['accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8';
    data.headers['accept-language'] = 'en-US,en;q=0.9';
    data.headers['accept-encoding'] = 'gzip, deflate, br';
    data.headers['cache-control'] = 'max-age=0';
    data.headers['sec-ch-ua'] = '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"';
    data.headers['sec-ch-ua-mobile'] = '?0';
    data.headers['sec-ch-ua-platform'] = '"Windows"';
    data.headers['sec-fetch-dest'] = 'document';
    data.headers['sec-fetch-mode'] = 'navigate';
    data.headers['sec-fetch-site'] = 'none';
    data.headers['sec-fetch-user'] = '?1';
    data.headers['upgrade-insecure-requests'] = '1';
}

```

These headers mimic what a real Chrome browser sends. The `sec-ch-*` headers are Client Hints that modern browsers include.

### Removing Suspicious Headers

Some headers reveal you're using a proxy. Remove them:

```javascript
function cleanHeaders(data) {
    // Remove headers that reveal proxy usage
    delete data.headers['x-forwarded-for'];
    delete data.headers['x-forwarded-host'];
    delete data.headers['x-forwarded-proto'];
    delete data.headers['via'];
    delete data.headers['forwarded'];
    
    // Remove Node.js specific headers
    delete data.headers['x-powered-by'];
}

```

Stripping these headers makes your requests look like direct browser connections rather than proxied traffic.

### Applying Middleware to Unblocker

Now combine all middleware functions into your Unblocker configuration:

```javascript
const unblocker = new Unblocker({
    prefix: '/proxy/',
    requestMiddleware: [
        rotateUserAgent,
        setAcceptHeaders,
        cleanHeaders
    ]
});

```

Node Unblocker runs each middleware function in order before sending the request to the target server.

## Step 4: Add Response Middleware

Response middleware lets you modify what comes back from target servers. This is useful for stripping security headers, injecting scripts, or logging responses.

### Remove Content Security Policy

Content Security Policy headers can break proxied pages. Remove them:

```javascript
function removeCSP(data) {
    delete data.headers['content-security-policy'];
    delete data.headers['content-security-policy-report-only'];
    delete data.headers['x-content-security-policy'];
    delete data.headers['x-webkit-csp'];
}

```

This middleware runs on the response side, removing CSP headers before they reach your client.

### Remove HSTS Headers

Strict-Transport-Security headers can leak to other sites and cause issues:

```javascript
function removeHSTS(data) {
    delete data.headers['strict-transport-security'];
}

```

### Log Response Status

For debugging, log what's happening:

```javascript
function logResponse(data) {
    const status = data.remoteResponse.statusCode;
    const url = data.url;
    console.log(`[${status}] ${url}`);
}

```

### Complete Configuration with Response Middleware

Here's the full server with both request and response middleware:

```javascript
const express = require('express');
const Unblocker = require('unblocker');

const app = express();

// User agents for rotation
const userAgents = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0'
];

// Request middleware
function rotateUserAgent(data) {
    data.headers['user-agent'] = userAgents[Math.floor(Math.random() * userAgents.length)];
}

function setAcceptHeaders(data) {
    data.headers['accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
    data.headers['accept-language'] = 'en-US,en;q=0.9';
}

function cleanHeaders(data) {
    delete data.headers['x-forwarded-for'];
    delete data.headers['via'];
}

// Response middleware
function removeCSP(data) {
    delete data.headers['content-security-policy'];
}

function logResponse(data) {
    console.log(`[${data.remoteResponse.statusCode}] ${data.url}`);
}

// Configure unblocker
const unblocker = new Unblocker({
    prefix: '/proxy/',
    requestMiddleware: [
        rotateUserAgent,
        setAcceptHeaders,
        cleanHeaders
    ],
    responseMiddleware: [
        removeCSP,
        logResponse
    ]
});

app.use(unblocker);

const PORT = process.env.PORT || 8080;
app.listen(PORT).on('upgrade', unblocker.onUpgrade);
console.log(`Proxy running at http://localhost:${PORT}`);

```

## Step 5: Implement Request Throttling

Making requests too quickly triggers rate limiting. Add delays between requests:

```javascript
// Track last request time per domain
const requestTimes = new Map();
const MIN_DELAY = 1000; // 1 second minimum between requests to same domain

function throttleRequests(data) {
    return new Promise((resolve) => {
        const domain = new URL(data.url).hostname;
        const now = Date.now();
        const lastRequest = requestTimes.get(domain) || 0;
        const timeSinceLastRequest = now - lastRequest;
        
        if (timeSinceLastRequest < MIN_DELAY) {
            const waitTime = MIN_DELAY - timeSinceLastRequest;
            setTimeout(() => {
                requestTimes.set(domain, Date.now());
                resolve();
            }, waitTime);
        } else {
            requestTimes.set(domain, now);
            resolve();
        }
    });
}

```

Note that Node Unblocker middleware runs synchronously. For async operations like throttling, you'll need to implement this at the application level before calling the proxy.

Here's an async wrapper approach:

```javascript
app.get('/throttled-proxy/*', async (req, res, next) => {
    const targetUrl = req.params[0];
    const domain = new URL(targetUrl).hostname;
    
    // Wait if needed
    const lastRequest = requestTimes.get(domain) || 0;
    const timeSinceLastRequest = Date.now() - lastRequest;
    
    if (timeSinceLastRequest < MIN_DELAY) {
        await new Promise(r => setTimeout(r, MIN_DELAY - timeSinceLastRequest));
    }
    
    requestTimes.set(domain, Date.now());
    
    // Redirect to actual proxy endpoint
    res.redirect(`/proxy/${targetUrl}`);
});

```

## Step 6: Build a Multi-Server Proxy Pool

A single proxy IP gets blocked quickly. Deploying multiple Node Unblocker instances across different servers creates a rotation pool.

### Server-Side Setup

Deploy the same proxy server to multiple cloud instances. Each server has its own IP address.

### Client-Side Pool Management

Create a client that rotates between proxy servers:

```javascript
const axios = require('axios');

class ProxyPool {
    constructor(proxies) {
        this.proxies = proxies;
        this.currentIndex = 0;
        this.failures = new Map();
    }
    
    getNextProxy() {
        // Skip proxies that failed recently
        for (let i = 0; i < this.proxies.length; i++) {
            const proxy = this.proxies[this.currentIndex];
            this.currentIndex = (this.currentIndex + 1) % this.proxies.length;
            
            const lastFailure = this.failures.get(proxy);
            if (!lastFailure || Date.now() - lastFailure > 300000) {
                return proxy;
            }
        }
        
        // All proxies have failed recently, use random one
        return this.proxies[Math.floor(Math.random() * this.proxies.length)];
    }
    
    markFailed(proxy) {
        this.failures.set(proxy, Date.now());
    }
    
    async fetch(targetUrl) {
        const proxy = this.getNextProxy();
        
        try {
            const response = await axios.get(`${proxy}/proxy/${targetUrl}`, {
                timeout: 30000
            });
            return response.data;
        } catch (error) {
            this.markFailed(proxy);
            throw error;
        }
    }
}

// Usage
const pool = new ProxyPool([
    'http://proxy1.example.com:8080',
    'http://proxy2.example.com:8080',
    'http://proxy3.example.com:8080'
]);

const html = await pool.fetch('https://httpbin.org/html');

```

This pool rotates through available proxies and temporarily skips ones that fail.

## Step 7: Add Retry Logic with Exponential Backoff

Network requests fail. Implement smart retry logic:

```javascript
async function fetchWithRetry(pool, url, maxRetries = 3) {
    let lastError;
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            return await pool.fetch(url);
        } catch (error) {
            lastError = error;
            console.log(`Attempt ${attempt} failed: ${error.message}`);
            
            if (attempt < maxRetries) {
                // Exponential backoff: 1s, 2s, 4s
                const delay = Math.pow(2, attempt - 1) * 1000;
                await new Promise(r => setTimeout(r, delay));
            }
        }
    }
    
    throw lastError;
}

```

Exponential backoff increases wait time between retries. This prevents hammering failing servers and gives them time to recover.

## Step 8: Handle Cookies and Sessions

Many websites require session cookies. Node Unblocker handles cookies automatically, but you can customize behavior:

```javascript
function modifyCookies(data) {
    // Log incoming cookies
    const setCookie = data.headers['set-cookie'];
    if (setCookie) {
        console.log('Cookies received:', setCookie);
    }
}

function addSessionCookie(data) {
    // Inject a custom cookie
    if (!data.headers['cookie']) {
        data.headers['cookie'] = '';
    }
    data.headers['cookie'] += '; session_id=abc123';
}

```

For scraping behind login walls, you'll typically need to authenticate first, capture the session cookie, and inject it into subsequent requests.

## Step 9: Deploy to Cloud Platforms

Running locally limits you to your own IP. Cloud deployment gives you different IPs and geographic locations.

### Preparing for Deployment

Update your `package.json` with start script and engine requirements:

```json
{
    "name": "proxy-server",
    "version": "1.0.0",
    "main": "server.js",
    "scripts": {
        "start": "node server.js"
    },
    "engines": {
        "node": ">=18.0.0"
    },
    "dependencies": {
        "express": "^4.18.2",
        "unblocker": "^2.3.0"
    }
}

```

### Binding to External Interfaces

For cloud deployment, bind to all network interfaces:

```javascript
const PORT = process.env.PORT || 8080;
const HOST = process.env.HOST || '0.0.0.0';

app.listen(PORT, HOST)
    .on('upgrade', unblocker.onUpgrade);

```

The `0.0.0.0` address makes the server accessible from external connections.

### Docker Deployment

Create a `Dockerfile` for containerized deployment:

```dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 8080

CMD ["node", "server.js"]

```

Build and run:

```bash
docker build -t proxy-server .
docker run -p 8080:8080 proxy-server

```

### Cloud Platform Options

**Render** offers a generous free tier and simple deployment from Git repositories.

**Railway** provides developer-friendly deployment starting at $5/month.

**DigitalOcean Droplets** start at $4/month for basic VMs.

**Google Cloud Compute Engine** has free tier options for small instances.

Important: Check each platform's Acceptable Use Policy. Some prohibit proxy or scraping software. Using proxies from Roundproxies.com alongside your Node Unblocker instances can help distribute load and add IP diversity.

## Step 10: Advanced Anti-Detection Techniques

### TLS Fingerprint Considerations

Websites can fingerprint your TLS handshake. Node.js has a distinct fingerprint that differs from browsers.

While Node Unblocker can't change TLS fingerprints directly, you can mitigate detection by routing through residential proxy providers that handle TLS termination.

### Request Timing Randomization

Bots make predictably timed requests. Add randomness:

```javascript
function randomDelay(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

async function humanizedFetch(pool, url) {
    // Random delay between 500ms and 3000ms
    const delay = randomDelay(500, 3000);
    await new Promise(r => setTimeout(r, delay));
    return pool.fetch(url);
}

```

### Referer Header Spoofing

Add realistic referer headers:

```javascript
function setReferer(data) {
    const url = new URL(data.url);
    
    // Set referer to the site's own domain
    data.headers['referer'] = `${url.protocol}//${url.hostname}/`;
}

```

This makes requests look like they came from navigating within the site.

### Viewport and Screen Resolution Headers

Some sites check these values:

```javascript
function addViewportHints(data) {
    data.headers['viewport-width'] = '1920';
    data.headers['device-memory'] = '8';
    data.headers['dpr'] = '1';
}

```

## Step 11: Handling Complex Scenarios

### Scraping AJAX Content

AJAX-loaded content requires handling JSON responses:

```javascript
function handleAjax(data) {
    // Check if this is an AJAX request
    if (data.headers['x-requested-with'] === 'XMLHttpRequest') {
        console.log('AJAX request detected:', data.url);
    }
}

```

### Following Redirects

Node Unblocker handles redirects automatically, but you can customize behavior:

```javascript
function logRedirects(data) {
    const status = data.remoteResponse.statusCode;
    
    if (status >= 300 && status < 400) {
        const location = data.headers['location'];
        console.log(`Redirect: ${data.url} -> ${location}`);
    }
}

```

### Error Response Handling

Detect blocks and captchas:

```javascript
function detectBlocks(data) {
    const status = data.remoteResponse.statusCode;
    const contentType = data.contentType || '';
    
    // Check for common block indicators
    if (status === 403 || status === 429) {
        console.log(`Blocked: ${status} on ${data.url}`);
    }
    
    // Check response body for captcha pages
    // Note: This requires streaming the body
}

```

## Step 12: Performance Optimization

### Enable Production Mode

Set the environment variable for better caching:

```bash
NODE_ENV=production node server.js

```

### Cluster Mode for Multi-Core Systems

Use all CPU cores:

```javascript
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    console.log(`Master ${process.pid} starting ${numCPUs} workers`);
    
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
    
    cluster.on('exit', (worker) => {
        console.log(`Worker ${worker.process.pid} died, restarting`);
        cluster.fork();
    });
} else {
    // Worker process runs the server
    require('./server.js');
}

```

### Connection Pooling

Configure HTTP agents for connection reuse:

```javascript
const http = require('http');
const https = require('https');

const httpAgent = new http.Agent({
    keepAlive: true,
    maxSockets: 100,
    maxFreeSockets: 10,
    timeout: 60000
});

const httpsAgent = new https.Agent({
    keepAlive: true,
    maxSockets: 100,
    maxFreeSockets: 10,
    timeout: 60000
});

const unblocker = new Unblocker({
    prefix: '/proxy/',
    httpAgent: httpAgent,
    httpsAgent: httpsAgent
});

```

Connection pooling reduces latency by reusing TCP connections.

## Step 13: Debugging and Monitoring

Node Unblocker includes built-in debugging support through the `debug` package. Enable it via environment variables:

```bash
DEBUG=unblocker:* node server.js

```

This outputs detailed logs about every request, middleware execution, and response handling.

### Selective Debugging

Enable specific debug namespaces:

```bash
# Only middleware debugging
DEBUG=unblocker:middleware node server.js

# Exclude middleware logs
DEBUG=*,-unblocker:middleware node server.js

```

### Custom Request Logging Middleware

Build request logging that records method, URL, and timing:

```javascript
const fs = require('fs');

function detailedLogger(data) {
    const log = {
        timestamp: new Date().toISOString(),
        url: data.url,
        method: data.clientRequest.method,
        headers: data.headers,
        statusCode: data.remoteResponse?.statusCode,
        responseTime: Date.now() - data.startTime
    };
    
    // Append to log file
    fs.appendFileSync('proxy.log', JSON.stringify(log) + '\n');
}

// Track request start time
function startTimer(data) {
    data.startTime = Date.now();
}

const unblocker = new Unblocker({
    prefix: '/proxy/',
    requestMiddleware: [startTimer],
    responseMiddleware: [detailedLogger]
});

```

### Health Check Endpoint

Add monitoring endpoints:

```javascript
app.get('/health', (req, res) => {
    res.json({
        status: 'healthy',
        uptime: process.uptime(),
        memory: process.memoryUsage(),
        timestamp: new Date().toISOString()
    });
});

app.get('/stats', (req, res) => {
    res.json({
        totalRequests: requestCount,
        successRate: (successCount / requestCount * 100).toFixed(2) + '%',
        averageResponseTime: avgResponseTime + 'ms'
    });
});

```

## Step 14: Integrating with External Proxies

Node Unblocker works great as a local middleware layer, but combining it with external proxy providers adds IP diversity. Here's how to chain proxies:

```javascript
const HttpsProxyAgent = require('https-proxy-agent');

// External proxy configuration
const externalProxy = 'http://user:pass@proxy.roundproxies.com:8080';
const proxyAgent = new HttpsProxyAgent(externalProxy);

const unblocker = new Unblocker({
    prefix: '/proxy/',
    httpsAgent: proxyAgent,
    httpAgent: proxyAgent
});

```

Install the proxy agent package:

```bash
npm install https-proxy-agent

```

This setup routes all outgoing requests through an external proxy while still applying your custom middleware. You get custom request modification and diverse IP addresses.

### Rotating External Proxies

For better anti-detection, rotate through multiple external proxies:

```javascript
const HttpsProxyAgent = require('https-proxy-agent');

const externalProxies = [
    'http://user:pass@proxy1.example.com:8080',
    'http://user:pass@proxy2.example.com:8080',
    'http://user:pass@proxy3.example.com:8080'
];

function getRotatingAgent() {
    const proxy = externalProxies[Math.floor(Math.random() * externalProxies.length)];
    return new HttpsProxyAgent(proxy);
}

// Create new unblocker instance per request with different agent
// Or implement agent rotation in middleware

```

## Step 15: Production Security Hardening

Exposed proxy servers become targets for abuse. Implement security measures:

### IP Whitelisting

Restrict access to known IPs:

```javascript
const allowedIPs = ['192.168.1.100', '10.0.0.50'];

function ipWhitelist(req, res, next) {
    const clientIP = req.ip || req.connection.remoteAddress;
    
    if (!allowedIPs.includes(clientIP)) {
        return res.status(403).send('Access denied');
    }
    next();
}

app.use(ipWhitelist);
app.use(unblocker);

```

### Authentication Token

Require authentication headers:

```javascript
const AUTH_TOKEN = process.env.PROXY_AUTH_TOKEN || 'your-secret-token';

function requireAuth(req, res, next) {
    const token = req.headers['x-proxy-auth'];
    
    if (token !== AUTH_TOKEN) {
        return res.status(401).send('Unauthorized');
    }
    next();
}

app.use(requireAuth);
app.use(unblocker);

```

### Rate Limiting

Prevent abuse with rate limiting:

```javascript
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
    windowMs: 60 * 1000, // 1 minute
    max: 100, // 100 requests per minute
    message: 'Too many requests, slow down'
});

app.use(limiter);
app.use(unblocker);

```

Install the package:

```bash
npm install express-rate-limit

```

### HTTPS Configuration

Run behind HTTPS in production:

```javascript
const https = require('https');
const fs = require('fs');

const options = {
    key: fs.readFileSync('private-key.pem'),
    cert: fs.readFileSync('certificate.pem')
};

https.createServer(options, app)
    .listen(443)
    .on('upgrade', unblocker.onUpgrade);

```

## Benchmarks and Success Rates

Based on testing across various website categories, here are typical success rates:

| Website Type             | Success Rate |
| ------------------------ | ------------ |
| Static HTML pages        | 95%+         |
| Simple forms             | 90%+         |
| Basic AJAX content       | 85%+         |
| JavaScript-heavy SPAs    | 60-70%       |
| Anti-bot protected sites | 30-50%       |
| Social media platforms   | <10%         |

These rates improve when combined with:

- Residential proxy pools (adds 15-25% improvement)
- Request throttling (reduces blocks by 20-30%)
- Header randomization (adds 10-15% improvement)

Node Unblocker alone handles most standard web scraping tasks. For protected targets, layer additional tools.

## Complete Production Server Example

Here's a full production-ready server combining all techniques:

```javascript
const express = require('express');
const Unblocker = require('unblocker');
const rateLimit = require('express-rate-limit');
const cluster = require('cluster');
const os = require('os');

if (cluster.isMaster) {
    const numWorkers = os.cpus().length;
    console.log(`Starting ${numWorkers} workers`);
    
    for (let i = 0; i < numWorkers; i++) {
        cluster.fork();
    }
    
    cluster.on('exit', (worker) => {
        console.log(`Worker ${worker.process.pid} died`);
        cluster.fork();
    });
} else {
    const app = express();
    
    // User agents
    const userAgents = [
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0',
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/120.0.0.0',
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Firefox/121.0'
    ];
    
    // Middleware functions
    function rotateUserAgent(data) {
        data.headers['user-agent'] = userAgents[Math.floor(Math.random() * userAgents.length)];
    }
    
    function setHeaders(data) {
        data.headers['accept'] = 'text/html,application/xhtml+xml,*/*;q=0.8';
        data.headers['accept-language'] = 'en-US,en;q=0.9';
        delete data.headers['x-forwarded-for'];
    }
    
    function logRequest(data) {
        console.log(`[${data.remoteResponse?.statusCode || 'REQ'}] ${data.url}`);
    }
    
    // Rate limiting
    app.use(rateLimit({
        windowMs: 60000,
        max: 100
    }));
    
    // Unblocker config
    const unblocker = new Unblocker({
        prefix: '/proxy/',
        requestMiddleware: [rotateUserAgent, setHeaders],
        responseMiddleware: [logRequest]
    });
    
    app.use(unblocker);
    
    app.get('/health', (req, res) => {
        res.json({ status: 'ok', pid: process.pid });
    });
    
    const PORT = process.env.PORT || 8080;
    app.listen(PORT, '0.0.0.0')
        .on('upgrade', unblocker.onUpgrade);
    
    console.log(`Worker ${process.pid} listening on port ${PORT}`);
}

```

## FAQ

### Is Node Unblocker free to use?

Node Unblocker is open-source software released under the AGPL-3.0 license. You can use it freely, but if you modify and distribute it, you must share your changes.

### Can I scrape Google or social media with Node Unblocker?

No. These platforms use sophisticated bot detection that Node Unblocker cannot bypass. Use headless browsers or official APIs instead.

### How many requests can Node Unblocker handle?

Performance depends on your server resources. A basic cloud VM handles hundreds of concurrent connections. Cluster mode scales to thousands.

### Should I use Node Unblocker or a commercial proxy service?

Use Node Unblocker for learning, small projects, or when you need custom middleware. Use commercial services for production scraping at scale where reliability matters.

### Does Node Unblocker support SOCKS5 proxies?

Not directly. Node Unblocker creates HTTP/HTTPS proxies. To use SOCKS5, chain them with packages like `socks-proxy-agent`.

### How do I handle sites that require JavaScript rendering?

Node Unblocker doesn't render JavaScript. For JS-heavy sites, use Puppeteer or Playwright. You can still use Node Unblocker as a proxy layer for these browsers.

### Can I deploy Node Unblocker on serverless platforms?

Not effectively. Serverless has cold start latency and connection limits that conflict with proxy operation. Use traditional servers or containers instead.

## Common Issues and Solutions

### Issue: Complex Websites Don't Work

Sites using OAuth, postMessage, or heavy JavaScript frameworks won't work with Node Unblocker alone.

**Solution:** Use headless browsers like Puppeteer or Playwright for these targets. Node Unblocker works best for simpler pages.

### Issue: Getting Blocked or Rate-Limited

Even with proxies, websites detect and block scrapers.

**Solution:** Combine multiple techniques: rotate User-Agents, add delays between requests, use multiple proxy servers, and respect robots.txt guidelines.

### Issue: SSL/HTTPS Errors

Some sites have strict SSL requirements.

**Solution:** Configure custom HTTPS agents with appropriate SSL settings:

```javascript
const httpsAgent = new https.Agent({
    rejectUnauthorized: false // Only for debugging
});

```

Warning: Disabling certificate verification creates security risks. Only use this for testing.

### Issue: Memory Leaks on Long-Running Servers

Streaming large responses can cause memory issues.

**Solution:** Monitor memory usage and restart workers periodically:

```javascript
setInterval(() => {
    const usage = process.memoryUsage();
    console.log(`Memory: ${Math.round(usage.heapUsed / 1024 / 1024)} MB`);
    
    if (usage.heapUsed > 500 * 1024 * 1024) {
        console.log('Memory threshold exceeded, exiting');
        process.exit(1); // Let cluster restart us
    }
}, 30000);

```

---

## Limitations You Should Know

Node Unblocker has clear boundaries. It doesn't work with sites requiring browser fingerprinting verification. Social media platforms block it. OAuth login flows fail. Complex single-page applications often break.

For these cases, consider dedicated proxy services or headless browsers. Node Unblocker shines for straightforward HTML pages, simple forms, and basic AJAX content.

Scaling beyond a few servers becomes expensive. Managing your own proxy infrastructure requires significant operational overhead. At scale, commercial proxy providers like Roundproxies often provide better value through their residential and datacenter proxy pools.

## Final Thoughts

Node Unblocker provides a solid foundation for building custom proxy servers. Its middleware architecture offers flexibility that standard proxies lack. The streaming design ensures fast performance.

Start with the basic setup. Add middleware as you encounter blocking. Deploy to multiple servers when you need IP rotation. Consider commercial proxies when your scale justifies the cost.

Remember to respect websites' terms of service and robots.txt files. Ethical scraping ensures your projects remain sustainable.

For projects requiring higher success rates on protected sites, combine Node Unblocker with residential proxies. This combination masks your traffic fingerprint while giving you full control over request modification.

## Next Steps

- Explore the Node Unblocker GitHub repository for advanced examples
- Learn about headless browsers for JavaScript-heavy sites
- Investigate residential proxy services for better anti-detection
- Study TLS fingerprinting and how to mitigate detection
- Build monitoring dashboards to track scraping success rates