Firezone WireGuard VPN
Self-hosted WireGuard VPN server with web UI for managing users and devices.
Overview
Firezone is a modern, open-source WireGuard VPN server that provides enterprise-grade remote access capabilities through an intuitive web interface. Built on the WireGuard protocol, Firezone offers superior performance and security compared to traditional VPN solutions like OpenVPN, while maintaining the simplicity and reliability that makes WireGuard the gold standard for modern VPN implementations. The platform focuses on zero-trust network access principles, allowing organizations to provide secure remote connectivity without the complexity of traditional VPN infrastructure.
This deployment creates a complete VPN infrastructure using three specialized services: the Firezone application server handles user management and WireGuard configuration generation, a dedicated PostgreSQL database stores user accounts and device configurations, and Caddy provides automatic HTTPS termination with Let's Encrypt certificates. The Firezone container runs with elevated network privileges (NET_ADMIN and SYS_MODULE capabilities) to manage WireGuard tunnels and IP forwarding, while the entire stack operates on an isolated Docker network for enhanced security.
This configuration is ideal for organizations seeking a self-hosted VPN solution that combines the performance benefits of WireGuard with enterprise management features. Unlike simple WireGuard deployments that require manual key management, this stack provides automated user provisioning, device management, and centralized policy control through a modern web interface, making it suitable for teams that need scalable remote access without vendor lock-in.
Key Features
- WireGuard protocol implementation with automatic key generation and distribution for optimal VPN performance
- Web-based administration interface for managing users, devices, and network policies without command-line complexity
- OIDC/SAML single sign-on integration for enterprise authentication systems and identity providers
- Automatic HTTPS certificate provisioning through Caddy with Let's Encrypt integration
- PostgreSQL-backed user and device management with full ACID compliance for data integrity
- Network policy enforcement with subnet routing and DNS configuration per user or group
- Real-time connection monitoring and logging with detailed client status and bandwidth usage
- Multi-platform client support with automatic configuration file generation for Windows, macOS, iOS, and Android
Common Use Cases
- 1Remote workforce enablement for companies transitioning to hybrid work models requiring secure corporate network access
- 2Homelab enthusiasts seeking professional-grade VPN capabilities with web management for family device access
- 3Development teams needing secure access to staging environments and internal services across distributed locations
- 4Small to medium businesses replacing expensive commercial VPN solutions with self-hosted infrastructure
- 5Educational institutions providing secure network access for students and faculty across campus and remote locations
- 6Consultants and contractors requiring isolated client network access with professional management capabilities
- 7Organizations with compliance requirements needing full control over VPN infrastructure and audit logs
Prerequisites
- Docker host with minimum 1GB RAM for PostgreSQL and Firezone application components
- Public IP address or dynamic DNS configuration for external client connectivity
- Domain name with DNS control for automatic HTTPS certificate generation via Let's Encrypt
- UDP port 51820 accessible from the internet for WireGuard protocol traffic
- Basic understanding of network routing and firewall configuration for subnet management
- Administrative access to configure ip_forward and network sysctls on the Docker host
For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms
docker-compose.yml
docker-compose.yml
1services: 2 firezone: 3 image: firezone/firezone:latest4 container_name: firezone5 cap_add: 6 - NET_ADMIN7 - SYS_MODULE8 environment: 9 - DEFAULT_ADMIN_EMAIL=${ADMIN_EMAIL}10 - DEFAULT_ADMIN_PASSWORD=${ADMIN_PASSWORD}11 - EXTERNAL_URL=${EXTERNAL_URL}12 - DATABASE_HOST=db13 - DATABASE_NAME=firezone14 - DATABASE_USER=firezone15 - DATABASE_PASSWORD=${DB_PASSWORD}16 - SECRET_KEY_BASE=${SECRET_KEY}17 - LIVE_VIEW_SIGNING_SALT=${SIGNING_SALT}18 - COOKIE_SIGNING_SALT=${COOKIE_SALT}19 - COOKIE_ENCRYPTION_SALT=${ENCRYPTION_SALT}20 - WIREGUARD_IPV4_ENABLED=true21 - WIREGUARD_IPV4_NETWORK=10.3.2.0/2422 - WIREGUARD_IPV4_ADDRESS=10.3.2.123 volumes: 24 - firezone-data:/var/firezone25 ports: 26 - "51820:51820/udp"27 sysctls: 28 - net.ipv4.ip_forward=129 - net.ipv4.conf.all.src_valid_mark=130 depends_on: 31 - db32 networks: 33 - firezone-network34 restart: unless-stopped3536 db: 37 image: postgres:15-alpine38 container_name: firezone-db39 environment: 40 - POSTGRES_USER=firezone41 - POSTGRES_PASSWORD=${DB_PASSWORD}42 - POSTGRES_DB=firezone43 volumes: 44 - postgres-data:/var/lib/postgresql/data45 networks: 46 - firezone-network47 restart: unless-stopped4849 caddy: 50 image: caddy:alpine51 container_name: firezone-caddy52 ports: 53 - "80:80"54 - "443:443"55 volumes: 56 - ./Caddyfile:/etc/caddy/Caddyfile:ro57 - caddy-data:/data58 - caddy-config:/config59 depends_on: 60 - firezone61 networks: 62 - firezone-network63 restart: unless-stopped6465volumes: 66 firezone-data: 67 postgres-data: 68 caddy-data: 69 caddy-config: 7071networks: 72 firezone-network: 73 driver: bridge.env Template
.env
1# Firezone VPN2ADMIN_EMAIL=admin@example.com3ADMIN_PASSWORD=secure_admin_password4EXTERNAL_URL=https://vpn.example.com5DB_PASSWORD=secure_db_password67# Generate these with: openssl rand -base64 328SECRET_KEY=your_64_char_secret_key9SIGNING_SALT=your_signing_salt10COOKIE_SALT=your_cookie_salt11ENCRYPTION_SALT=your_encryption_saltUsage Notes
- 1Web UI at https://localhost
- 2WireGuard on UDP port 51820
- 3Add users and devices via web UI
- 4Download WireGuard configs for clients
- 5Supports SSO with OIDC providers
Individual Services(3 services)
Copy individual services to mix and match with your existing compose files.
firezone
firezone:
image: firezone/firezone:latest
container_name: firezone
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- DEFAULT_ADMIN_EMAIL=${ADMIN_EMAIL}
- DEFAULT_ADMIN_PASSWORD=${ADMIN_PASSWORD}
- EXTERNAL_URL=${EXTERNAL_URL}
- DATABASE_HOST=db
- DATABASE_NAME=firezone
- DATABASE_USER=firezone
- DATABASE_PASSWORD=${DB_PASSWORD}
- SECRET_KEY_BASE=${SECRET_KEY}
- LIVE_VIEW_SIGNING_SALT=${SIGNING_SALT}
- COOKIE_SIGNING_SALT=${COOKIE_SALT}
- COOKIE_ENCRYPTION_SALT=${ENCRYPTION_SALT}
- WIREGUARD_IPV4_ENABLED=true
- WIREGUARD_IPV4_NETWORK=10.3.2.0/24
- WIREGUARD_IPV4_ADDRESS=10.3.2.1
volumes:
- firezone-data:/var/firezone
ports:
- 51820:51820/udp
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
depends_on:
- db
networks:
- firezone-network
restart: unless-stopped
db
db:
image: postgres:15-alpine
container_name: firezone-db
environment:
- POSTGRES_USER=firezone
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=firezone
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- firezone-network
restart: unless-stopped
caddy
caddy:
image: caddy:alpine
container_name: firezone-caddy
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
depends_on:
- firezone
networks:
- firezone-network
restart: unless-stopped
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 firezone:5 image: firezone/firezone:latest6 container_name: firezone7 cap_add:8 - NET_ADMIN9 - SYS_MODULE10 environment:11 - DEFAULT_ADMIN_EMAIL=${ADMIN_EMAIL}12 - DEFAULT_ADMIN_PASSWORD=${ADMIN_PASSWORD}13 - EXTERNAL_URL=${EXTERNAL_URL}14 - DATABASE_HOST=db15 - DATABASE_NAME=firezone16 - DATABASE_USER=firezone17 - DATABASE_PASSWORD=${DB_PASSWORD}18 - SECRET_KEY_BASE=${SECRET_KEY}19 - LIVE_VIEW_SIGNING_SALT=${SIGNING_SALT}20 - COOKIE_SIGNING_SALT=${COOKIE_SALT}21 - COOKIE_ENCRYPTION_SALT=${ENCRYPTION_SALT}22 - WIREGUARD_IPV4_ENABLED=true23 - WIREGUARD_IPV4_NETWORK=10.3.2.0/2424 - WIREGUARD_IPV4_ADDRESS=10.3.2.125 volumes:26 - firezone-data:/var/firezone27 ports:28 - "51820:51820/udp"29 sysctls:30 - net.ipv4.ip_forward=131 - net.ipv4.conf.all.src_valid_mark=132 depends_on:33 - db34 networks:35 - firezone-network36 restart: unless-stopped3738 db:39 image: postgres:15-alpine40 container_name: firezone-db41 environment:42 - POSTGRES_USER=firezone43 - POSTGRES_PASSWORD=${DB_PASSWORD}44 - POSTGRES_DB=firezone45 volumes:46 - postgres-data:/var/lib/postgresql/data47 networks:48 - firezone-network49 restart: unless-stopped5051 caddy:52 image: caddy:alpine53 container_name: firezone-caddy54 ports:55 - "80:80"56 - "443:443"57 volumes:58 - ./Caddyfile:/etc/caddy/Caddyfile:ro59 - caddy-data:/data60 - caddy-config:/config61 depends_on:62 - firezone63 networks:64 - firezone-network65 restart: unless-stopped6667volumes:68 firezone-data:69 postgres-data:70 caddy-data:71 caddy-config:7273networks:74 firezone-network:75 driver: bridge76EOF7778# 2. Create the .env file79cat > .env << 'EOF'80# Firezone VPN81ADMIN_EMAIL=admin@example.com82ADMIN_PASSWORD=secure_admin_password83EXTERNAL_URL=https://vpn.example.com84DB_PASSWORD=secure_db_password8586# Generate these with: openssl rand -base64 3287SECRET_KEY=your_64_char_secret_key88SIGNING_SALT=your_signing_salt89COOKIE_SALT=your_cookie_salt90ENCRYPTION_SALT=your_encryption_salt91EOF9293# 3. Start the services94docker compose up -d9596# 4. View logs97docker compose logs -fOne-Liner
Run this command to download and set up the recipe in one step:
terminal
1curl -fsSL https://docker.recipes/api/recipes/firezone-vpn/run | bashTroubleshooting
- Clients cannot connect to VPN: Verify UDP port 51820 is open in firewall and router port forwarding is configured correctly
- Web UI shows database connection errors: Check that db container is healthy and DB_PASSWORD environment variable matches between firezone and db services
- HTTPS certificate generation fails: Ensure domain DNS points to server IP and ports 80/443 are accessible for Let's Encrypt validation
- WireGuard tunnel establishes but no internet access: Verify net.ipv4.ip_forward=1 sysctl is applied and Docker host IP forwarding is enabled
- firezone container fails to start with capability errors: Ensure Docker daemon has privileges to grant NET_ADMIN and SYS_MODULE capabilities to containers
- Configuration changes not persisting: Check that firezone-data volume is properly mounted and has correct permissions for the container user
Community Notes
Loading...
Loading notes...
Download Recipe Kit
Get all files in a ready-to-deploy package
Includes docker-compose.yml, .env template, README, and license
Components
firezonepostgresqlcaddy
Tags
#vpn#wireguard#firezone#security#self-hosted
Category
Security & NetworkingAd Space
Shortcuts: C CopyF FavoriteD Download