ZuploZuplo
LoginStart for Free
  • Documentation
  • API Reference
Introduction
Getting Started
    Develop in the portal
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingDynamic MCP Server - Quickstart
    Develop locally with the CLI
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingDynamic MCP Server - Quickstart
Concepts
Development
Policies
Handlers
API Keys
Rate Limiting
Caching
MCP Server
MCP Gateway
AI Gateway
Developer Portal
Monetization
GraphQL
Deploying & Source Control
Analytics
Observability
Networking & Infrastructure
    Overview
    Managed Dedicated
    Managed EdgeSelf Hosted
    Custom Domains
    Securing Your Backend
      Securing your backend
      IAM Authentication
      mTLS
      Secure Tunnel
        OverviewSetupConnect to ServicesAdvancedTroubleshooting
    Web Application Firewalls
    DDoS Protection
Account Management
Programming API
Build with AI
Zuplo CLI
Migration Guides
Platform LimitsVersion Support PolicySecuritySupportTrust & ComplianceChangelog
powered by Zudoku
Secure Tunnel

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
FROM cloudflare/cloudflared:2026.7.3-amd64 ENTRYPOINT ["cloudflared", "tunnel", "--no-autoupdate", "--protocol", "http2", "run"]

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

FlagWhy the image sets it
--no-autoupdateStops 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 http2Forces 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.
runRuns 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:

VariableDefaultDescription
TUNNEL_TOKENnoneThe tunnel's connection token, from zuplo tunnel describe. Required.
TUNNEL_LOGLEVELinfoLog verbosity. One of debug, info, warn, error, or fatal. Use debug when troubleshooting.
TUNNEL_METRICSnoneAddress to serve Prometheus metrics on, such as 0.0.0.0:2000. Useful for scraping connection health.
TUNNEL_TRANSPORT_PROTOCOLautoTransport to Cloudflare's edge. One of auto, http2, or quic.
NO_AUTOUPDATEfalseDisables in-place binary updates.
TUNNEL_EDGE_IP_VERSION4IP 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:

TerminalCode
docker run -d --name zuplo-tunnel \ -e TUNNEL_TOKEN=<YOUR_TUNNEL_TOKEN> \ zuplo/tunnel:2025.10.1

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.

  1. Issue a new token for the tunnel:

    TerminalCode
    zuplo tunnel rotate-token --tunnel-id tnl_TRMZwunq2PLNQDwhu6A04Bmx

    After rotation, the old token can't establish new connections, but instances already connected with it keep serving traffic.

  2. Update the token in your secret manager.

  3. Restart half your instances so they pick up the new token, and wait for them to report as connected.

  4. 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
FROM cloudflare/cloudflared:2026.7.3-amd64 ENTRYPOINT ["cloudflared", "tunnel", "--no-autoupdate", "--protocol", "http2", "run"]

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:

TerminalCode
docker build -t my-registry/tunnel:2026.7.3 . docker run -d --name tunnel \ -e TUNNEL_TOKEN=<YOUR_TUNNEL_TOKEN> \ my-registry/tunnel:2026.7.3

You can also run the upstream image directly, without a Dockerfile, by supplying the command yourself:

TerminalCode
docker run -d --name tunnel \ -e TUNNEL_TOKEN=<YOUR_TUNNEL_TOKEN> \ cloudflare/cloudflared:2026.7.3-amd64 \ tunnel --no-autoupdate --protocol http2 run

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.
Edit this page
Last modified on August 5, 2026
Connect to ServicesTroubleshooting
On this page
  • The cloudflared foundation
    • Entrypoint flags
    • Container characteristics
  • Environment variables
  • Pin and upgrade the image version
  • Rotate the tunnel token
  • Run your own connector image
  • Next steps