Deploying Firezone
Introduction
Firezone is a modern, self-hosted WireGuard-based VPN server and secure remote access platform designed for simplicity, security, and scalability. Built on the WireGuard protocol, Firezone provides lightning-fast, secure tunneling with an intuitive web interface for user management, device provisioning, and access control. Unlike traditional VPN solutions, Firezone leverages WireGuard’s cutting-edge cryptography and minimal attack surface to deliver enterprise-grade security with exceptional performance and ease of use.
Firezone delivers comprehensive secure remote access capabilities:
- WireGuard-Based: Built on the modern, high-performance WireGuard protocol
- Web Management Portal: Intuitive dashboard for users, devices, and access control
- Multi-Platform Support: Native clients for Linux, macOS, Windows, iOS, and Android
- Single Sign-On: SAML 2.0 and OpenID Connect integration with popular identity providers
- Split Tunneling: Granular control over which traffic routes through the VPN
- Device Management: Track and manage all connected devices from a central dashboard
- Access Policies: Fine-grained access control based on users, groups, and networks
- Multi-Tenancy: Support for multiple organizations with isolated configurations
- Zero Trust Architecture: Authenticate and authorize every connection
- Audit Logging: Comprehensive logging of authentication and connection events
- REST API: Automate device provisioning and user management
- IPv4 and IPv6 Support: Full dual-stack networking capabilities
- NAT Traversal: Seamless connectivity behind NAT and firewalls
- Automatic Key Rotation: Enhanced security with periodic key updates
- Session Recording: Optional connection logging for compliance requirements
Whether you’re securing remote workers, connecting distributed offices, implementing zero trust networking, or providing secure access to cloud resources, Firezone combines WireGuard’s performance with enterprise management features.
This comprehensive guide walks you through deploying Firezone on Klutch.sh using Docker, including PostgreSQL database setup, WireGuard configuration, user management, SSO integration, client deployment, and production best practices.
Why Deploy Firezone on Klutch.sh?
Klutch.sh provides the perfect infrastructure for hosting Firezone VPN servers:
- Persistent Storage: PostgreSQL database with automatic backups and durability
- Automatic HTTPS: Secure web portal with TLS certificate management
- Port Management: Simple TCP/HTTP traffic configuration for VPN and web services
- Environment Variables: Secure storage for database credentials and secrets
- Zero Downtime Deployments: Rolling updates without service interruption
- Resource Scaling: Scale compute and storage as your VPN usage grows
- Built-in Monitoring: Track application health and performance metrics
- Custom Domains: Professional URLs for your VPN portal
- Infrastructure Automation: Simplified deployment without manual server management
Prerequisites
Before you begin, ensure you have the following:
- A Klutch.sh account
- A GitHub account with a repository for your project
- Docker installed locally for testing (optional but recommended)
- Basic understanding of VPN concepts and WireGuard protocol
- Access to a PostgreSQL database (deploy separately on Klutch.sh - see PostgreSQL guide)
- Email server (SMTP) credentials for user invitations and notifications
- Domain name for your Firezone portal (optional but recommended for production)
Architecture Overview
Firezone requires several components working together:
- Firezone Server: The main VPN server and web portal (Elixir/Phoenix application)
- PostgreSQL Database: Stores user accounts, devices, configurations, and audit logs
- WireGuard Kernel Module: Handles VPN tunneling at the kernel level
- SMTP Server: Sends user invitations and notification emails
Deployment Strategy: Deploy components as separate apps on Klutch.sh:
- PostgreSQL database with persistent volume (see PostgreSQL guide)
- Firezone server with WireGuard support (this guide)
Port Requirements:
- Web Portal: HTTP/HTTPS on port 443 (managed by Klutch.sh)
- WireGuard VPN: UDP port 51820 (requires TCP traffic configuration)
Installation and Setup
Step 1: Create Your Project Directory
First, create a new directory for your Firezone deployment:
mkdir firezone-klutchcd firezone-klutchgit initStep 2: Create the Dockerfile
Create a Dockerfile in your project root. Firezone requires WireGuard support and PostgreSQL connectivity:
Basic Dockerfile (Development):
FROM firezone/firezone:latest
# Firezone uses port 13000 for web interface by defaultEXPOSE 13000
# WireGuard portEXPOSE 51820/udp
# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:13000/health || exit 1Production Dockerfile (Multi-Stage with Custom Configuration):
FROM firezone/firezone:latest
# Install additional tools for monitoring and debuggingRUN apk add --no-cache \ curl \ postgresql-client \ wireguard-tools \ iptables \ ip6tables
# Create non-root user for securityRUN addgroup -g 1000 firezone && \ adduser -D -u 1000 -G firezone firezone
# Create necessary directoriesRUN mkdir -p /var/firezone /var/log/firezone && \ chown -R firezone:firezone /var/firezone /var/log/firezone
# Set working directoryWORKDIR /var/firezone
# Copy startup scriptCOPY --chown=firezone:firezone scripts/entrypoint.sh /usr/local/bin/RUN chmod +x /usr/local/bin/entrypoint.sh
# Expose portsEXPOSE 13000 51820/udp
# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f http://localhost:13000/health || exit 1
# Switch to non-root userUSER firezone
# Start FirezoneENTRYPOINT ["/usr/local/bin/entrypoint.sh"]CMD ["start"]Step 3: Create Startup Script (for Production Dockerfile)
Create scripts/entrypoint.sh:
#!/bin/shset -e
# Wait for PostgreSQL to be readyecho "Waiting for PostgreSQL..."until pg_isready -h "$DATABASE_HOST" -U "$DATABASE_USER"; do echo "PostgreSQL is unavailable - sleeping" sleep 2doneecho "PostgreSQL is ready!"
# Run database migrationsecho "Running database migrations..."/app/bin/firezone eval "Firezone.Release.migrate()"
# Start Firezoneecho "Starting Firezone..."exec /app/bin/firezone "$@"Make it executable:
chmod +x scripts/entrypoint.shStep 4: Create Environment Configuration File
Create a .env.example file documenting all configuration options:
# Firezone Core ConfigurationEXTERNAL_URL=https://vpn.yourdomain.comDEFAULT_ADMIN_EMAIL=admin@yourdomain.comDEFAULT_ADMIN_PASSWORD=changeme_secure_password
# Database Configuration (PostgreSQL)DATABASE_HOST=postgres-app.klutch.shDATABASE_PORT=8000DATABASE_NAME=firezoneDATABASE_USER=firezoneDATABASE_PASSWORD=your_secure_db_passwordDATABASE_POOL_SIZE=10DATABASE_SSL=false
# Secret Key Base (generate with: openssl rand -base64 32)SECRET_KEY_BASE=your_64_character_secret_key_here
# Live View Signing Salt (generate with: openssl rand -base64 32)LIVE_VIEW_SIGNING_SALT=your_32_character_salt_here
# Guardian Secret Key (generate with: openssl rand -base64 32)GUARDIAN_SECRET_KEY=your_32_character_guardian_key_here
# WireGuard ConfigurationWIREGUARD_ENDPOINT=vpn.yourdomain.comWIREGUARD_PORT=51820WIREGUARD_IPV4_ENABLED=trueWIREGUARD_IPV4_NETWORK=10.3.2.0/24WIREGUARD_IPV4_ADDRESS=10.3.2.1WIREGUARD_IPV6_ENABLED=falseWIREGUARD_PERSISTENT_KEEPALIVE=25WIREGUARD_DNS=1.1.1.1,1.0.0.1WIREGUARD_ALLOWED_IPS=0.0.0.0/0WIREGUARD_MTU=1280
# Application SettingsPHOENIX_HTTP_PORT=13000PHOENIX_EXTERNAL_TRUSTED_PROXIES=["10.0.0.0/8"]MAX_DEVICES_PER_USER=10ALLOW_UNPRIVILEGED_DEVICE_MANAGEMENT=trueALLOW_UNPRIVILEGED_DEVICE_CONFIGURATION=trueAUTO_CREATE_OIDC_USERS=true
# Email Configuration (SMTP)OUTBOUND_EMAIL_FROM=noreply@yourdomain.comOUTBOUND_EMAIL_ADAPTER=Swoosh.Adapters.SMTPOUTBOUND_EMAIL_ADAPTER_OPTS_RELAY=smtp.gmail.comOUTBOUND_EMAIL_ADAPTER_OPTS_PORT=587OUTBOUND_EMAIL_ADAPTER_OPTS_USERNAME=your-email@gmail.comOUTBOUND_EMAIL_ADAPTER_OPTS_PASSWORD=your-app-passwordOUTBOUND_EMAIL_ADAPTER_OPTS_TLS=alwaysOUTBOUND_EMAIL_ADAPTER_OPTS_AUTH=always
# Session ConfigurationSESSION_TTL_HOURS=720DEVICE_TTL_HOURS=8760
# Security SettingsSECURE_COOKIES=trueSIGN_OUT_ON_SESSION_EXPIRE=falseRATE_LIMIT_ENABLED=trueRATE_LIMIT_MAX_REQUESTS=10RATE_LIMIT_WINDOW_SECONDS=60
# Telemetry and LoggingTELEMETRY_ENABLED=trueLOG_LEVEL=infoENABLE_PROMETHEUS_METRICS=true
# SAML SSO Configuration (Optional)SAML_ENTITY_ID=https://vpn.yourdomain.comSAML_KEYFILE_PATH=/var/firezone/saml/key.pemSAML_CERTFILE_PATH=/var/firezone/saml/cert.pem
# OIDC Configuration (Optional)OIDC_DISCOVERY_DOCUMENT_URI=https://accounts.google.com/.well-known/openid-configurationOIDC_CLIENT_ID=your-oidc-client-idOIDC_CLIENT_SECRET=your-oidc-client-secretOIDC_REDIRECT_URI=https://vpn.yourdomain.com/auth/oidc/callbackOIDC_RESPONSE_TYPE=codeOIDC_SCOPE=openid email profile
# Advanced NetworkingENABLE_IPV6=falseENABLE_MASQUERADE=trueENABLE_PORT_FORWARDING=true
# Backup and MaintenanceDATABASE_BACKUP_ENABLED=trueDATABASE_BACKUP_SCHEDULE="0 2 * * *"Step 5: Create README Documentation
Create a README.md file:
# Firezone VPN on Klutch.sh
Self-hosted WireGuard-based VPN server with web management portal.
## Features
- WireGuard VPN protocol- Web-based user and device management- SAML 2.0 and OpenID Connect SSO- Split tunneling support- Multi-platform clients- Audit logging and session tracking
## Prerequisites
- PostgreSQL database (deployed separately)- SMTP server for email notifications- Domain name (recommended)
## Deployment
1. Deploy PostgreSQL on Klutch.sh first2. Update `.env` with your database credentials3. Generate secret keys: ```bash openssl rand -base64 48- Push to GitHub
- Deploy on Klutch.sh:
- Set traffic type to HTTP
- Internal port: 13000
- Configure environment variables
- Attach persistent volume at
/var/firezone
Initial Setup
- Access web portal at your deployed URL
- Login with DEFAULT_ADMIN_EMAIL and DEFAULT_ADMIN_PASSWORD
- Change admin password immediately
- Configure WireGuard settings
- Create users and generate device configurations
Client Setup
Linux
sudo apt install wireguard# Download config from Firezone portalsudo wg-quick up wg0macOS
- Install WireGuard from App Store
- Import config from Firezone portal
- Activate tunnel
Windows
- Download WireGuard client
- Import config file
- Activate tunnel
iOS/Android
- Install WireGuard app
- Scan QR code from Firezone portal
- Activate tunnel
Documentation
- Official Docs: https://docs.firezone.dev
- WireGuard: https://www.wireguard.com
- PostgreSQL Guide: /guides/databases/postgres
### Step 6: Create PostgreSQL Database Schema
While Firezone handles migrations automatically, document the required database setup:
Create `docs/database-setup.md`:
```markdown# PostgreSQL Database Setup for Firezone
## Create Database and User
Connect to your PostgreSQL instance:
```sql-- Create database userCREATE USER firezone WITH PASSWORD 'your_secure_password';
-- Create databaseCREATE DATABASE firezone OWNER firezone;
-- Grant privilegesGRANT ALL PRIVILEGES ON DATABASE firezone TO firezone;
-- Connect to firezone database\c firezone
-- Grant schema privilegesGRANT ALL ON SCHEMA public TO firezone;Verify Connection
Test connection from your local machine:
psql -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone -c "SELECT version();"Migrations
Firezone automatically runs migrations on startup. The following tables will be created:
users- User accountsdevices- VPN devices and configurationsrules- Access control rulessites- Multi-tenant site configurationssettings- Application settingsaudit_logs- Authentication and connection logssessions- Active user sessionssaml_identity_providers- SAML SSO configurationsoidc_providers- OpenID Connect configurations
Backup Recommendations
# Full database backuppg_dump -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone > firezone_backup.sql
# Restore from backuppsql -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone < firezone_backup.sql### Step 7: Test Locally with Docker Compose (Optional)
Create `docker-compose.yml` for local testing:
```yamlversion: '3.8'
services: postgres: image: postgres:15-alpine environment: POSTGRES_DB: firezone POSTGRES_USER: firezone POSTGRES_PASSWORD: firezone_local_pass volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U firezone"] interval: 10s timeout: 5s retries: 5
firezone: build: . depends_on: postgres: condition: service_healthy environment: EXTERNAL_URL: http://localhost:13000 DEFAULT_ADMIN_EMAIL: admin@localhost DEFAULT_ADMIN_PASSWORD: adminpass123 DATABASE_HOST: postgres DATABASE_PORT: 5432 DATABASE_NAME: firezone DATABASE_USER: firezone DATABASE_PASSWORD: firezone_local_pass SECRET_KEY_BASE: local_dev_secret_key_base_replace_in_production LIVE_VIEW_SIGNING_SALT: local_signing_salt GUARDIAN_SECRET_KEY: local_guardian_key WIREGUARD_ENDPOINT: localhost WIREGUARD_PORT: 51820 WIREGUARD_IPV4_NETWORK: 10.3.2.0/24 WIREGUARD_IPV4_ADDRESS: 10.3.2.1 PHOENIX_HTTP_PORT: 13000 LOG_LEVEL: debug ports: - "13000:13000" - "51820:51820/udp" cap_add: - NET_ADMIN - SYS_MODULE sysctls: - net.ipv4.ip_forward=1 - net.ipv6.conf.all.forwarding=1 volumes: - firezone_data:/var/firezone
volumes: postgres_data: firezone_data:Test locally:
docker-compose up -ddocker-compose logs -f# Access at http://localhost:13000Step 8: Initialize Git Repository
# Create .gitignorecat > .gitignore << 'EOF'.env.env.local*.lognode_modules/.DS_Storedocker-compose.override.yml*.sqlbackups/EOF
# Initialize repositorygit add .git commit -m "Initial Firezone deployment setup"
# Add GitHub remotegit remote add origin https://github.com/yourusername/firezone-klutch.gitgit branch -M maingit push -u origin mainDeploying on Klutch.sh
-
### Deploy PostgreSQL First
Before deploying Firezone, set up PostgreSQL:- Follow the [PostgreSQL deployment guide](/guides/databases/postgres)- Create the `firezone` database and user- Note the connection details (host, port, credentials)- Ensure TCP traffic is configured on port 8000
-
### Log in to Klutch.sh
Navigate to <a href="https://klutch.sh/app" target="_blank" rel="noopener noreferrer">klutch.sh/app</a> and log in to your account.
-
### Create a New Project
- Click **"New Project"**- Enter a project name: **"Firezone VPN"**- Click **"Create Project"**
-
### Create New App
- Inside your project, click **"New App"**- Enter app name: **"firezone-vpn"** (or your preferred name)- Click **"Create App"**
-
### Connect GitHub Repository
- Click **"Connect Repository"**- Select your GitHub account- Choose the repository you created earlier- Select the **main** branch- Click **"Connect"**
-
### Configure Network Settings
Set traffic type and port:- Select traffic type: **HTTP**- Set internal port: **13000** (Firezone default web portal port)- Klutch.sh will automatically handle HTTPS and certificate management
-
### Set Environment Variables
In the Klutch.sh dashboard, add the following environment variables (update with your values):**Core Configuration**:```bashEXTERNAL_URL=https://example-app.klutch.shDEFAULT_ADMIN_EMAIL=admin@yourdomain.comDEFAULT_ADMIN_PASSWORD=your_secure_admin_password```**Database Configuration**:```bashDATABASE_HOST=your-postgres-app.klutch.shDATABASE_PORT=8000DATABASE_NAME=firezoneDATABASE_USER=firezoneDATABASE_PASSWORD=your_secure_db_passwordDATABASE_POOL_SIZE=10```**Secret Keys** (generate with `openssl rand -base64 48`):```bashSECRET_KEY_BASE=your_generated_secret_key_baseLIVE_VIEW_SIGNING_SALT=your_generated_signing_saltGUARDIAN_SECRET_KEY=your_generated_guardian_key```**WireGuard Configuration**:```bashWIREGUARD_ENDPOINT=example-app.klutch.shWIREGUARD_PORT=51820WIREGUARD_IPV4_ENABLED=trueWIREGUARD_IPV4_NETWORK=10.3.2.0/24WIREGUARD_IPV4_ADDRESS=10.3.2.1WIREGUARD_DNS=1.1.1.1,1.0.0.1WIREGUARD_MTU=1280```**Email Configuration** (SMTP):```bashOUTBOUND_EMAIL_FROM=noreply@yourdomain.comOUTBOUND_EMAIL_ADAPTER=Swoosh.Adapters.SMTPOUTBOUND_EMAIL_ADAPTER_OPTS_RELAY=smtp.gmail.comOUTBOUND_EMAIL_ADAPTER_OPTS_PORT=587OUTBOUND_EMAIL_ADAPTER_OPTS_USERNAME=your-email@gmail.comOUTBOUND_EMAIL_ADAPTER_OPTS_PASSWORD=your-app-passwordOUTBOUND_EMAIL_ADAPTER_OPTS_TLS=always```**Security Settings**:```bashPHOENIX_HTTP_PORT=13000SECURE_COOKIES=trueRATE_LIMIT_ENABLED=trueLOG_LEVEL=infoTELEMETRY_ENABLED=true```
-
### Attach Persistent Volume
For storing Firezone data and logs:- Click **"Add Volume"**- Mount path: `/var/firezone`- Recommended size: **10GB** (for configurations, logs, and certificates)
-
### Deploy the Application
- Click **"Deploy"**- Klutch.sh will:- Detect your Dockerfile automatically- Build the Docker image- Deploy the container- Configure networking and storage- Monitor deployment logs for any errors
-
### Verify Deployment
Once deployed:- Access the web portal at your app URL (e.g., `https://example-app.klutch.sh`)- You should see the Firezone login page- Check deployment logs for successful database connection- Verify health check endpoint: `/health`
Post-Deployment Configuration
Step 1: Initial Admin Login
- Navigate to your Firezone URL
- Login with the admin credentials you set: - Email: Value from `DEFAULT_ADMIN_EMAIL` - Password: Value from `DEFAULT_ADMIN_PASSWORD`
- You'll be prompted to change your password immediately
- Set a strong new admin password and save
Step 2: Configure WireGuard Settings
- Navigate to **Settings → General**
- Verify WireGuard endpoint is correct (your domain or Klutch.sh URL)
- Confirm IPv4 network range doesn't conflict with existing networks
- Set DNS servers for VPN clients (e.g., `1.1.1.1, 1.0.0.1`)
- Configure split tunneling if needed
- Save settings
Step 3: Create Users
- Navigate to **Users** in the sidebar
- Click **"Add User"**
- Enter user details: - Email address - Role (Admin or User)
- User will receive an invitation email
- Repeat for all users needing VPN access
Step 4: Generate Device Configurations
- Login as a user (or admin)
- Navigate to **Devices**
- Click **"Add Device"**
- Enter device details: - Device name (e.g., "John's MacBook") - Description (optional)
- Click **"Generate Configuration"**
- Download configuration file or scan QR code
Step 5: Configure SSO (Optional)
For SAML 2.0 or OpenID Connect integration:
- Navigate to **Settings → SSO**
- Choose SSO method (SAML or OIDC)
- Enter provider details: - For Google: Use OAuth 2.0 client credentials - For Okta: Configure SAML app integration - For Azure AD: Use OpenID Connect
- Configure callback URLs
- Test SSO login
- Enable auto-user creation if desired
Client Setup and Connection
Linux Client Setup
# Install WireGuardsudo apt updatesudo apt install wireguard -y
# Download config from Firezone portal# Save as /etc/wireguard/wg0.conf
# Start VPN tunnelsudo wg-quick up wg0
# Enable on bootsudo systemctl enable wg-quick@wg0
# Check connection statussudo wg show
# Stop tunnelsudo wg-quick down wg0macOS Client Setup
# Install via Homebrewbrew install wireguard-tools
# Or download WireGuard app from App Store# Download config from Firezone portal# Import into WireGuard app# Activate tunnelUsing WireGuard App:
- Download WireGuard from App Store
- Open WireGuard app
- Click “Import tunnel(s) from file”
- Select downloaded config file
- Click “Activate” to connect
Windows Client Setup
- Download WireGuard for Windows
- Install and launch WireGuard
- Click “Import tunnel(s) from file”
- Select downloaded config file from Firezone
- Click “Activate” to connect
- Check system tray icon for connection status
iOS Client Setup
- Install WireGuard from App Store
- Open Firezone portal on your phone
- Navigate to Devices → Add Device
- Scan QR code with WireGuard app
- Name the tunnel
- Toggle switch to activate
Android Client Setup
- Install WireGuard from Play Store
- Open Firezone portal on your phone
- Navigate to Devices → Add Device
- Scan QR code with WireGuard app
- Name the tunnel
- Toggle switch to activate
Verifying Connection
Once connected, verify VPN is working:
# Check assigned VPN IPip addr show wg0 # Linux/macOSipconfig /all # Windows
# Test connectivityping 10.3.2.1 # VPN gateway
# Check public IP (should show VPN exit IP)curl ifconfig.me
# DNS testnslookup google.comIntegration Examples
API Integration (Python)
import requestsimport json
class FirezoneAPI: def __init__(self, api_url, api_token): """ Initialize Firezone API client
Args: api_url: Firezone server URL (e.g., https://vpn.example.com) api_token: API token from Firezone admin panel """ self.api_url = api_url.rstrip('/') self.api_token = api_token self.headers = { 'Authorization': f'Bearer {api_token}', 'Content-Type': 'application/json' }
def list_users(self): """List all users""" response = requests.get( f'{self.api_url}/api/users', headers=self.headers ) response.raise_for_status() return response.json()
def create_user(self, email, role='user'): """ Create a new user
Args: email: User email address role: User role ('user' or 'admin') """ data = { 'email': email, 'role': role } response = requests.post( f'{self.api_url}/api/users', headers=self.headers, json=data ) response.raise_for_status() return response.json()
def delete_user(self, user_id): """Delete a user by ID""" response = requests.delete( f'{self.api_url}/api/users/{user_id}', headers=self.headers ) response.raise_for_status() return True
def list_devices(self, user_id=None): """ List devices
Args: user_id: Filter by user ID (optional) """ url = f'{self.api_url}/api/devices' if user_id: url += f'?user_id={user_id}'
response = requests.get(url, headers=self.headers) response.raise_for_status() return response.json()
def create_device(self, user_id, name, description=''): """ Create a new device for a user
Args: user_id: User ID name: Device name description: Device description (optional) """ data = { 'user_id': user_id, 'name': name, 'description': description } response = requests.post( f'{self.api_url}/api/devices', headers=self.headers, json=data ) response.raise_for_status() return response.json()
def revoke_device(self, device_id): """Revoke a device by ID""" response = requests.delete( f'{self.api_url}/api/devices/{device_id}', headers=self.headers ) response.raise_for_status() return True
def get_audit_logs(self, limit=100, offset=0): """ Retrieve audit logs
Args: limit: Number of records to return offset: Pagination offset """ response = requests.get( f'{self.api_url}/api/audit_logs', headers=self.headers, params={'limit': limit, 'offset': offset} ) response.raise_for_status() return response.json()
# Usage exampleif __name__ == '__main__': # Initialize API client api = FirezoneAPI( api_url='https://vpn.example.com', api_token='your_api_token_here' )
# List all users users = api.list_users() print(f'Total users: {len(users)}')
# Create new user new_user = api.create_user( email='newuser@example.com', role='user' ) print(f'Created user: {new_user["email"]}')
# Create device for user device = api.create_device( user_id=new_user['id'], name='Work Laptop', description='MacBook Pro 2023' ) print(f'Created device: {device["name"]}')
# List user's devices devices = api.list_devices(user_id=new_user['id']) print(f'User has {len(devices)} device(s)')
# Get audit logs logs = api.get_audit_logs(limit=50) print(f'Retrieved {len(logs)} audit log entries')Automated User Provisioning (Node.js)
const axios = require('axios');
class FirezoneClient { constructor(apiUrl, apiToken) { this.apiUrl = apiUrl.replace(/\/$/, ''); this.apiToken = apiToken; this.client = axios.create({ baseURL: this.apiUrl, headers: { 'Authorization': `Bearer ${apiToken}`, 'Content-Type': 'application/json' } }); }
async createUser(email, role = 'user') { try { const response = await this.client.post('/api/users', { email, role }); return response.data; } catch (error) { throw new Error(`Failed to create user: ${error.message}`); } }
async createDevice(userId, name, description = '') { try { const response = await this.client.post('/api/devices', { user_id: userId, name, description }); return response.data; } catch (error) { throw new Error(`Failed to create device: ${error.message}`); } }
async provisionUser(email, deviceName, role = 'user') { // Create user const user = await this.createUser(email, role); console.log(`Created user: ${user.email} (ID: ${user.id})`);
// Create device for user const device = await this.createDevice( user.id, deviceName, `Device for ${email}` ); console.log(`Created device: ${device.name} (ID: ${device.id})`);
return { user, device, configUrl: `${this.apiUrl}/devices/${device.id}/config` }; }
async bulkProvision(users) { const results = [];
for (const userData of users) { try { const result = await this.provisionUser( userData.email, userData.deviceName, userData.role || 'user' ); results.push({ success: true, ...result }); } catch (error) { results.push({ success: false, email: userData.email, error: error.message }); } }
return results; }
async listConnectedDevices() { try { const response = await this.client.get('/api/devices', { params: { status: 'connected' } }); return response.data; } catch (error) { throw new Error(`Failed to list devices: ${error.message}`); } }
async getConnectionStats() { try { const response = await this.client.get('/api/stats'); return response.data; } catch (error) { throw new Error(`Failed to get stats: ${error.message}`); } }}
// Usage exampleasync function main() { const firezone = new FirezoneClient( 'https://vpn.example.com', process.env.FIREZONE_API_TOKEN );
// Provision single user const result = await firezone.provisionUser( 'john.doe@example.com', 'Johns Laptop', 'user' ); console.log('Provisioning result:', result);
// Bulk provision users const usersToProvision = [ { email: 'alice@example.com', deviceName: 'Alice MacBook', role: 'user' }, { email: 'bob@example.com', deviceName: 'Bob Windows', role: 'user' }, { email: 'admin@example.com', deviceName: 'Admin Device', role: 'admin' } ];
const bulkResults = await firezone.bulkProvision(usersToProvision); console.log('Bulk provisioning results:', bulkResults);
// Get connected devices const connected = await firezone.listConnectedDevices(); console.log(`Currently connected devices: ${connected.length}`);
// Get connection statistics const stats = await firezone.getConnectionStats(); console.log('Connection stats:', stats);}
// Run if executed directlyif (require.main === module) { main().catch(console.error);}
module.exports = FirezoneClient;Production Best Practices
Security Hardening
Strong Authentication:
- Use complex admin passwords (minimum 16 characters)
- Enable two-factor authentication for admin accounts
- Rotate admin credentials quarterly
- Use SSO integration for centralized identity management
- Implement least-privilege access control
Network Security:
# Restrict allowed IPs in environment variablesWIREGUARD_ALLOWED_IPS=10.0.0.0/8,192.168.0.0/16
# Enable secure cookiesSECURE_COOKIES=true
# Configure trusted proxiesPHOENIX_EXTERNAL_TRUSTED_PROXIES=["10.0.0.0/8"]
# Enable rate limitingRATE_LIMIT_ENABLED=trueRATE_LIMIT_MAX_REQUESTS=10RATE_LIMIT_WINDOW_SECONDS=60Certificate Management:
- Use custom domain with valid SSL certificate
- Klutch.sh provides automatic HTTPS
- For internal certificates, store securely in environment variables
- Rotate WireGuard keys periodically
Audit Logging:
# Enable comprehensive loggingLOG_LEVEL=infoTELEMETRY_ENABLED=true
# Export logs for external analysis# Configure log forwarding to SIEM or monitoring systemPerformance Optimization
Database Tuning:
# Increase connection pool for high loadDATABASE_POOL_SIZE=20
# Enable connection poolingDATABASE_SSL=false # Set to true if database supports SSLResource Allocation:
- Monitor CPU and memory usage in Klutch.sh dashboard
- Scale vertically for more concurrent connections
- Consider horizontal scaling for geographic distribution
WireGuard Optimization:
# Tune MTU for your networkWIREGUARD_MTU=1420 # Default: 1280, adjust based on network
# Set persistent keepaliveWIREGUARD_PERSISTENT_KEEPALIVE=25 # Helps with NAT traversal
# Enable IPv6 if supportedWIREGUARD_IPV6_ENABLED=trueMonitoring and Observability
Health Checks:
# Monitor application healthcurl -f https://vpn.yourdomain.com/health
# Check WireGuard statussudo wg showMetrics Collection:
# Enable Prometheus metricsENABLE_PROMETHEUS_METRICS=true
# Access metrics endpointcurl https://vpn.yourdomain.com/metricsConnection Monitoring:
- Track active connections via admin dashboard
- Monitor authentication failures
- Set up alerts for unusual activity
- Review audit logs regularly
Backup and Disaster Recovery
Database Backups:
# Automated daily backupsDATABASE_BACKUP_ENABLED=trueDATABASE_BACKUP_SCHEDULE="0 2 * * *"
# Manual backuppg_dump -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone > firezone_backup_$(date +%Y%m%d).sql
# Restore from backuppsql -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone < firezone_backup.sqlConfiguration Backups:
# Backup environment variables (store securely)# Document all custom settings# Version control Dockerfile and scripts
# Backup volume data# Klutch.sh provides automatic volume snapshotsDisaster Recovery Plan:
- Document database connection details
- Store secrets in secure vault (e.g., 1Password, LastPass)
- Maintain off-site backup copies
- Test restore procedures quarterly
- Document recovery time objectives (RTO)
- Maintain emergency contact list
Scaling Considerations
Vertical Scaling:
- Increase container resources in Klutch.sh dashboard
- Monitor connection limits and adjust accordingly
- Upgrade database resources as needed
Geographic Distribution:
- Deploy multiple Firezone instances in different regions
- Use round-robin DNS or geo-routing
- Maintain separate databases or database replication
- Consider split tunneling to reduce load
High Availability:
- Use managed PostgreSQL with automatic failover
- Implement health checks and automatic restarts
- Configure database connection pooling
- Monitor uptime and set up alerts
Troubleshooting
Common Issues and Solutions
Issue: Cannot connect to database
# Check database connectivitypg_isready -h postgres-app.klutch.sh -p 8000 -U firezone
# Verify environment variablesecho $DATABASE_HOSTecho $DATABASE_PORT
# Check database logs# Review Klutch.sh deployment logs
# Solution: Ensure DATABASE_HOST uses full Klutch.sh app URL# Example: postgres-app.klutch.sh (not localhost)Issue: WireGuard tunnel not connecting
# Check client configurationwg show
# Verify endpoint is correct# Should match WIREGUARD_ENDPOINT environment variable
# Test UDP connectivitync -uz vpn.example.com 51820
# Solution: Ensure WIREGUARD_ENDPOINT matches your public URL# Check NAT traversal settings# Verify WIREGUARD_PERSISTENT_KEEPALIVE is setIssue: Users not receiving invitation emails
# Check SMTP configuration# Verify OUTBOUND_EMAIL_ADAPTER settings
# Test SMTP connectiontelnet smtp.gmail.com 587
# Check application logs for email errors# Review Klutch.sh deployment logs
# Solution: Verify SMTP credentials# For Gmail, use App Password (not account password)# Check spam folder for invitation emailsIssue: Admin panel not loading
# Check application healthcurl -I https://example-app.klutch.sh/health
# Verify SECRET_KEY_BASE is set correctly# Check deployment logs for errors
# Solution: Ensure all required environment variables are set# Verify EXTERNAL_URL matches your actual URL# Check persistent volume is mounted correctlyIssue: High memory usage
# Check connection pool sizeecho $DATABASE_POOL_SIZE
# Monitor active connections# Review audit logs for unusual activity
# Solution: Reduce DATABASE_POOL_SIZE if too high# Scale up container resources in Klutch.sh# Investigate memory leaks in application logsIssue: SSL/TLS certificate errors
# Verify domain configurationnslookup vpn.yourdomain.com
# Check certificate validityopenssl s_client -connect vpn.yourdomain.com:443
# Solution: Ensure custom domain is properly configured# Klutch.sh automatically manages certificates# Verify DNS records point to Klutch.shDebugging Tips
Enable Debug Logging:
# Set in environment variablesLOG_LEVEL=debug
# Redeploy to apply changes# Review detailed logs in Klutch.sh dashboardCheck WireGuard Status:
# On server (if accessible)wg show
# On clientwg show wg0
# Check routesip route show table all | grep wg0Database Query Debugging:
-- Connect to databasepsql -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone
-- Check active connectionsSELECT count(*) FROM pg_stat_activity WHERE datname = 'firezone';
-- Review recent audit logsSELECT * FROM audit_logs ORDER BY inserted_at DESC LIMIT 20;
-- Check user and device countsSELECT (SELECT count(*) FROM users) as total_users, (SELECT count(*) FROM devices) as total_devices;Network Diagnostics:
# Test HTTP endpointcurl -v https://example-app.klutch.sh
# Check DNS resolutiondig vpn.yourdomain.com
# Test WireGuard UDP portnc -uz example-app.klutch.sh 51820
# Trace routetraceroute example-app.klutch.shAdvanced Configuration
Custom DNS Configuration
Configure custom DNS servers for VPN clients:
# Multiple DNS servers (comma-separated)WIREGUARD_DNS=1.1.1.1,1.0.0.1,8.8.8.8
# Internal DNS for corporate networkWIREGUARD_DNS=10.0.0.53,1.1.1.1
# DNS with search domains# Configure in WireGuard client config manuallySplit Tunneling Setup
Configure which traffic routes through VPN:
# Only route specific networks through VPNWIREGUARD_ALLOWED_IPS=10.0.0.0/8,192.168.0.0/16
# Route all traffic through VPN (full tunnel)WIREGUARD_ALLOWED_IPS=0.0.0.0/0
# Exclude specific networks (configure client-side)# Edit WireGuard config file manuallyMulti-Site Configuration
Deploy multiple Firezone instances for different offices:
Site 1 (US East):
EXTERNAL_URL=https://vpn-us-east.yourdomain.comWIREGUARD_ENDPOINT=vpn-us-east.yourdomain.comWIREGUARD_IPV4_NETWORK=10.1.0.0/24Site 2 (EU West):
EXTERNAL_URL=https://vpn-eu-west.yourdomain.comWIREGUARD_ENDPOINT=vpn-eu-west.yourdomain.comWIREGUARD_IPV4_NETWORK=10.2.0.0/24SAML Integration Example (Okta)
# Okta SAML ConfigurationSAML_ENTITY_ID=https://vpn.yourdomain.comSAML_KEYFILE_PATH=/var/firezone/saml/key.pemSAML_CERTFILE_PATH=/var/firezone/saml/cert.pem
# Auto-create users from SAMLAUTO_CREATE_OIDC_USERS=true
# Map SAML attributes# Configure in Okta SAML app:# - Email: user.email# - FirstName: user.firstName# - LastName: user.lastName# - Groups: user.groupsGoogle Workspace SSO Integration
# Google Workspace OIDCOIDC_DISCOVERY_DOCUMENT_URI=https://accounts.google.com/.well-known/openid-configurationOIDC_CLIENT_ID=your-client-id.apps.googleusercontent.comOIDC_CLIENT_SECRET=your-client-secretOIDC_REDIRECT_URI=https://vpn.yourdomain.com/auth/oidc/callbackOIDC_RESPONSE_TYPE=codeOIDC_SCOPE=openid email profile
# Auto-create usersAUTO_CREATE_OIDC_USERS=true
# Domain restriction (optional)# Implement via custom middleware or OIDC claims filteringAPI Rate Limiting
# Enable rate limitingRATE_LIMIT_ENABLED=true
# Configure limitsRATE_LIMIT_MAX_REQUESTS=10 # Requests per windowRATE_LIMIT_WINDOW_SECONDS=60 # Window duration
# Apply to authentication endpointsRATE_LIMIT_AUTH_ATTEMPTS=5RATE_LIMIT_AUTH_WINDOW=300Custom Branding
Customize Firezone appearance:
- Create custom logo and favicon
- Store in persistent volume:
/var/firezone/assets - Configure asset paths in environment variables
- Use custom domain for branded experience
Use Cases
Remote Workforce Access
Secure remote access for distributed teams:
- Deploy Firezone as central VPN gateway
- Integrate with Google Workspace or Azure AD
- Configure split tunneling for corporate resources
- Monitor connections and enforce access policies
Secure Cloud Resource Access
Connect to private cloud resources:
- Route traffic to AWS VPC, Azure VNet, or GCP VPC
- Configure site-to-site VPN tunnels
- Implement zero trust networking
- Audit all resource access
Multi-Office Connectivity
Connect multiple office locations:
- Deploy Firezone instance in each office
- Configure mesh networking between sites
- Centralize authentication with SSO
- Monitor inter-office traffic
Developer Access to Production
Secure developer access to production systems:
- Require 2FA for all production access
- Audit all production connections
- Implement time-based access controls
- Integrate with CI/CD pipelines
Contractor and Vendor Access
Provide temporary VPN access:
- Create time-limited user accounts
- Restrict access to specific resources
- Revoke access automatically on project completion
- Maintain comprehensive audit logs
Resources
Official Documentation
Klutch.sh Platform
- PostgreSQL Deployment Guide
- Persistent Volumes Documentation
- Custom Domains Configuration
- Networking Concepts
Community and Support
Related Technologies
Conclusion
Deploying Firezone on Klutch.sh provides you with a powerful, self-hosted VPN solution that combines WireGuard’s cutting-edge performance with enterprise management features. With integrated web portal, SSO authentication, multi-platform client support, comprehensive audit logging, fine-grained access control, and Klutch.sh’s managed infrastructure, you can implement secure remote access for your organization without the complexity of traditional VPN solutions. Klutch.sh’s persistent storage, automatic HTTPS, and simplified deployment ensure your VPN infrastructure is reliable, secure, and easy to maintain.
Start securing your remote access today by deploying Firezone on Klutch.sh and experience modern VPN technology with enterprise-grade management capabilities.