VeilBrowserDocs

Edge security & TLS

How the edge blocks direct-IP scans, hides your domain from scanners, locks the origin to Cloudflare, and which TLS mode to choose.

Once your cluster has a public hostname, the OpenResty edge stops behaving like an open IP and becomes a locked-down front door. It answers only the hostnames you configured, hides your real domain from internet scanners, and can refuse any connection that did not arrive through Cloudflare. This page explains each protection, the available TLS modes, and how to add a host firewall for defense in depth.

Eval and IP-only installs stay open

These protections activate only after a hostname is configured. An IP-only evaluation install (no hostname, no TLS) intentionally stays reachable over http://<ip> so you can try the cluster before wiring up DNS. Add a hostname before you rely on any of the hardening below.

Host and direct-IP blocking

With a hostname set, the edge only serves requests whose Host header (or TLS SNI) matches a configured hostname. Anything else, including a raw request to the server's IP address or an unknown Host, is dropped with HTTP 444. That is nginx's "close the connection without a response" status, so scanners and bots get nothing back to fingerprint.

RequestResult
https://your-domain/Served normally
https://<origin-ip>/ (direct IP)Connection dropped, 444
Unknown or spoofed Host headerConnection dropped, 444
ACME challenge on port 80Allowed, so certificate issuance still works

This closes the common mistake where hitting the origin IP falls through to the first server block and quietly serves your app. A strict catch-all default_server now owns port 80 and port 443, so unmatched traffic never reaches the application.

Anti-scanning: the decoy certificate

Services like Shodan and Censys crawl the whole IPv4 space, connect to port 443 on every IP, and record the certificate. A real certificate leaks your domain in its Subject Alternative Name (SAN), which lets anyone map an IP straight back to your site.

To prevent that, the catch-all default_server presents a decoy self-signed certificate with a bogus common name and no real SAN. A scanner hitting your IP reads only the decoy, so your true domain never appears in scan results. The real certificate is served exclusively to connections whose SNI matches a configured hostname.

The edge also sets server_tokens off, so responses do not advertise the server version. Together the decoy cert and hidden version give IP scanners nothing useful.

Why self-signed is fine here

The decoy is never validated by a real client, because real clients arrive with the correct SNI and get the real certificate. Its only job is to answer scanners with a cert that reveals nothing.

Cloudflare origin lock

When Cloudflare fronts your cluster, all legitimate traffic arrives from Cloudflare's IP ranges. Anyone who discovers your origin IP could otherwise bypass Cloudflare (and its WAF, rate limits, and TLS) by connecting to the origin directly.

The origin lock closes that gap. The edge reads the real connecting IP and refuses any connection that is not from a current Cloudflare range or from loopback, returning 444. Cloudflare's published IPv4 and IPv6 ranges are fetched at render time and cached, with a bundled fallback list in the image so a render never depends on network access.

The lock is on by default for Cloudflare mode and applies to both Flexible (port 80) and Full (port 443). Loopback is always allowed so on-box health checks keep working.

TLS modes

Traffic to the end user is always HTTPS. You pick how TLS is terminated and how the edge presents itself to the origin. Choose the mode that matches how requests reach your host.

Use this when Cloudflare proxies your domain (the orange cloud). Cloudflare terminates TLS with the browser, then connects to your origin. Pick a sub-mode that matches your Cloudflare SSL/TLS setting.

  • Flexible: the origin serves plain HTTP on port 80 and Cloudflare handles TLS at the edge. No origin certificate is needed. Simplest to set up, but the Cloudflare-to-origin hop is unencrypted, so rely on the origin lock plus a host firewall.
  • Full: the origin serves HTTPS on port 443 and Cloudflare connects over TLS. Choose the origin certificate source:
    • Self-signed (default): a generic self-signed origin certificate the edge generates automatically. Valid for Cloudflare Full because Full does not validate the origin certificate.
    • Cloudflare Origin CA: for Full (strict). The edge issues a long-lived origin certificate through the Cloudflare API using a one-time API token. The token is used once and never stored.

