CacheGenie Tunnels

Updated 2 Oct 2026

A tunnel puts a server that cannot be reached from the internet behind the CDN. You run a small program, the connector, on a machine that can reach the server; it connects out to us, so nothing on your network has to be opened, and your zone fetches from the server through it.

How it works#

  • A tunnel has one connector and one or more endpoints. An endpoint is a service the connector can reach, such as https://192.168.1.5:443 or http://app:8080, and a zone uses one endpoint as its origin.
  • The connector measures its round trip to each of our locations, connects to the nearest, and moves by itself when that location is taken out of service. Every other location reaches your service through that one, so a zone behind a tunnel has no Home PoP of its own.
  • A zone behind a tunnel does everything any zone does: caching, a whole website with its logins and forms, WebSockets and server-sent events, uploads of any size, signed links, blocking, maintenance mode and statistics.
  • The connection between the connector and us is encrypted (WireGuard), and it carries only requests for your endpoints. Bandwidth is counted as for any zone, by what visitors receive.

Create a tunnel#

On the Tunnels page of the NOC, press New Tunnel and give it a name of 1 to 64 characters, which only you see. The tunnel's page opens with its token, a value starting cgt_. Copy it now: it is shown only this once.

Run the connector#

The connector is one program, cachegenie-tunnel, built for Linux on amd64, arm64 and 32-bit ARM, and a Docker image for amd64 and arm64; there is no macOS or Windows build. It needs no root, no kernel module and no open port, and its one setting is the token. Run it on a machine that can reach the services you will add as endpoints.

Public downloads are coming soon. Until the Docker image and the Linux builds are published, email the team and we will send you the connector. Once they are, this page and your tunnel's page give every command with the names filled in; below, {IMAGE} stands for the image's name.

Docker, on any machine with Docker:

docker run -d --name cachegenie-tunnel --restart unless-stopped \
  -e CG_TUNNEL_TOKEN=cgt_... \
  {IMAGE}:latest

On a container platform such as Bunny Magic Containers, run the same image as one replica with the token in the environment variable CG_TUNNEL_TOKEN; it needs no port, volume or privilege. Inside a container, localhost is the container itself, so name your service by an address or a hostname the container can reach.

A Linux server, any distribution: put the program in place and start it as a service.

sudo install -m 755 cachegenie-tunnel /usr/local/bin/cachegenie-tunnel
sudo cachegenie-tunnel service install cgt_...

service install needs root and systemd. It saves the token to /etc/cachegenie-tunnel/token, readable by root alone, writes the unit cachegenie-tunnel.service, and starts the connector now and at every boot, as an unprivileged user of its own. It does not replace a different token or unit unless you add --force. sudo cachegenie-tunnel service uninstall stops the service and removes what it wrote. The program has to sit outside home folders and temporary folders, such as in /usr/local/bin, so the service can run it.

The program also comes as .deb and .rpm packages, with a SHA256SUMS file to check each download. After installing a package, run sudo cachegenie-tunnel service install cgt_.... On a system without systemd, run cachegenie-tunnel run --token-file /path/to/token under the supervisor you use.

Kubernetes: a Secret holding the token and a Deployment of one replica. The Recreate strategy stops the old connector before the new one starts, so a rollout never runs two.

kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Secret
metadata:
  name: cachegenie-tunnel
type: Opaque
stringData:
  CG_TUNNEL_TOKEN: cgt_...
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cachegenie-tunnel
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels: {app: cachegenie-tunnel}
  template:
    metadata:
      labels: {app: cachegenie-tunnel}
    spec:
      containers:
        - name: connector
          image: {IMAGE}:latest
          envFrom:
            - secretRef: {name: cachegenie-tunnel}
          securityContext:
            runAsNonRoot: true
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities: {drop: ["ALL"]}
EOF

The token#

The connector reads the token from the first of these that is set: the --token option, the environment variable CG_TUNNEL_TOKEN, or a file named with --token-file (the service reads the one service install saved). Whoever holds the token can connect the tunnel from anywhere, so keep it as you would a password; the connector never writes it to its log.

A token is shown only when it is made. If it is lost, or may have been seen by someone else, press New token on the tunnel's page: the old token stops working at once, the connector using it is cut off, and the tunnel's zones answer visitors with an error page until a connector runs with the new one.

What the connector needs#

  • Outbound HTTPS to api.cachegenie.com, which it reports to every 30 seconds.
  • Outbound TCP to port 443 of our servers, to find the nearest: a connection that opens and closes, with nothing sent.
  • Outbound UDP to port 42819 of the server it connects to.
  • Whatever it takes to reach your services.

Nothing inbound: no port is opened or forwarded to the connector.

One connector per tunnel#

A second connector started with the same token waits, and its log says another connector is running. It takes over once the first has stopped: within 30 seconds when the first was stopped cleanly, otherwise once the first has been silent for 90 seconds. To connect services in two places, make a tunnel for each.

Update the connector#

The connector never updates itself. With Docker, pull the image and start the container again: docker pull {IMAGE}:latest, docker rm -f cachegenie-tunnel, then the run command above. On a Linux server, put the new program in place with the first command above and then sudo systemctl restart cachegenie-tunnel; with a package, upgrade the package and restart the service the same way. The tunnel is down for the few seconds the connector takes to start.

Endpoints#

Under Endpoints on the tunnel's page, add each service a zone will fetch from:

  • Name: what you call it, 1 to 64 characters.
  • Scheme: https or http, how the connector talks to the service.
  • Host: the address or hostname of the service as seen from where the connector runs, such as 192.168.1.5, app.internal or web. Private addresses are welcome: the connector makes the connection, never our servers, and it resolves a hostname itself.
  • Port: 1 to 65535. Left empty, 443 for https and 80 for http.

A change reaches the connector within 30 seconds, and every zone using the endpoint follows it. An endpoint that is a zone's origin cannot be deleted: choose another origin for the zone first.

Use an endpoint as a zone's origin#

In the zone page's Origin section, or when creating a zone, set Origin Type to CacheGenie Tunnel, then choose the Tunnel, the Endpoint and the Delivery:

  • Full website, the default: the whole site behind the CDN, pages, forms, logins and APIs included, exactly as a full site origin.
  • Static files: files served and cached as from a standard origin, as Zone settings describes.

A few settings are decided by the tunnel:

  • Home PoP is not used: every location already fetches through the location the connector is connected to.
  • Follow Redirects and Add Canonical Headers are switched off, as on a full site.
  • There is no Origin Certificate box: the connection to your connector is already authenticated and encrypted.
  • Verify Origin SSL Certificate is switched off when a zone becomes a tunnel zone, because most services on a private network carry a certificate of their own making. Switch it back on to have an https endpoint checked: it then has to present a certificate a public authority issued for the hostname it is asked for, which is the endpoint's host unless the Host Header or Forward Host Header says otherwise.
  • Host Header is sent to your service as the Host header. Left empty, the endpoint's host is sent; with Forward Host Header on, each visitor's hostname.

While the tunnel is disabled, or no connector is running, the zone answers visitors with an error page (502), and the tunnel's page says why.

Disable or delete a tunnel#

The Enabled switch on the tunnel's page turns a tunnel off without changing anything else: its connector is refused and its zones answer with the error page until it is switched back on. Delete removes the tunnel and its endpoints, and is refused while one of its endpoints is a zone's origin.

Through the API, see Tunnels in the API section.

Ask a human

To
Subject
Docs: CacheGenie Tunnels

Read and answered by the people who build CacheGenie, seven days a week.

Write to us