Advanced Tunnel Configuration
Enterprise Feature
Secure tunneling is available as an add-on as part of an enterprise plan. If you would like to purchase this feature, please contact us at sales@zuplo.com or reach out to your account manager.
Most enterprise features can be used in a trial mode for a limited time. Feel free to use enterprise features for development and testing purposes.
The zuplo/tunnel image covers most
deployments without configuration beyond TUNNEL_TOKEN. This page is for teams
that need more control: pinning versions, tuning the transport, rotating tokens,
or building and running the connector image themselves.
The cloudflared foundation
Zuplo's tunnel is a thin packaging of
cloudflared, Cloudflare's open
source tunnel connector. It isn't a Zuplo-specific protocol or a proprietary
agent. The entire zuplo/tunnel image is the upstream
cloudflare/cloudflared
image with a fixed entrypoint:
Code
Two consequences follow from this. First, everything the cloudflared documentation says about deploying, monitoring, and tuning a connector applies to your Zuplo tunnel. Second, you can run the upstream image yourself instead of Zuplo's — see Run your own connector image.
Entrypoint flags
| Flag | Why the image sets it |
|---|---|
--no-autoupdate | Stops cloudflared from replacing its own binary while running. The image tag is then the only thing that determines the version, which keeps containers immutable and deployments reproducible. |
--protocol http2 | Forces the HTTP/2 transport. The cloudflared default, auto, prefers QUIC over UDP port 7844 and falls back to HTTP/2 when it can't open UDP connections. Many corporate networks block outbound UDP, so pinning HTTP/2 skips the fallback. |
run | Runs a remotely-managed tunnel. The tunnel's routing configuration lives in Zuplo, not in a local config file, and cloudflared reads its credentials from TUNNEL_TOKEN. |
Container characteristics
Because the image inherits the upstream cloudflared base, it has properties worth knowing when you write a deployment manifest or a security policy:
- Distroless base, no shell. You can't exec into a running tunnel container to debug it. Run a separate debug container in the same network namespace instead — see Check connectivity to your backend.
- Runs as a non-root user (UID 65532). It needs no elevated privileges, no additional Linux capabilities, and no writable root filesystem.
- Needs no persistent volume. The tunnel holds no state between restarts and fetches its configuration from Zuplo on startup.
- Listens on no inbound ports unless you set
TUNNEL_METRICS.
Environment variables
The tunnel reads cloudflared's environment variables. The ones that matter for a Zuplo tunnel:
| Variable | Default | Description |
|---|---|---|
TUNNEL_TOKEN | none | The tunnel's connection token, from zuplo tunnel describe. Required. |
TUNNEL_LOGLEVEL | info | Log verbosity. One of debug, info, warn, error, or fatal. Use debug when troubleshooting. |
TUNNEL_METRICS | none | Address to serve Prometheus metrics on, such as 0.0.0.0:2000. Useful for scraping connection health. |
TUNNEL_TRANSPORT_PROTOCOL | auto | Transport to Cloudflare's edge. One of auto, http2, or quic. |
NO_AUTOUPDATE | false | Disables in-place binary updates. |
TUNNEL_EDGE_IP_VERSION | 4 | IP version for reaching the edge. One of 4, 6, or auto. |
Flags override environment variables
The zuplo/tunnel image sets --no-autoupdate and --protocol http2 as
command-line flags in its entrypoint, and cloudflared gives command-line flags
precedence over environment variables. Setting NO_AUTOUPDATE or
TUNNEL_TRANSPORT_PROTOCOL on a zuplo/tunnel container has no effect. To
change either one, build your own image with a different entrypoint.
Pin and upgrade the image version
The zuplo/tunnel tags mirror the cloudflared release they wrap, so
zuplo/tunnel:2025.10.1 contains cloudflared 2025.10.1. The latest tag always
points at the most recent release.
For production, pin an explicit tag rather than using latest, so a redeploy
can't silently change connector versions:
Code
Then upgrade deliberately. Cloudflare supports cloudflared versions released within one year of the most recent release, and may introduce breaking changes that affect older versions. Check for a newer tag on a regular cadence and treat the upgrade as routine maintenance. Test each new version in a staging environment before rolling it out to production.
Because tunnel instances that share a token act as replicas, you can upgrade without downtime: start instances on the new version, wait for them to connect, then stop the old ones.
Rotate the tunnel token
Rotate a token on a schedule, and immediately if you suspect it's been exposed. With at least two instances running, you can rotate without dropping traffic.
-
Issue a new token for the tunnel:
CodeAfter rotation, the old token can't establish new connections, but instances already connected with it keep serving traffic.
-
Update the token in your secret manager.
-
Restart half your instances so they pick up the new token, and wait for them to report as connected.
-
Restart the remaining instances.
Rotating with a single instance running causes a brief interruption while the instance restarts. Schedule it during a maintenance window.
Run your own connector image
Because the tunnel is stock cloudflared, you can build and run the connector yourself. Consider this when you need to:
- Change the entrypoint flags, such as running QUIC instead of HTTP/2, or exposing the metrics endpoint.
- Mirror the image into your own registry to satisfy a policy that forbids pulling from public registries.
- Meet a scanning, signing, or base-image requirement your platform enforces.
- Run on
arm64, using a matching upstream tag.
To match the behavior of zuplo/tunnel, build from the upstream image and
replicate the entrypoint:
Code
Replace 2026.7.3 with a current tag from
Docker Hub — a version
pinned here goes stale, and running a connector more than a year behind the
latest release falls outside Cloudflare's support window. Use the -amd64 or
-arm64 suffix that matches your host architecture.
Build and run it with the same TUNNEL_TOKEN you'd give the Zuplo image:
Code
You can also run the upstream image directly, without a Dockerfile, by supplying the command yourself:
Code
Keep the run subcommand and don't add a local configuration file, credentials
file, or --url argument. Your tunnel is remotely managed: Zuplo owns the
routing configuration, and cloudflared fetches it using the token. Local
configuration conflicts with that and can stop traffic reaching your services.
Zuplo tests and supports the zuplo/tunnel image. A connector image you build
and operate yourself is yours to maintain, and support can help with the tunnel
and its configuration in Zuplo but not with your image or build pipeline. If
you're unsure whether a change is safe, ask
Zuplo support before rolling it out.
Next steps
- Troubleshoot a tunnel — diagnose a tunnel that's down or not passing traffic.
- Connect to tunnel services — the service
configuration reference and
service://usage.