How to Self-Host Firezone Gateway with Docker
What Is Firezone?
Firezone is a zero-trust remote access platform built on WireGuard. It replaces traditional VPNs with a modern approach: instead of granting full network access, Firezone lets you define granular policies that control which users can access which resources. It uses peer-to-peer encrypted tunnels, automatic NAT traversal, and ephemeral WireGuard keys that rotate constantly.
Firezone 1.x uses a split architecture: the admin portal and control plane run as a managed service at app.firezone.dev, while Gateways — the components that connect users to your resources — run on your infrastructure. You self-host the gateways; Firezone manages the control plane. This is different from traditional self-hosted VPN solutions like WireGuard or wg-easy where you own the entire stack.
If you need a fully self-hosted VPN with no cloud dependency, look at wg-easy, Headscale, or NetBird instead. Firezone is the right choice when you want enterprise-grade zero-trust access policies without building that infrastructure yourself.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 128 MB of free RAM (per gateway)
- A Firezone account (free tier available)
- A Firezone Site and Gateway token from the admin portal
Firezone Gateways need outbound internet access to connect to the control plane at api.firezone.dev. No inbound ports need to be opened — the gateway establishes outbound connections and uses NAT traversal for client tunnels.
Architecture Overview
Before deploying, understand how the pieces fit together:
- Admin Portal (cloud-hosted at
app.firezone.dev): Where you configure Sites, Resources, Groups, Policies, and Users. - Gateways (self-hosted on your infrastructure): Linux processes that create WireGuard tunnels to clients and route traffic to your Resources. You deploy one or more per Site.
- Clients (on user devices): Official apps for macOS, Windows, Linux, iOS, and Android that connect to Gateways.
- Relays (Firezone-managed): STUN/TURN servers that help establish connections when direct peer-to-peer isn’t possible. All traffic remains end-to-end encrypted — relays cannot decrypt it.
The data plane (actual traffic) flows directly between clients and gateways over WireGuard. The control plane (configuration, auth, key distribution) goes through Firezone’s managed API.
Getting a Gateway Token
Before writing the Docker Compose file, you need a token:
- Sign up or log in at app.firezone.dev
- Create a Site (a logical grouping of Gateways and Resources — e.g., “Home Lab” or “Office”)
- Click Deploy Gateway within the Site
- Select Docker as the deployment method
- Copy the
FIREZONE_TOKENvalue — you’ll need it for the Compose file
Each Site can have multiple Gateways for redundancy and load balancing. If one Gateway goes down, clients automatically failover to another in the same Site.
Docker Compose Configuration
Create a docker-compose.yml file:
services:
firezone-gateway:
image: ghcr.io/firezone/gateway:1
container_name: firezone-gateway
restart: unless-stopped
environment:
# Required: token from Firezone admin portal
- FIREZONE_TOKEN=${FIREZONE_TOKEN}
# Optional: unique ID for this gateway (auto-generated if omitted)
- FIREZONE_ID=${FIREZONE_ID:-}
# Optional: human-readable name shown in admin portal
- FIREZONE_NAME=${FIREZONE_NAME:-gateway-1}
# Logging level: trace, debug, info, warn, error, off
- RUST_LOG=${RUST_LOG:-info}
# Enable flow logs for debugging (disable in production for performance)
- FIREZONE_ENABLE_MASQUERADE=1
cap_add:
- NET_ADMIN # Required for creating WireGuard interfaces and managing routes
sysctls:
- net.ipv4.ip_forward=1 # Enable IPv4 forwarding for routing VPN traffic
- net.ipv4.conf.all.src_valid_mark=1 # Required for WireGuard routing
- net.ipv6.conf.all.forwarding=1 # Enable IPv6 forwarding
devices:
- /dev/net/tun:/dev/net/tun # TUN device for WireGuard tunnel
volumes:
- firezone-gateway:/var/lib/firezone # Persistent state
healthcheck:
test: ["CMD", "ip", "link", "show", "tun-firezone"]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
networks:
- firezone
networks:
firezone:
driver: bridge
volumes:
firezone-gateway:
Create a .env file alongside it:
# Required: paste your token from the Firezone admin portal
FIREZONE_TOKEN=your-token-from-admin-portal
# Optional: unique identifier for this gateway instance
# Leave empty to auto-generate. Set explicitly if you want stable identity across restarts.
FIREZONE_ID=
# Optional: display name in admin portal
FIREZONE_NAME=gateway-1
# Log level: trace, debug, info, warn, error, off
RUST_LOG=info
Start the gateway:
docker compose up -d
Initial Setup
- After starting the gateway, verify it connected to the control plane:
docker compose logs firezone-gateway
You should see output indicating a successful connection to api.firezone.dev and tunnel interface creation.
-
In the Firezone admin portal, confirm your gateway shows as Online in the Site view.
-
Create Resources — define what the gateway should provide access to:
- A specific IP address (e.g.,
192.168.1.100) - A CIDR range (e.g.,
192.168.1.0/24) - A DNS name (e.g.,
nas.local)
- A specific IP address (e.g.,
-
Create a Group and add users to it.
-
Create a Policy linking the Group to the Resource. This is the zero-trust part — only users in the Group can access the Resource, and only through an authenticated client.
-
Install the Firezone Client on your devices and sign in with your account.
Configuration
Multiple Gateways for High Availability
Deploy two or more gateways in the same Site for automatic failover. Each gateway needs its own unique FIREZONE_ID:
services:
firezone-gateway-1:
image: ghcr.io/firezone/gateway:1
container_name: firezone-gw-1
restart: unless-stopped
environment:
- FIREZONE_TOKEN=${FIREZONE_TOKEN}
- FIREZONE_ID=gateway-1
- FIREZONE_NAME=gateway-primary
- RUST_LOG=info
- FIREZONE_ENABLE_MASQUERADE=1
cap_add:
- NET_ADMIN
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.forwarding=1
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- firezone-gw1:/var/lib/firezone
networks:
- firezone
firezone-gateway-2:
image: ghcr.io/firezone/gateway:1
container_name: firezone-gw-2
restart: unless-stopped
environment:
- FIREZONE_TOKEN=${FIREZONE_TOKEN}
- FIREZONE_ID=gateway-2
- FIREZONE_NAME=gateway-secondary
- RUST_LOG=info
- FIREZONE_ENABLE_MASQUERADE=1
cap_add:
- NET_ADMIN
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.forwarding=1
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- firezone-gw2:/var/lib/firezone
networks:
- firezone
networks:
firezone:
driver: bridge
volumes:
firezone-gw1:
firezone-gw2:
Both gateways use the same FIREZONE_TOKEN (tied to the Site), but different FIREZONE_ID values. Firezone automatically load-balances and fails over between them.
DNS Resources
Firezone can intercept DNS queries and route them through gateways. When you define a DNS-based Resource (like *.internal.company.com), clients automatically resolve and route traffic for matching domains through the gateway — no split-DNS configuration needed on the client side.
Telemetry
Firezone gateways send anonymous crash reports by default. To disable:
FIREZONE_NO_TELEMETRY=true
Reverse Proxy
Firezone Gateways don’t serve a web UI — the admin interface is the cloud-hosted portal at app.firezone.dev. No reverse proxy configuration is needed for the gateway itself.
If you’re using Firezone to provide access to services behind a reverse proxy like Nginx Proxy Manager or Traefik, define those services as Resources in the admin portal and create policies to control access. For general reverse proxy setup, see Reverse Proxy Setup.
Backup
The gateway’s persistent state in /var/lib/firezone contains cached configuration and WireGuard keys. Backing it up is optional — if lost, the gateway re-syncs from the control plane on next startup.
What you should back up is your Firezone account configuration (Sites, Resources, Policies). That lives in Firezone’s managed service, which handles its own backups.
For general backup strategies, see Backup Strategy.
Troubleshooting
Gateway Shows as Offline
Symptom: The gateway appears offline in the admin portal even though the container is running.
Fix: Check that the gateway can reach api.firezone.dev on port 443 (WSS):
docker compose exec firezone-gateway curl -s https://api.firezone.dev
If this fails, check your firewall rules for outbound HTTPS. Also verify your FIREZONE_TOKEN is correct — an invalid token causes silent connection failures.
Clients Can’t Reach Resources
Symptom: Client connects but can’t access defined Resources.
Fix: Verify the gateway can reach the Resource from its network:
docker compose exec firezone-gateway ping 192.168.1.100
If the gateway can’t reach it, the issue is networking — not Firezone. Ensure the Docker network has access to your LAN. You may need network_mode: host instead of bridge networking for LAN access:
services:
firezone-gateway:
# ... other config ...
network_mode: host
TUN Device Not Available
Symptom: Error about /dev/net/tun not being available.
Fix: Ensure the TUN kernel module is loaded:
sudo modprobe tun
If running on a VPS, some providers disable TUN devices. Check with your host or use a provider that supports it (Hetzner, DigitalOcean, and Linode all support TUN).
High Latency Through Gateway
Symptom: Connections through Firezone are slower than expected.
Fix: Firezone uses peer-to-peer connections by default. If direct connectivity isn’t possible, traffic routes through Firezone’s relay servers (TURN), adding latency. Check the connection type in the client app — if it shows “relayed,” the issue is NAT traversal. Deploying the gateway on a host with a public IP or enabling UPnP can help establish direct connections.
Gateway Keeps Restarting
Symptom: Container restarts repeatedly, logs show token or authentication errors.
Fix: Regenerate the gateway token in the admin portal. Tokens can be invalidated if you delete and recreate the Site, or if the token was generated for a different Site.
Resource Requirements
- RAM: ~50-128 MB per gateway depending on the number of connected clients
- CPU: Low — WireGuard is efficient. A single core handles hundreds of clients.
- Disk: <100 MB for the gateway itself
- Network: Outbound HTTPS to
api.firezone.dev. WireGuard traffic on UDP (port negotiated dynamically via control plane).
Verdict
Firezone occupies a unique niche: it brings enterprise-grade zero-trust access to self-hosters, but with a trade-off — the control plane is cloud-hosted. You can’t run the admin portal on your own server.
Choose Firezone if: You want granular, policy-based access control (specific users can access specific resources), built-in SSO/identity provider integration, and multi-site gateway management. It’s the best option for teams and organizations where access policies matter more than full infrastructure ownership.
Look elsewhere if: You want a fully self-hosted VPN with zero cloud dependencies. wg-easy gives you a simple WireGuard server with a web UI. Headscale gives you a self-hosted Tailscale control plane. NetBird offers a fully self-hostable zero-trust platform including the control plane.
For most home lab users who just need remote access to their services, Tailscale or wg-easy are simpler choices. Firezone shines when you need real access policies.
Frequently Asked Questions
Is Firezone fully self-hostable?
No. As of Firezone 1.x, the admin portal and control plane are cloud-managed services. You self-host the Gateways (the data plane). The source code is open and you can technically build the entire stack yourself, but it’s not officially supported for production self-hosting. If you need full self-hosting, look at NetBird or Headscale.
Is there a free tier?
Yes. Firezone offers a free tier that includes up to 6 users and basic features. Check firezone.dev/pricing for current limits.
How does Firezone compare to a traditional VPN?
Traditional VPNs grant full network access once connected. Firezone uses zero-trust principles — each resource requires explicit policy authorization. Traffic flows peer-to-peer and is encrypted end-to-end. There’s no central chokepoint like a traditional VPN gateway.
Can I use Firezone alongside other VPN solutions?
Yes. Firezone Gateways are isolated — they create their own WireGuard interfaces and don’t interfere with existing VPN setups. You can run Firezone alongside WireGuard or Tailscale on the same host.
What happens if Firezone’s cloud goes down?
Existing tunnels continue to work — the data plane is peer-to-peer. However, new connections and policy changes won’t propagate until the control plane is back. This is the inherent risk of the split architecture.
Related
Get self-hosting tips in your inbox
New guides, comparisons, and setup tutorials — delivered weekly. No spam.