zuplo 7.0.1 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Connect to an AWS ALB with mTLS
3
- sidebar_label: Connect to an AWS ALB with mTLS
3
+ sidebar_label: AWS ALB
4
4
  description:
5
5
  Configure Zuplo to authenticate to an AWS Application Load Balancer using a
6
6
  mutual TLS client certificate, so the ALB only accepts traffic that comes
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Secure a GCP Backend with Zuplo Upstream Auth
3
- sidebar_label: GCP Backend with Upstream Auth
3
+ sidebar_label: GCP Backend
4
4
  ---
5
5
 
6
6
  When using any API gateway as your API's entry point, it's critical that only
@@ -1,84 +1,160 @@
1
1
  ---
2
2
  title: Secure Tunnel
3
+ sidebar_label: Overview
3
4
  ---
4
5
 
5
- For customers running on bare metal, on-premises, or other non-cloud providers
6
- tunnels provides a way to secure your backend without mTLS or IAM.
7
-
8
- The way this system works is by deploying a small service inside your network or
9
- VPC that makes a secure outbound connection to Zuplo's infrastructure. Your
10
- Zuplo API Gateway can then use this tunnel to securely route traffic to your
11
- private API. The benefits of a secure tunnel are:
12
-
13
- 1. Because the tunnel makes an outbound connection, there is no need for your
14
- API to be exposed on the internet at all.
15
- 2. All traffic between Zuplo and your API is fully encrypted.
16
- 3. You eliminate the need to configure complex ingress, firewall, or other types
17
- of policies to route traffic into your API. Simply install the tunnel and
18
- Zuplo takes care of the rest.
19
-
20
- ## How does the Tunnel Work?
21
-
22
- The Zuplo tunnel can run on virtually any Linux-based infrastructure. The most
23
- common way users install the tunnel is as a Docker container, but it can also
24
- run directly on a Linux virtual machine or bare-metal server. The tunnel itself
25
- is a lightweight service that when started makes an outbound connection to the
26
- Zuplo network and then through to your Zuplo Gateway.
27
-
28
- When the tunnel service connects to the Zuplo network, traffic from your gateway
29
- can be routed to internal services running in your network or VPC. For example,
30
- if your API is running on the internal DNS address `external-api.local`, the
31
- tunnel will route traffic from the Zuplo API Gateway to your internal service
32
- based only on the code and policies you have set up in your Zuplo Gateway.
33
-
34
- The example below illustrates how the Zuplo tunnel would be configured in an AWS
35
- ECS Cluster. Notice that there is no public IP address or ingress traffic in
36
- this configuration. This is a completely private VPC. The tunnel makes an
37
- outbound connection to the Zuplo Gateway and then uses internal DNS to route
38
- requests to the Private API.
39
-
40
- ![System diagram](../../public/media/secure-tunnel/fefdc7fb-f3b6-4908-8485-3d20cb769cfd.png)
41
-
42
- ## Is this Secure?
43
-
44
- Zuplo builds on top of many different tools to ensure that your gateway and API
45
- stay secure. Each tunnel uses a secret key that allows it to securely connect to
46
- Zuplo's network. Under the hood, Zuplo relies on Cloudflare's network for
47
- establishing secure and reliable tunnel connections. Each tunnel is configured
48
- with unique access policies that allow only the Zuplo Gateway that you have
49
- authorized to make connections over that tunnel. Every incoming request is
50
- terminated using Cloudflare's network which provides sophisticated DDoS, bot,
51
- and threat protections. Next, the request is routed through your Zuplo Gateway
52
- which can be configured with all policies and code you require to control access
53
- to your API. By default, no requests will be routed from your gateway to your
54
- API until you configure routes, URL rewrites, and policies in your Gateway.
55
-
56
- All traffic is terminated at the edge with SSL certificates and encrypted
57
- through the entire route to your API. All requests that your gateway makes to
58
- Zuplo's internal services like API Key Management or Rate Limiting are also
59
- transported over secure and encrypted tunnels.
60
-
61
- Every request is logged and you can configure Zuplo's logs to push to the log
62
- service of your choice.
63
-
64
- ## How will tunnels perform?
65
-
66
- Most customers are fine running two instances of the tunnel service for
67
- redundancy in the event one pod/service fails. Each tunnel is able to handle
68
- millions of requests per minute. For customers that require additional scale,
69
- simply increase the number of tunnel instances you are running or configure auto
70
- scaling on your deployment. It's unlikely that the tunnel will become the
71
- bottleneck in your traffic before other factors, but if you do run into any
72
- issues [contact support](mailto:support@zuplo.com) and we will work out a
73
- solution that meets your scale requirements.
74
-
75
- ## How should I Configure the Tunnel?
76
-
77
- You should run your tunnel with an IAM role or other network policies that only
78
- allow the tunnel to make requests to the network services that you want your
79
- Gateway to access. This can be done in a variety of ways depending on your
80
- setup. IAM roles, network segregation, and internal service meshes are common
81
- means of controlling which services the tunnel can access.
82
-
83
- For details on how to configure a tunnel on your network see
84
- [the setup guide](tunnel-setup.mdx).
6
+ <EnterpriseFeature name="Secure tunneling" />
7
+
8
+ A secure tunnel connects your Zuplo gateway to a backend API that isn't
9
+ reachable from the public internet. You run a small tunnel service inside your
10
+ network, it opens an outbound connection to Zuplo, and your gateway routes
11
+ requests back through that connection to your private API.
12
+
13
+ Tunnels suit backends that run where IAM roles and mTLS aren't available — bare
14
+ metal, on-premises data centers, or a non-cloud hosting provider. For the other
15
+ ways to secure gateway-to-backend traffic, see
16
+ [Securing your backend](./securing-your-backend.mdx).
17
+
18
+ A tunnel gives you three things:
19
+
20
+ - Your API doesn't need to be exposed on the internet at all, because the tunnel
21
+ dials out rather than accepting inbound connections.
22
+ - All traffic between Zuplo and your API is encrypted.
23
+ - You don't need to configure ingress, firewall rules, or load balancers to let
24
+ gateway traffic in. Install the tunnel and Zuplo routes to it.
25
+
26
+ ## How a tunnel works
27
+
28
+ The tunnel is a lightweight service that runs on Linux, most often as a Docker
29
+ container. On startup it authenticates with a token you generate in Zuplo and
30
+ establishes an outbound connection to Zuplo's network.
31
+
32
+ Once connected, the tunnel can reach internal services on your network by their
33
+ private DNS names. You tell Zuplo which of those services to expose by naming
34
+ them in a tunnel configuration file. Your gateway then calls each one through
35
+ the `service://` URL scheme instead of a hostname. A service named
36
+ `payments-api` becomes `service://payments-api`, and the tunnel forwards those
37
+ requests to whatever internal endpoint you mapped it to, such as
38
+ `http://payments.internal:8080`.
39
+
40
+ The following diagram shows the path a request takes. Note that the gateway
41
+ never opens a connection into your network — it reuses the connection the tunnel
42
+ already established.
43
+
44
+ <Diagram height="h-64" direction="horizontal">
45
+ <DiagramNode id="client">API client</DiagramNode>
46
+ <DiagramNode id="gateway" variant="zuplo">
47
+ Zuplo Gateway
48
+ </DiagramNode>
49
+ <DiagramGroup id="private" label="Your private network">
50
+ <DiagramNode id="tunnel" variant="blue">
51
+ Tunnel service
52
+ </DiagramNode>
53
+ <DiagramNode id="api" variant="green">
54
+ Private API
55
+ </DiagramNode>
56
+ </DiagramGroup>
57
+ <DiagramEdge from="client" to="gateway" label="HTTPS" />
58
+ <DiagramEdge from="gateway" to="tunnel" label="service://" animated />
59
+ <DiagramEdge from="tunnel" to="api" fromSide="bottom" toSide="top" />
60
+ </Diagram>
61
+
62
+ Because the tunnel controls which internal endpoints it forwards to, and Zuplo
63
+ controls which projects and environments can use each service, no traffic
64
+ reaches your API until you configure both halves.
65
+
66
+ ## Architecture example
67
+
68
+ The following diagram shows a tunnel running in an AWS ECS cluster. The VPC is
69
+ fully private: there's no public IP address and no inbound traffic. The tunnel
70
+ makes an outbound connection to Zuplo, then uses internal DNS to reach the
71
+ private API.
72
+
73
+ <Framed>
74
+
75
+ ![A tunnel container running in a private AWS VPC, connecting outbound to the Zuplo Gateway and forwarding requests to a private API in the same ECS cluster](../../public/media/secure-tunnel/fefdc7fb-f3b6-4908-8485-3d20cb769cfd.png)
76
+
77
+ </Framed>
78
+
79
+ The same pattern applies to Azure Container Instances, GCP Cloud Run,
80
+ Kubernetes, and plain Linux hosts. Only the deployment mechanics change.
81
+
82
+ ## Security model
83
+
84
+ Zuplo's tunnel is built on [cloudflared](./tunnel-advanced.mdx), Cloudflare's
85
+ open source tunnel connector, and inherits Cloudflare's network for transport.
86
+ Several layers control what can reach your API:
87
+
88
+ - **Token authentication.** Each tunnel has its own secret token. Without it, a
89
+ tunnel instance can't connect.
90
+ - **Per-tunnel access policies.** Each tunnel accepts connections only from the
91
+ Zuplo gateways you authorize.
92
+ - **Per-service scoping.** Each service in your tunnel configuration names the
93
+ projects and environments allowed to call it, so a preview environment can't
94
+ reach a production backend unless you say so.
95
+ - **Edge protections.** Incoming requests terminate on Cloudflare's network,
96
+ which adds DDoS, bot, and threat protection ahead of your gateway.
97
+ - **Gateway policies.** Requests then pass through your Zuplo gateway, where
98
+ your own policies and code apply. Until you configure routes and URL rewrites,
99
+ the gateway sends nothing to your API.
100
+
101
+ Traffic is terminated with TLS at the edge and encrypted for the rest of the
102
+ path to your API. Requests your gateway makes to Zuplo's internal services, such
103
+ as API key management and rate limiting, travel over encrypted connections as
104
+ well.
105
+
106
+ Every request is logged, and you can
107
+ [forward gateway logs](./monitoring-your-gateway.mdx) to the log service of your
108
+ choice.
109
+
110
+ ## Availability and scale
111
+
112
+ Each tunnel instance opens several connections to more than one Cloudflare data
113
+ center, so a single instance survives the loss of an individual connection. Run
114
+ at least two instances so the tunnel keeps serving traffic if a host or pod
115
+ fails. Instances that share a token act as replicas of the same tunnel, and
116
+ Zuplo distributes traffic across whichever ones are available.
117
+
118
+ A single instance handles a high request volume, and adding instances or
119
+ enabling autoscaling raises the ceiling further. If you have specific throughput
120
+ requirements, [contact support](mailto:support@zuplo.com).
121
+
122
+ ## Network access control
123
+
124
+ The tunnel can reach anything its host can reach, so treat its network position
125
+ as the security boundary. Restrict it to the services you want your gateway to
126
+ call, using whichever mechanism fits your platform:
127
+
128
+ - IAM roles or service accounts scoped to specific resources
129
+ - Network segmentation, security groups, or egress rules
130
+ - Service mesh authorization policies
131
+
132
+ Naming a service in your tunnel configuration is what makes it callable from
133
+ Zuplo. Restricting the host is what limits the damage if the tunnel is
134
+ misconfigured. Do both.
135
+
136
+ ## Requirements
137
+
138
+ Running a tunnel requires:
139
+
140
+ - A Linux host or container runtime. The
141
+ [`zuplo/tunnel` image](https://hub.docker.com/r/zuplo/tunnel) is a Linux
142
+ container, and non-containerized deployments must target Linux.
143
+ - Outbound internet access from the tunnel host, so it can reach Zuplo's
144
+ network.
145
+ - Internal DNS resolution from the tunnel host to your backend services.
146
+
147
+ Managed container platforms such as AWS ECS, Azure Container Instances, GCP
148
+ Cloud Run, and Kubernetes run Linux containers by default and need no extra
149
+ configuration.
150
+
151
+ ## Next steps
152
+
153
+ - [Set up a tunnel](./tunnel-setup.mdx) — create a tunnel, run the container,
154
+ and expose your first service.
155
+ - [Connect to tunnel services](./tunnel-services.mdx) — call `service://` URLs
156
+ from your gateway code and configuration.
157
+ - [Advanced tunnel configuration](./tunnel-advanced.mdx) — the cloudflared
158
+ foundation, environment variable reference, and self-managed images.
159
+ - [Troubleshoot a tunnel](./tunnel-troubleshooting.mdx) — diagnose a tunnel
160
+ that's down or not passing traffic.
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  title: Gateway to Origin mTLS Authentication
3
+ sidebar_label: Gateway to Origin
3
4
  ---
4
5
 
5
6
  <EnterpriseFeature name="mTLS Client Certificates" />
@@ -496,7 +497,7 @@ For more information on securing your backend, see:
496
497
 
497
498
  - [Securing your Backend](./securing-your-backend.mdx) - Overview of all backend
498
499
  security options
499
- - [Shared Secret / API Key](./securing-your-backend.mdx#1-shared-secret--api-key) -
500
+ - [Shared Secret / API Key](./securing-your-backend.mdx#shared-secret-or-api-key) -
500
501
  Alternative approach using shared secrets
501
502
  - [Secure Tunnels](./secure-tunnel.mdx) - Connect to private backends without
502
503
  exposing them to the internet
@@ -8,10 +8,22 @@ correctly applied to all traffic.
8
8
 
9
9
  ![Zuplo as an API gateway](../../public/media/securing-your-backend/b7290dd1-43fa-49f8-8629-6b4899e2e9f3.png)
10
10
 
11
- To do this, we need to secure the communication between Zuplo and your backend
12
- APIs (origin). There are several options to do this securely.
11
+ That means securing the communication between Zuplo and your backend API
12
+ (origin). Several options do this, and the right one depends on where your
13
+ backend runs and what it can already verify.
13
14
 
14
- ## 1/ Shared secret / API Key
15
+ | Approach | Use it when | Plan |
16
+ | -------------------------------------------------------------- | -------------------------------------------------------------------------- | ---------- |
17
+ | [Shared secret](#shared-secret-or-api-key) | Your backend can check a header. The most common choice, and the simplest. | All |
18
+ | [IAM authentication](./upstream-iam-auth.mdx) | Your backend runs behind AWS, Azure, or Google Cloud IAM. | Enterprise |
19
+ | [mTLS](./securing-backend-mtls.mdx) | You want both sides to authenticate each other with certificates. | Enterprise |
20
+ | [Secure tunnel](./secure-tunnel.mdx) | Your backend has no public endpoint, or runs on bare metal or on premises. | Enterprise |
21
+ | [Custom networking](#custom-networking-managed-dedicated-only) | You're on managed dedicated and want VPC peering or PrivateLink. | Dedicated |
22
+
23
+ The rest of this page covers the shared secret approach in full. Each other
24
+ approach has its own section in the sidebar.
25
+
26
+ ## Shared secret or API key
15
27
 
16
28
  This is the most popular option and is used by companies like Supabase,
17
29
  Firebase, and Stripe to secure their own APIs. In this solution the backend
@@ -95,62 +107,55 @@ app.use((req, res, next) => {
95
107
  });
96
108
  ```
97
109
 
98
- ## 2/ Federated Authentication
99
-
100
- This is a new option where you can configure your cloud service (for example,
101
- GCP or AWS) to trust a JWT token created by the Zuplo runtime. If you're
102
- interested in using this option please contact us at `support@zuplo.com`.
110
+ ## IAM authentication
103
111
 
104
- ## 3/ Upstream Service Authentication
112
+ Let your cloud provider decide whether a request from Zuplo is allowed through.
113
+ Your gateway proves its identity to AWS, Azure, or Google Cloud, and your
114
+ provider's authorization rules apply — so there's no shared secret to
115
+ distribute.
105
116
 
106
- Utilize the IAM controls provided by your Cloud host to secure inbound requests
107
- and allow only authorized service principals access to your service.
117
+ Where the provider supports it, Zuplo can present a short-lived OIDC token and
118
+ exchange it for temporary credentials, which means no long-lived key exists at
119
+ all. Otherwise the policies use a key or client secret you store as an
120
+ environment variable.
108
121
 
109
- - For Azure users, you can use the
110
- [Upstream Azure AD Service Auth](../policies/upstream-azure-ad-service-auth-inbound.mdx)
111
- policy. This uses Microsoft Entra ID (formerly Azure AD) App registrations to
112
- create a token that Zuplo sends with requests to Azure.
122
+ For the policy for each provider and the trade-off between the two approaches,
123
+ see [IAM authentication for your backend](./upstream-iam-auth.mdx).
113
124
 
114
- - For GCP users, you can use our
115
- [Upstream GCP Service AUth](../policies/upstream-gcp-service-auth-inbound.mdx)
116
- or [Upstream GCP JWT](../policies/upstream-gcp-jwt-inbound.mdx) policies.
117
- These use a `service.json` credential to create or issue JWT tokens that Zuplo
118
- will send to requests to GCP.
125
+ ## mTLS authentication
119
126
 
120
- ## 4/ mTLS Authentication
127
+ Mutual TLS establishes a trust relationship between your gateway and your
128
+ backend using client certificates. Both sides authenticate each other, which
129
+ gives you a zero trust posture between the two.
121
130
 
122
- Mutual TLS (mTLS) authentication allows the configuration of a trust
123
- relationship between your Zuplo gateway and your backend API using client
124
- certificates. With mTLS, both your gateway and backend authenticate each other,
125
- providing a "Zero Trust" security model that's popular with enterprise
126
- customers.
127
-
128
- To learn how to set up mTLS with client certificates, see the
129
- [Securing your Backend with mTLS](./securing-backend-mtls.mdx) article. This is
131
+ Zuplo manages the client certificates, presents them on upstream requests, and
132
+ supports rotation and per-environment certificates. See
133
+ [Gateway to origin mTLS authentication](./securing-backend-mtls.mdx). For a
134
+ worked example against an AWS load balancer, see
135
+ [Connect to an AWS ALB with mTLS](./connect-to-aws-alb-with-mtls.mdx). This is
130
136
  an [enterprise feature](https://zuplo.com/pricing).
131
137
 
132
- ## 5/ Secure Tunneling
138
+ ## Secure tunneling
139
+
140
+ A [secure tunnel](./secure-tunnel.mdx) runs a small connector inside your VPC or
141
+ private data center that makes an outbound connection to your Zuplo gateway. It
142
+ suits workloads without IAM or mTLS capabilities — bare metal, on premises, or a
143
+ non-cloud provider. Your backend needs no public endpoint at all.
133
144
 
134
- Used by some of our larger customers, our [secure tunnels](./secure-tunnel.mdx)
135
- allow you to create a WireGuard based tunnel from your VPC or private
136
- data-center that connects directly to your Zuplo gateway. This option is useful
137
- when running workloads in a non-cloud provider (for example, bare metal, on
138
- premises, etc.) that don't have IAM or mTLS capabilities. In this solution, your
139
- backend API doesn't need to be exposed to the internet at all. This is a more
140
- complex setup and is only available on our
145
+ This is a more involved setup than the other options and is available on the
141
146
  [enterprise plan](https://zuplo.com/pricing).
142
147
 
143
- To discuss security and connectivity options, our
144
- [discord channel](https://discord.zuplo.com) is a great community, with active
145
- participation from the Zuplo team.
148
+ ## Custom networking (managed dedicated only)
149
+
150
+ On the managed dedicated plan, Zuplo can provide custom networking to reach your
151
+ backend, using your cloud provider's VPC connectivity — AWS Transit Gateway,
152
+ PrivateLink, or VPC peering.
146
153
 
147
- ## 6/ Custom Networking (Managed Dedicated Only)
154
+ For more information, see the
155
+ [networking documentation](../dedicated/networking.mdx).
148
156
 
149
- For customers on our managed dedicated plan, we can provide custom networking to
150
- connect your backend to Zuplo. This can include using VPC connectivity
151
- capabilities from your cloud provider (for example AWS, Azure, GCP, etc.) such
152
- as AWS Transit Gateway, PrivateLink, or VPC Peering to connect to your backend
153
- services.
157
+ ## Get help choosing
154
158
 
155
- For more details on networking options for managed dedicated customers, see our
156
- [Networking documentation](../dedicated/networking.mdx).
159
+ To discuss security and connectivity options, the
160
+ [Zuplo Discord](https://discord.zuplo.com) has active participation from the
161
+ Zuplo team, or contact [support](mailto:support@zuplo.com).
@@ -0,0 +1,202 @@
1
+ ---
2
+ title: Advanced Tunnel Configuration
3
+ sidebar_label: Advanced
4
+ ---
5
+
6
+ <EnterpriseFeature name="Secure tunneling" />
7
+
8
+ The [`zuplo/tunnel`](https://hub.docker.com/r/zuplo/tunnel) image covers most
9
+ deployments without configuration beyond `TUNNEL_TOKEN`. This page is for teams
10
+ that need more control: pinning versions, tuning the transport, rotating tokens,
11
+ or building and running the connector image themselves.
12
+
13
+ ## The cloudflared foundation
14
+
15
+ Zuplo's tunnel is a thin packaging of
16
+ [cloudflared](https://github.com/cloudflare/cloudflared), Cloudflare's open
17
+ source tunnel connector. It isn't a Zuplo-specific protocol or a proprietary
18
+ agent. The entire `zuplo/tunnel` image is the upstream
19
+ [`cloudflare/cloudflared`](https://hub.docker.com/r/cloudflare/cloudflared)
20
+ image with a fixed entrypoint:
21
+
22
+ ```dockerfile title="Dockerfile"
23
+ FROM cloudflare/cloudflared:2026.7.3-amd64
24
+ ENTRYPOINT ["cloudflared", "tunnel", "--no-autoupdate", "--protocol", "http2", "run"]
25
+ ```
26
+
27
+ Two consequences follow from this. First, everything the
28
+ [cloudflared documentation](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/)
29
+ says about deploying, monitoring, and tuning a connector applies to your Zuplo
30
+ tunnel. Second, you can run the upstream image yourself instead of Zuplo's — see
31
+ [Run your own connector image](#run-your-own-connector-image).
32
+
33
+ ### Entrypoint flags
34
+
35
+ | Flag | Why the image sets it |
36
+ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
37
+ | `--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. |
38
+ | `--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. |
39
+ | `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`. |
40
+
41
+ ### Container characteristics
42
+
43
+ Because the image inherits the upstream cloudflared base, it has properties
44
+ worth knowing when you write a deployment manifest or a security policy:
45
+
46
+ - **Distroless base, no shell.** You can't exec into a running tunnel container
47
+ to debug it. Run a separate debug container in the same network namespace
48
+ instead — see
49
+ [Check connectivity to your backend](./tunnel-troubleshooting.mdx#check-connectivity-to-your-backend).
50
+ - **Runs as a non-root user** (UID 65532). It needs no elevated privileges, no
51
+ additional Linux capabilities, and no writable root filesystem.
52
+ - **Needs no persistent volume.** The tunnel holds no state between restarts and
53
+ fetches its configuration from Zuplo on startup.
54
+ - **Listens on no inbound ports** unless you set `TUNNEL_METRICS`.
55
+
56
+ ## Environment variables
57
+
58
+ The tunnel reads cloudflared's environment variables. The ones that matter for a
59
+ Zuplo tunnel:
60
+
61
+ | Variable | Default | Description |
62
+ | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------ |
63
+ | `TUNNEL_TOKEN` | none | The tunnel's connection token, from `zuplo tunnel describe`. Required. |
64
+ | `TUNNEL_LOGLEVEL` | `info` | Log verbosity. One of `debug`, `info`, `warn`, `error`, or `fatal`. Use `debug` when troubleshooting. |
65
+ | `TUNNEL_METRICS` | none | Address to serve Prometheus metrics on, such as `0.0.0.0:2000`. Useful for scraping connection health. |
66
+ | `TUNNEL_TRANSPORT_PROTOCOL` | `auto` | Transport to Cloudflare's edge. One of `auto`, `http2`, or `quic`. |
67
+ | `NO_AUTOUPDATE` | `false` | Disables in-place binary updates. |
68
+ | `TUNNEL_EDGE_IP_VERSION` | `4` | IP version for reaching the edge. One of `4`, `6`, or `auto`. |
69
+
70
+ :::caution{title="Flags override environment variables"}
71
+
72
+ The `zuplo/tunnel` image sets `--no-autoupdate` and `--protocol http2` as
73
+ command-line flags in its entrypoint, and cloudflared gives command-line flags
74
+ precedence over environment variables. Setting `NO_AUTOUPDATE` or
75
+ `TUNNEL_TRANSPORT_PROTOCOL` on a `zuplo/tunnel` container has no effect. To
76
+ change either one, build your own image with a different entrypoint.
77
+
78
+ :::
79
+
80
+ ## Pin and upgrade the image version
81
+
82
+ The `zuplo/tunnel` tags mirror the cloudflared release they wrap, so
83
+ `zuplo/tunnel:2025.10.1` contains cloudflared 2025.10.1. The `latest` tag always
84
+ points at the most recent release.
85
+
86
+ For production, pin an explicit tag rather than using `latest`, so a redeploy
87
+ can't silently change connector versions:
88
+
89
+ ```bash
90
+ docker run -d --name zuplo-tunnel \
91
+ -e TUNNEL_TOKEN=<YOUR_TUNNEL_TOKEN> \
92
+ zuplo/tunnel:2025.10.1
93
+ ```
94
+
95
+ Then upgrade deliberately. Cloudflare supports cloudflared versions released
96
+ within one year of the most recent release, and may introduce breaking changes
97
+ that affect older versions. Check for a newer tag on a regular cadence and treat
98
+ the upgrade as routine maintenance. Test each new version in a staging
99
+ environment before rolling it out to production.
100
+
101
+ Because tunnel instances that share a token act as replicas, you can upgrade
102
+ without downtime: start instances on the new version, wait for them to connect,
103
+ then stop the old ones.
104
+
105
+ ## Rotate the tunnel token
106
+
107
+ Rotate a token on a schedule, and immediately if you suspect it's been exposed.
108
+ With at least two instances running, you can rotate without dropping traffic.
109
+
110
+ <Stepper>
111
+
112
+ 1. Issue a new token for the tunnel:
113
+
114
+ ```bash
115
+ zuplo tunnel rotate-token --tunnel-id tnl_TRMZwunq2PLNQDwhu6A04Bmx
116
+ ```
117
+
118
+ After rotation, the old token can't establish _new_ connections, but
119
+ instances already connected with it keep serving traffic.
120
+
121
+ 1. Update the token in your secret manager.
122
+
123
+ 1. Restart half your instances so they pick up the new token, and wait for them
124
+ to report as connected.
125
+
126
+ 1. Restart the remaining instances.
127
+
128
+ </Stepper>
129
+
130
+ Rotating with a single instance running causes a brief interruption while the
131
+ instance restarts. Schedule it during a maintenance window.
132
+
133
+ ## Run your own connector image
134
+
135
+ Because the tunnel is stock cloudflared, you can build and run the connector
136
+ yourself. Consider this when you need to:
137
+
138
+ - Change the entrypoint flags, such as running QUIC instead of HTTP/2, or
139
+ exposing the metrics endpoint.
140
+ - Mirror the image into your own registry to satisfy a policy that forbids
141
+ pulling from public registries.
142
+ - Meet a scanning, signing, or base-image requirement your platform enforces.
143
+ - Run on `arm64`, using a matching upstream tag.
144
+
145
+ To match the behavior of `zuplo/tunnel`, build from the upstream image and
146
+ replicate the entrypoint:
147
+
148
+ ```dockerfile title="Dockerfile"
149
+ FROM cloudflare/cloudflared:2026.7.3-amd64
150
+ ENTRYPOINT ["cloudflared", "tunnel", "--no-autoupdate", "--protocol", "http2", "run"]
151
+ ```
152
+
153
+ Replace `2026.7.3` with a current tag from
154
+ [Docker Hub](https://hub.docker.com/r/cloudflare/cloudflared/tags) — a version
155
+ pinned here goes stale, and running a connector more than a year behind the
156
+ latest release falls outside Cloudflare's support window. Use the `-amd64` or
157
+ `-arm64` suffix that matches your host architecture.
158
+
159
+ Build and run it with the same `TUNNEL_TOKEN` you'd give the Zuplo image:
160
+
161
+ ```bash
162
+ docker build -t my-registry/tunnel:2026.7.3 .
163
+ docker run -d --name tunnel \
164
+ -e TUNNEL_TOKEN=<YOUR_TUNNEL_TOKEN> \
165
+ my-registry/tunnel:2026.7.3
166
+ ```
167
+
168
+ You can also run the upstream image directly, without a Dockerfile, by supplying
169
+ the command yourself:
170
+
171
+ ```bash
172
+ docker run -d --name tunnel \
173
+ -e TUNNEL_TOKEN=<YOUR_TUNNEL_TOKEN> \
174
+ cloudflare/cloudflared:2026.7.3-amd64 \
175
+ tunnel --no-autoupdate --protocol http2 run
176
+ ```
177
+
178
+ :::caution
179
+
180
+ Keep the `run` subcommand and don't add a local configuration file, credentials
181
+ file, or `--url` argument. Your tunnel is remotely managed: Zuplo owns the
182
+ routing configuration, and cloudflared fetches it using the token. Local
183
+ configuration conflicts with that and can stop traffic reaching your services.
184
+
185
+ :::
186
+
187
+ :::note
188
+
189
+ Zuplo tests and supports the `zuplo/tunnel` image. A connector image you build
190
+ and operate yourself is yours to maintain, and support can help with the tunnel
191
+ and its configuration in Zuplo but not with your image or build pipeline. If
192
+ you're unsure whether a change is safe, ask
193
+ [Zuplo support](mailto:support@zuplo.com) before rolling it out.
194
+
195
+ :::
196
+
197
+ ## Next steps
198
+
199
+ - [Troubleshoot a tunnel](./tunnel-troubleshooting.mdx) — diagnose a tunnel
200
+ that's down or not passing traffic.
201
+ - [Connect to tunnel services](./tunnel-services.mdx) — the service
202
+ configuration reference and `service://` usage.