Secure Tunnel

Advanced Tunnel Configuration

Applies to
Gatewayruntime for API, AI, and MCP gateways
Hosting
Managed EdgeManaged DedicatedDiffersSelf-HostedDiffers
2 differences by hosting option
Managed Dedicated

Tunnels work on Managed Dedicated, but most teams connect to private backends with their cloud provider's native networking, such as a transit gateway or VPC peering. See Networking.

Self-Hosted

Tunnels work on Self-Hosted, but your gateway already runs on your network, so most teams reach private backends directly or with native networking, such as a transit gateway or VPC peering.

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 mirroring the image into their own registry.

How the image runs

The image starts the tunnel with fixed settings:

SettingWhy the image sets it
No automatic updatesThe tunnel never replaces its own binary while running. The image tag is the only thing that determines the version, which keeps containers immutable and deployments reproducible.
HTTP/2 transportThe tunnel connects over HTTP/2 on TCP port 443. Many corporate networks block outbound UDP, so the image doesn't try a UDP transport first.
Remotely managed routingThe tunnel's routing configuration lives in Zuplo, not in a local config file. The tunnel reads its credentials from TUNNEL_TOKEN and fetches the rest of its configuration from Zuplo when it starts.

Container characteristics

The image 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 these environment variables:

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 the tunnel uses to connect to Zuplo. One of auto, http2, or quic.
NO_AUTOUPDATEfalseDisables in-place binary updates.
TUNNEL_EDGE_IP_VERSION4IP version for connecting to Zuplo. One of 4, 6, or auto.

Image settings override environment variables

The zuplo/tunnel image turns off automatic updates and sets the HTTP/2 transport on its command line, which takes precedence over environment variables. Setting NO_AUTOUPDATE or TUNNEL_TRANSPORT_PROTOCOL on a zuplo/tunnel container has no effect.

Pin and upgrade the image version

The zuplo/tunnel tags are date-based versions, such as zuplo/tunnel: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. Versions more than a year older than the latest release can stop working, and new releases can include breaking changes. 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.

Mirror the image into your registry

If a policy forbids pulling from public registries, copy zuplo/tunnel into your own registry and run it from there. Keep the image unchanged and pass the same TUNNEL_TOKEN:

TerminalCode
docker pull zuplo/tunnel:2025.10.1 docker tag zuplo/tunnel:2025.10.1 my-registry/zuplo-tunnel:2025.10.1 docker push my-registry/zuplo-tunnel:2025.10.1

Mirror each new version the same way when you upgrade. Zuplo tests and supports the zuplo/tunnel image. If you change the image or build your own, support can help with the tunnel and its configuration in Zuplo but not with your image.

Next steps

Last modified on