ZuploZuplo
LoginSign Up
  • Documentation
  • API Reference
Introduction
Getting Started
    Develop using the Portal
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingMCP - Quick start
    Develop Locally
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth
Concepts
Development
Policies
Handlers
API Keys
MCP Server
MCP Gateway
AI Gateway
Developer Portal
Monetization
Deploying & Source Control
Observability
Networking & Infrastructure
    Overview
    Managed Dedicated
    Managed EdgeSelf Hosted
    Custom Domains
    Securing Your Backend
      Securing your backendGateway to Origin mTLS AuthenticationGCP Backend with Upstream Auth
      Secure Tunnel
        Secure TunnelTunnel Setup & UseTunnel Troubleshooting
    Web Application Firewalls
    DDoS Protection
Account Management
Programming API
Build with AI
Zuplo CLI
Migration Guides
Platform LimitsSecuritySupportTrust & ComplianceChangelog
powered by Zudoku
Secure Tunnel

Tunnel Setup & Use

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.

Platform Requirement

The Zuplo tunnel service is officially supported on Linux only. The zuplo/tunnel Docker image is a Linux container, and any non-containerized deployment must target a Linux host. Cloud container platforms (AWS ECS, Azure Container Instances, GCP Cloud Run, Kubernetes) run Linux containers by default and require no extra configuration. If you are deploying on a virtual machine or bare metal, ensure the host runs a supported Linux distribution.

Setting up Tunnels

A tunnel is a way to expose your internal services to the Zuplo gateway without exposing it to the public internet. Your Zuplo Gateway accesses those services through the service:// protocol.

Create the tunnel

Before you deploy the tunnel container, create the tunnel in Zuplo using the CLI. This gives you the tunnel record in your account and the token that you will later provide to the container as TUNNEL_TOKEN.

TerminalCode
zuplo tunnel create --tunnel-name <your-tunnel-name> zuplo tunnel list zuplo tunnel describe --tunnel-id <your-tunnel-id>

Use these commands as follows:

  1. Run zuplo tunnel create to create the tunnel.
  2. Run zuplo tunnel list to see the tunnels in your account and identify the tunnel ID if you need it.
  3. Run zuplo tunnel describe with the tunnel ID to retrieve the tunnel details and copy the token value you will use for TUNNEL_TOKEN.

The easiest way to deploy your tunnel is using a Docker container. The three basic requirements for deploying a secure tunnel with Docker are:

  1. A tunnel secret that's provided to the Docker container as an environment variable named TUNNEL_TOKEN (the secret is provided by the Zuplo CLI when you create the tunnel. See creating a tunnel)
  2. The ability for the tunnel service to make an outbound connection to the public internet to establish the secure tunnel.
  3. The ability for the tunnel service to make a request to your internal API by a DNS address. (for example https://my-service.local/api).

The tunnel can run anywhere you can deploy a Docker container. Where you deploy depends on your specific setup. To run the Docker container on your own infrastructure, refer to instructions from your cloud provider or contact Zuplo support for assistance.

Below are a few option for deploying the tunnel.

  • Deploying Docker containers on Azure
  • Deploying Docker containers on AWS ECS
  • Deploying container images to GCP

The docker container is zuplo/tunnel and is available on Docker Hub.

Your running container needs a single environment variable named TUNNEL_TOKEN. You should store the value as a secret using the recommended means of secret storage and environment variable injection for your platform.

Configuring services

Once you have created a tunnel, you can configure which services it should expose using a configuration file. Below is a sample configuration file. The properties in the services objects are explained below.

  • name - This is the name of the service that you will use from your Zuplo project
  • endpoint - This is the local endpoint of your service that you tunnel can connect to
  • configurations - This object specifies which projects and which environments can access this service.
    • project - The name of the Zuplo project
    • accessibleBy - The environments which can use the tunnel. Valid values are production, preview, and working-copy.
tunnel-config.json
{ "version": 1, "services": [ { "name": "my-awesome-service-prod", "endpoint": "http://localhost:8000", "configurations": [ { "project": "my-project", "accessibleBy": ["production"] }, { "project": "my-other-project", "accessibleBy": ["production"] } ] }, { "name": "my-awesome-service-staging", "endpoint": "http://localhost:9000", "configurations": [ { "project": "my-project", "accessibleBy": ["preview", "working-copy"] }, { "project": "my-other-project", "accessibleBy": ["preview", "working-copy"] } ] } ] }
TerminalCode
zuplo tunnel services update \ --configuration-file <path-to-your-configuration-file> \ --tunnel-id <your-tunnel-id>

Using Services Exposed through Tunnels in Code

Once set up, the services in the tunnels can be treated like any API host that you call from your Zuplo gateway. Each service exposed through tunnels is called with the URL schema service://, so if your service is named my-awesome-service you will call it using the URL service://my-awesome-service.

This URL can be used in code as shown below.

Code
import { ZuploContext, ZuploRequest } from "@zuplo/runtime"; export default async function (request: ZuploRequest, context: ZuploContext) { const response = await fetch("service://my-awesome-service/hello-world"); if (response.status > 399) { return "It didn't work. :("; } else { return response; } }

It's common to have multiple services for each of your internal environments. Each service can be restricted so that it's only accessible by specific Zuplo environments. For example, you might have two services one for production and one for staging.

  • service://my-awesome-service-prod (Production)
  • service://my-awesome-service-staging (Staging)

Using Services Exposed through Tunnels in Configuration

Services can also be used in routes.oas.json file such as with the URL Rewrite handler. To call a tunnel service simply use it as part of the rewrite URL as shown in the image below.

Zuplo route handling

Service Environment Variables

When using these services in your code or configuration, it's often useful to store the values as an environment variable. This way you can change which environment calls which tunnel without changing code or configuration.

For the production environment you would set the BASE_SERVICE_URL to the production service name. See this document for more about Environment Variables

Code
BASE_SERVICE_URL=service://my-awesome-service-prod

And for staging, you would use the staging service name.

Code
BASE_SERVICE_URL=service://my-awesome-service-staging

In your handler code or other configuration, the service can be accessed using the environment variable.

Code
import { ZuploContext, ZuploRequest, environment } from "@zuplo/runtime"; export default async function (request: ZuploRequest, context: ZuploContext) { const response = await fetch(`${environment.BASE_SERVICE_URL}/hello-world`); if (response.status > 399) { return "It didn't work. :("; } else { return response; } }

Environment variables can also be used in configuration, such as the URL Rewrite handler as shown below.

Zuplo environment variables

Tunnel Upgrades

Zuplo publishes a new release of the tunnel Docker image about once per month or whenever Cloudflare ships a release to their underlying tunnel tools. The most recent version of the Docker Image is always tagged with the latest tag. We recommend periodically checking and upgrading the tunnel to the latest release to ensure you have the latest security and performance updates.

We recommend testing each release of the tunnel in a staging environment before rolling out to production.

Troubleshooting

For troubleshooting see this document.

Edit this page
Last modified on April 28, 2026
Secure TunnelTunnel Troubleshooting
On this page
  • Setting up Tunnels
  • Create the tunnel
  • Configuring services
  • Using Services Exposed through Tunnels in Code
  • Using Services Exposed through Tunnels in Configuration
  • Service Environment Variables
  • Tunnel Upgrades
  • Troubleshooting
JSON
TypeScript
TypeScript