# Edge tunnel gateway

Source: https://docs.quake.ai/resources/iac-templates/edge-tunnel-gateway
Markdown: https://docs.quake.ai/resources/iac-templates/edge-tunnel-gateway.md

---

# Edge tunnel gateway

This pattern composes Compute, Network, and Block Storage into a self-hosted tunnel endpoint on infrastructure you control.

## What this template does

Provisions a single instance running [Pangolin](https://github.com/fosrl/pangolin), an open-source tunnel and identity-aware reverse proxy, that exposes private or home-lab services through a public floating IP:

- Compute instance that runs Pangolin, Gerbil (WireGuard), and Traefik in Docker, sized for a modest tunnel surface (1 vCPU and 2 GiB RAM by default)
- Private network, subnet, router, port, and security group; a floating IP on the tunnel endpoint only
- A block volume mounted at `/data`, so Pangolin config, Traefik certificates, and tunnel state live on a volume you can grow rather than on the boot disk
- cloud-init installs Docker, generates a server secret on first boot, starts the Pangolin stack, and writes setup instructions to `/root/tunnel-admin-credentials`

Private services stay behind CGNAT, a home router, or a private subnet with no inbound ports open. A tunnel client (Pangolin Newt) on the private side dials out to the endpoint; Traefik routes authenticated traffic over the WireGuard tunnel to those services.

No credential ships with this template. The instance generates the server secret and initial setup token on first boot.

## Honest scope

This endpoint runs in one region on a VM you operate. It exposes a service *through* your Quake AI VM; it is not a global edge network and it does not absorb volumetric DDoS traffic. For geographic distribution and edge absorption, [front the origin with a third-party CDN](/docs/network/how-to/front-with-cdn).

## Alternate engines

This template leads with Pangolin (AGPL-3.0 community edition, WireGuard tunnel + Traefik routing + identity/SSO layer + dashboard). [frp](https://github.com/fatedier/frp) fits when you want a feature-complete TCP/UDP/HTTP tunnel without an access-control layer. [rathole](https://github.com/rapiz1/rathole) fits when you want the lowest resource use for the tunnel half only. [Chisel](https://github.com/jpillora/chisel) fits when you need tunnels over HTTP/HTTPS through restrictive networks. Those three solve only the tunnel half; Pangolin covers both the tunnel and who-is-allowed-through-it.

## Parameters

| Parameter | Description | Default |
| --- | --- | --- |
| `key_name` | SSH keypair name (must already exist) | No default |
| `flavor_name` | Instance size (Pangolin + Gerbil + Traefik in 2 GiB) | `s1a.small` |
| `image_name` | Operating system image | `Ubuntu-24.04` |
| `app_name` | Display name prefix for resources | `edge-tunnel-gateway` |
| `pangolin_version` | Pangolin container image tag | `1.18.4` |
| `gerbil_version` | Gerbil WireGuard manager image tag | `1.18.4` |
| `traefik_version` | Traefik image tag | `v3.7` |
| `wireguard_port` | UDP port for the WireGuard tunnel plane | `51820` |
| `wireguard_client_port` | Secondary UDP port for tunnel clients | `21820` |
| `dashboard_port` | Dashboard API port (reach via SSH tunnel) | `3001` |
| `domain` | Public hostname for the dashboard; empty serves HTTP on the floating IP | `""` |
| `base_domain` | Root domain for exposed resources; derived from `domain` when empty | Derived |
| `letsencrypt_email` | Email for Let's Encrypt and initial admin login when `domain` is set | `""` |
| `volume_size` | Block volume size in GiB, mounted at `/data` | `20` |
| `external_network` | External network for floating IP allocation | `PublicStatic` |
| `private_cidr` | CIDR for the private subnet | `10.42.0.0/24` |

## Ports and access

| Port | Protocol | Purpose |
| --- | --- | --- |
| 22 | TCP | Host SSH for administration |
| 80 | TCP | HTTP entry (Traefik; redirects to HTTPS when `domain` is set) |
| 443 | TCP | HTTPS entry when TLS is configured |
| 51820 | UDP | WireGuard tunnel control/data (Gerbil) |
| 21820 | UDP | Secondary WireGuard client port |
| 3001 | TCP | Pangolin dashboard API (not opened in the security group; use an SSH tunnel) |

## When to use this pattern

Run your own tunnel endpoint on a VM with a public IP so services behind CGNAT, a home lab, or a private subnet reach the internet without opening inbound ports on the private side. Pangolin adds identity-aware access (SSO, one-time codes, per-resource policies) on top of the WireGuard tunnel.

For TLS termination without tunneling, see the [edge reverse proxy template](/resources/iac-templates/edge-reverse-proxy). For L7 attack filtering on a public front door, see the [edge WAF template](/resources/iac-templates/edge-waf). For API rate limits and key auth, see the [API gateway template](/resources/iac-templates/api-gateway).

## Estimated cost

<PricingCompanion
  components={[
    { kind: "template", slug: "edge-tunnel-gateway", required: true },
  ]}
/>

## Template source

This is a [validated OpenTofu template](/docs/platform/validation#how-infrastructure-templates-are-checked).

<TemplateSource slug="edge-tunnel-gateway" />

<TemplateResourceMap template="edge-tunnel-gateway" format="opentofu" />

## Customize this pattern

- [Customize a template's image and flavor](/docs/automation/how-to/customize-template-image-flavor)
- [Add a block volume to a template](/docs/automation/how-to/add-volume-to-template)
- [Parameterize a template with a tfvars file](/docs/automation/how-to/parameterize-template-tfvars)

## See also

- [Deploy an edge tunnel gateway with the edge-tunnel-gateway template](/resources/deployments/deploy-edge-tunnel-gateway-template)
- [Edge reverse proxy template](/resources/iac-templates/edge-reverse-proxy)
- [Edge WAF template](/resources/iac-templates/edge-waf)
- [API gateway template](/resources/iac-templates/api-gateway)
- [Point a domain to Quake AI](/docs/network/how-to/point-domain-to-quake-ai)
