A private origin tunnel lets a CDN serve a machine that has no public IP, no port forwarding, and no inbound firewall rule at all. The origin dials out; nothing dials in. This is how CDNShark's is built — the SNI trick that keeps edges stateless, why the connector needs no root, and the limitations you should know before designing around it.
The problem
Conventional CDN setups require a reachable origin. That means a public IP, an open port 443, and a firewall you hope is configured correctly — plus the permanent risk that someone finds the origin IP and bypasses the CDN entirely. The usual mitigations (allowlisting edge IPs, origin certificates) help but still leave an inbound listener on the internet.
A tunnel inverts it. The origin makes an outbound connection and keeps it open. There is nothing to scan, nothing to bypass, and no inbound rule to get wrong.
The data path
Four design decisions worth explaining
The tunnel ID travels in the TLS SNI
The edge connects to https://HOSTID.tgw-us-west-1.cdnshark.com — the gateway node for that tunnel's region — so the tunnel identifier is the first label of the SNI. The gateway demuxes on it with ssl_preread before any HTTP parsing. This is what keeps edges stateless: an edge needs no WireGuard keys, no peer table, and no per-customer configuration — it just proxies to a hostname. Adding, moving, or removing a tunnel touches the gateway only, and never requires pushing state to 11 edges.
Authorisation is the client certificate, never the tunnel ID
The tunnel ID is in the SNI, which is visible on the wire. It is an address, not a secret. The gateway's HTTPS listener runs ssl_verify_client on against a private Edge CA, so only a machine holding a certificate from that CA can open a connection at all. Guessing a tunnel ID gets you a 400 at the TLS layer.
The connector needs no root and creates no network device
Most WireGuard setups need CAP_NET_ADMIN and a TUN device. The connector instead runs wireguard-go against a gVisor userspace network stack, terminating TCP in userspace and opening a fresh local connection to the target. Consequences: it runs as an unprivileged user, changes nothing about the host's networking, and cannot be used as a pivot into the rest of the network — because there is no route, only a userspace socket to the configured target.
523 is not 502
An unknown tunnel ID returns 523; a tunnel whose connector is dead returns 502. Collapsing them would be convenient and wrong, because they need completely different responses: 523 means the routing state is inconsistent (the ID does not exist at this gateway), while 502 means the customer's connector is offline. Keeping them distinct is what makes the tunnel debuggable at 3am.
Enrolment: the private key never leaves the customer's machine
1. portal issues a single-use enrolment token (valid 15 minutes)
2. connector generates its WireGuard keypair LOCALLY
-- the private key is never transmitted, ever
3. POST /api/tunnel/enroll { token, public_key }
4. control plane allocates a /32 from the gateway's subnet
5. MQTT: tunnel_peer_add -> gateway adds the peer to wg0
6. gateway rewrites state.json; the Lua picks it up on mtime change
-- no nginx reload, no restart, no dropped connections
7. routes are defined in the PORTAL only
-- there is no local config file to drift or leak
The last point is a deliberate operational choice. A connector with a local config file is a connector that will eventually disagree with the control plane. Routes live in one place.
What you can point a tunnel at
- A web server on
127.0.0.1on a machine behind NAT with no port forwarding - A private host elsewhere on the LAN, by host and port
- An internal admin panel or staging environment you do not want on the public internet
- A home lab, or a service on a network you do not control the firewall for
Up to 10 routes per tunnel. Included tunnels: 2 on Free, 5 on Basic, 25 on Enterprise; extra tunnels are $1.99/month each.
Limitations, stated plainly
- Three gateway regions. Gateways run in US-West, Europe and Asia-Pacific. That is far fewer than the 11 edge PoPs, so the gateway — not the edge — is the coarse half of the path: an origin sitting close to an edge but far from all three regions (South America, Africa, Oceania) still goes edge → distant gateway → origin and back, which can cross an ocean twice on a cache MISS. More regions are added as demand warrants, but weigh the footprint that exists rather than the one that might.
- 10 routes per tunnel.
- Cache HITs never touch the tunnel — which is the point — but a low cache-hit ratio means the tunnel is in the hot path for most requests.
- No load balancing across multiple connectors for one route; a tunnel maps to a peer.
- The connector is another process to keep running. If it stops, the origin is unreachable and the edge returns 502 (which is exactly why 502 and 523 are kept distinct).
- Not a general-purpose VPN.
ip_forwardis 0 and each peer is pinned to a /32 — you cannot route arbitrary traffic through it, by design.
How it compares
The obvious comparison is Cloudflare Tunnel, which is a mature product with a global gateway footprint and more integration surface. CDNShark's version has three gateway regions and a smaller feature set. What it offers instead is that it comes with the CDN plan rather than as a separate product, the architecture is documented down to the SNI demux and the 523 semantics, and the security model is small enough to actually verify: outbound-only, mTLS-authorised, per-peer /32, no forwarding, no root, no local config, and a private key that never leaves your machine.