← News
/PLAYBOOK · 2026-09-09

Nginx Origin Protection in Practice: Allow Only CDN Origin-Pull IPs

CDN defenses fail once the origin IP leaks—attackers connect directly and bypass every rule. This guide covers Nginx origin protection: geo-module origin-pull IP whitelist, 444 silent close, placeholder cert to hide the domain, curl two-way verification, vendor expansion false-block triage, and crawler impact. Commands are copy-paste ready.

Use Case

After a site is onboarded to a CDN (Alibaba Cloud CDN, Tencent Cloud CDN, Baidu Cloud Acceleration, and others), origin protection hinges on one fact: once an attacker recovers the real origin IP from historical DNS, certificate transparency logs, or email headers, they bypass the CDN and launch CC attacks and vulnerability scans directly. Every CDN-layer rule fails. This design uses an Nginx IP whitelist so only CDN origin-pull node IP ranges can reach ports 80/443; direct-to-origin requests are dropped.

Prerequisites

Mechanism

When CDN nodes pull origin content, the TCP source address belongs to the vendor-published IP ranges. Use that in Nginx via the geo module to whitelist the connection source IP: hits are forwarded; misses return 444 (Nginx-specific: drop the connection with no response packet), so scanners get nothing. Versus allow/deny ACL, geo matching finishes before the access phase, overhead is negligible, and the map is reusable across multiple server blocks.

Procedure

Step 1: Collect CDN Origin-Pull IP Ranges

Log into the CDN console and download origin-pull IP ranges from “IP list”, “origin nodes”, or the help docs. Example format below (vendor console is source of truth):

`# Example: Alibaba Cloud CDN origin IP ranges (partial illustration; always use the latest list from the console)
163.171.0.0/16
147.138.0.0/17
118.107.0.0/16`

Step 2: Configure the geo Whitelist

Create a standalone file `/etc/nginx/conf.d/cdn_allow.conf` at the `http {}` layer:

`geo $cdn_allowed {
    default        0;
    # CDN origin IP ranges (use the vendor console as source of truth)
    163.171.0.0/16   1;
    147.138.0.0/17   1;
    118.107.0.0/16   1;
    # Localhost and internal-network health checks
    127.0.0.1        1;
    10.0.0.0/8       1;
    172.16.0.0/12    1;
}`

Step 3: Block Direct Connections in server Blocks

Add the check on 80 and 443 listeners in the business server blocks:

`server {
    listen 80;
    server_name example.com;

    # Drop non-CDN origin IPs immediately
    if ($cdn_allowed = 0) {
        return 444;
    }

    # Normal application config ...
    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

server {
    listen 443 ssl;
    server_name example.com;
    # SSL certificate config ...

    if ($cdn_allowed = 0) {
        return 444;
    }

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}`

Key point: return 444 silently drops the connection; attacker scanners only see connection reset and cannot fingerprint the server. The if must sit at the top of the server block to avoid clashing with rewrite rules inside location. If the site also uses HTTP/2, the rule still applies; geo evaluation runs after protocol negotiation and before request handling.

Step 4: Address Certificate Disclosure

Even with 443 intercepting the request, an attacker connecting to the origin IP can still obtain the certificate domain via the TLS handshake and confirm the target. Put a default placeholder certificate on the 443 listener:

`server {
    listen 443 ssl default_server;
    ssl_certificate     /etc/nginx/ssl/fake.crt;
    ssl_certificate_key /etc/nginx/ssl/fake.key;
    return 444;
}`

Generate a self-signed placeholder in one line with `openssl req -x509 -nodes -newkey rsa:2048 -keyout fake.key -out fake.crt -subj \\\"/CN=localhost\\\"`.

Verification

`# 1. Check configuration syntax
nginx -t

# 2. Reload configuration
nginx -s reload

# 3. Direct-connect to origin IP (should get no response or connection reset)
curl -sv --resolve example.com:443:ORIGIN_IP https://example.com/ -o /dev/null --max-time 5

# 4. Access via the CDN domain (should return 200)
curl -sI https://example.com/ | head -1`

Also check origin Nginx logs: `tail -f /var/log/nginx/access.log`. Legitimate traffic should all come from CDN IP ranges.

FAQ

FAQ 1: After the CDN vendor expands origin-pull nodes, some users get 502/504

Cause: new origin-pull IP ranges were not added to the whitelist in time. Fix: re-pull the IP list from the console on a regular cadence (monthly recommended) and update the geo config; also watch source IPs that hit 444 in `access.log`. If a non-whitelist IP has normal traffic characteristics, immediately verify whether it is a new vendor node.

FAQ 2: Search-engine spiders hitting origin directly get blocked—does that hurt indexing?

No. Baidu, Google, and other major spiders fetch the DNS result; after CDN onboarding they origin-pull via CDN nodes and sit on the whitelist. Note the extreme case where a spider cached the direct origin IP (e.g. a CDN switch): confirm via spider UA logs and temporarily allow the IP range if needed.

FAQ 3: BT Panel and other management ports get false-blocked

The geo whitelist only applies to server blocks that contain `if ($cdn_allowed = 0)`. BT Panel, SSH, and other management services use separate ports and separate server configs, so they are out of scope—no extra allow needed.

Summary

Origin protection is the most neglected layer in a CDN stack: however complete the CDN WAF and rate-limit rules, a leaked origin IP zeros them out. geo module + 444 silent drop, in a dozen lines of config, narrows the origin from public-reachable to CDN origin-pull only. Pair with a placeholder certificate to hide domain info and close the origin-pull path. Ops focus: regular CDN origin-pull IP range updates and 444 log monitoring so vendor expansion nodes are not false-blocked.