Optionally enable mTLS / Authenticated Origin Pulls (Cloudflare with Full only). The edge then requires a client certificate from Cloudflare's origin-pull CA, so only Cloudflare can complete the TLS handshake. This uses the bundled global Cloudflare CA by default, or a zone-level CA you upload. See Authenticated Origin Pulls.

Behind Cloudflare, use Full (not Let's Encrypt)

Standalone Let's Encrypt uses an HTTP-01 challenge on port 80, which Cloudflare's proxy intercepts, so it cannot complete when DNS points at Cloudflare. Let's Encrypt behind Cloudflare (DNS-01) is not supported. Behind Cloudflare, use Full with a self-signed or Origin CA certificate instead.

Paste a PEM certificate and private key from your own CA or provider. The origin serves HTTPS on port 443 and redirects port 80 to 443. The files are stored on the cm-state volume and served directly. Use this when you already have a certificate you want to run, with or without an upstream proxy.

The edge issues and renews a certificate on-box with lua-resty-acme, using the HTTP-01 challenge. The origin serves HTTPS on port 443 and answers the challenge on port 80. This works only when DNS points straight at the origin, so nothing intercepts the port 80 challenge.

Prerequisites:

  • An A record for your hostname resolves to this host.
  • Ports 80 and 443 are open. Port 80 answers the challenge, port 443 serves the cert.

Do not use this mode behind a proxy that intercepts port 80, such as Cloudflare's orange cloud. In that case use Cloudflare + Full instead.

Reference

For how Cloudflare's Flexible, Full, and Full (strict) settings behave end to end, see the Cloudflare SSL/TLS encryption modes documentation. Match the origin sub-mode you pick here to your Cloudflare dashboard setting.

Download the active origin certificate

You can view and download the certificate the origin is currently serving from Settings in the console. The download is PEM only and never includes the private key. It shows the certificate along with its fingerprint and expiry, which is handy for uploading the origin certificate into Cloudflare (Full strict) or verifying what the edge presents.

The download is hidden for Cloudflare + Flexible, because in that mode the origin has no certificate (TLS lives entirely at the Cloudflare edge).

Defense in depth: host firewall

The origin lock lives inside the edge. Add a host firewall so unwanted traffic never even reaches OpenResty. When you front the cluster with Cloudflare, restrict ports 80 and 443 to Cloudflare's ranges at the operating-system level.

Allow only Cloudflare ranges to reach 80 and 443, then deny the rest. Repeat the allow lines for every range in Cloudflare's IP list:

terminal
# For each Cloudflare IPv4 and IPv6 range:
sudo ufw allow from 173.245.48.0/20 to any port 80 proto tcp
sudo ufw allow from 173.245.48.0/20 to any port 443 proto tcp
# ...repeat for every range...

# Then deny direct access from everywhere else:
sudo ufw deny 80/tcp
sudo ufw deny 443/tcp
sudo ufw enable

Build a named set of Cloudflare ranges and accept only those on 80 and 443:

/etc/nftables.conf
table inet filter {
  set cloudflare_v4 {
    type ipv4_addr
    flags interval
    elements = { 173.245.48.0/20, 103.21.244.0/22 } # add every Cloudflare range
  }

  chain input {
    type filter hook input priority 0; policy drop;
    ct state established,related accept
    iif "lo" accept
    tcp dport { 80, 443 } ip saddr @cloudflare_v4 accept
    # add an ipv6 set + rule for Cloudflare's IPv6 ranges
  }
}

Keep the firewall list current

Cloudflare's ranges change occasionally. Refresh your firewall rules from the Cloudflare IP list periodically, or automate it, so a new range is never blocked by mistake. The edge origin lock refreshes its own copy at render time.

Next steps

Was this page helpful?

On this page