Skip to content

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:

  1. Firezone Server: The main VPN server and web portal (Elixir/Phoenix application)
  2. PostgreSQL Database: Stores user accounts, devices, configurations, and audit logs
  3. WireGuard Kernel Module: Handles VPN tunneling at the kernel level
  4. 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:

Terminal window
mkdir firezone-klutch
cd firezone-klutch
git init

Step 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 default
EXPOSE 13000
# WireGuard port
EXPOSE 51820/udp
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:13000/health || exit 1

Production Dockerfile (Multi-Stage with Custom Configuration):

FROM firezone/firezone:latest
# Install additional tools for monitoring and debugging
RUN apk add --no-cache \
curl \
postgresql-client \
wireguard-tools \
iptables \
ip6tables
# Create non-root user for security
RUN addgroup -g 1000 firezone && \
adduser -D -u 1000 -G firezone firezone
# Create necessary directories
RUN mkdir -p /var/firezone /var/log/firezone && \
chown -R firezone:firezone /var/firezone /var/log/firezone
# Set working directory
WORKDIR /var/firezone
# Copy startup script
COPY --chown=firezone:firezone scripts/entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh
# Expose ports
EXPOSE 13000 51820/udp
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:13000/health || exit 1
# Switch to non-root user
USER firezone
# Start Firezone
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["start"]

Step 3: Create Startup Script (for Production Dockerfile)

Create scripts/entrypoint.sh:

#!/bin/sh
set -e
# Wait for PostgreSQL to be ready
echo "Waiting for PostgreSQL..."
until pg_isready -h "$DATABASE_HOST" -U "$DATABASE_USER"; do
echo "PostgreSQL is unavailable - sleeping"
sleep 2
done
echo "PostgreSQL is ready!"
# Run database migrations
echo "Running database migrations..."
/app/bin/firezone eval "Firezone.Release.migrate()"
# Start Firezone
echo "Starting Firezone..."
exec /app/bin/firezone "$@"

Make it executable:

Terminal window
chmod +x scripts/entrypoint.sh

Step 4: Create Environment Configuration File

Create a .env.example file documenting all configuration options:

Terminal window
# Firezone Core Configuration
EXTERNAL_URL=https://vpn.yourdomain.com
DEFAULT_ADMIN_EMAIL=admin@yourdomain.com
DEFAULT_ADMIN_PASSWORD=changeme_secure_password
# Database Configuration (PostgreSQL)
DATABASE_HOST=postgres-app.klutch.sh
DATABASE_PORT=8000
DATABASE_NAME=firezone
DATABASE_USER=firezone
DATABASE_PASSWORD=your_secure_db_password
DATABASE_POOL_SIZE=10
DATABASE_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 Configuration
WIREGUARD_ENDPOINT=vpn.yourdomain.com
WIREGUARD_PORT=51820
WIREGUARD_IPV4_ENABLED=true
WIREGUARD_IPV4_NETWORK=10.3.2.0/24
WIREGUARD_IPV4_ADDRESS=10.3.2.1
WIREGUARD_IPV6_ENABLED=false
WIREGUARD_PERSISTENT_KEEPALIVE=25
WIREGUARD_DNS=1.1.1.1,1.0.0.1
WIREGUARD_ALLOWED_IPS=0.0.0.0/0
WIREGUARD_MTU=1280
# Application Settings
PHOENIX_HTTP_PORT=13000
PHOENIX_EXTERNAL_TRUSTED_PROXIES=["10.0.0.0/8"]
MAX_DEVICES_PER_USER=10
ALLOW_UNPRIVILEGED_DEVICE_MANAGEMENT=true
ALLOW_UNPRIVILEGED_DEVICE_CONFIGURATION=true
AUTO_CREATE_OIDC_USERS=true
# Email Configuration (SMTP)
OUTBOUND_EMAIL_FROM=noreply@yourdomain.com
OUTBOUND_EMAIL_ADAPTER=Swoosh.Adapters.SMTP
OUTBOUND_EMAIL_ADAPTER_OPTS_RELAY=smtp.gmail.com
OUTBOUND_EMAIL_ADAPTER_OPTS_PORT=587
OUTBOUND_EMAIL_ADAPTER_OPTS_USERNAME=your-email@gmail.com
OUTBOUND_EMAIL_ADAPTER_OPTS_PASSWORD=your-app-password
OUTBOUND_EMAIL_ADAPTER_OPTS_TLS=always
OUTBOUND_EMAIL_ADAPTER_OPTS_AUTH=always
# Session Configuration
SESSION_TTL_HOURS=720
DEVICE_TTL_HOURS=8760
# Security Settings
SECURE_COOKIES=true
SIGN_OUT_ON_SESSION_EXPIRE=false
RATE_LIMIT_ENABLED=true
RATE_LIMIT_MAX_REQUESTS=10
RATE_LIMIT_WINDOW_SECONDS=60
# Telemetry and Logging
TELEMETRY_ENABLED=true
LOG_LEVEL=info
ENABLE_PROMETHEUS_METRICS=true
# SAML SSO Configuration (Optional)
SAML_ENTITY_ID=https://vpn.yourdomain.com
SAML_KEYFILE_PATH=/var/firezone/saml/key.pem
SAML_CERTFILE_PATH=/var/firezone/saml/cert.pem
# OIDC Configuration (Optional)
OIDC_DISCOVERY_DOCUMENT_URI=https://accounts.google.com/.well-known/openid-configuration
OIDC_CLIENT_ID=your-oidc-client-id
OIDC_CLIENT_SECRET=your-oidc-client-secret
OIDC_REDIRECT_URI=https://vpn.yourdomain.com/auth/oidc/callback
OIDC_RESPONSE_TYPE=code
OIDC_SCOPE=openid email profile
# Advanced Networking
ENABLE_IPV6=false
ENABLE_MASQUERADE=true
ENABLE_PORT_FORWARDING=true
# Backup and Maintenance
DATABASE_BACKUP_ENABLED=true
DATABASE_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 first
2. Update `.env` with your database credentials
3. Generate secret keys:
```bash
openssl rand -base64 48
  1. Push to GitHub
  2. Deploy on Klutch.sh:
    • Set traffic type to HTTP
    • Internal port: 13000
    • Configure environment variables
    • Attach persistent volume at /var/firezone

Initial Setup

  1. Access web portal at your deployed URL
  2. Login with DEFAULT_ADMIN_EMAIL and DEFAULT_ADMIN_PASSWORD
  3. Change admin password immediately
  4. Configure WireGuard settings
  5. Create users and generate device configurations

Client Setup

Linux

Terminal window
sudo apt install wireguard
# Download config from Firezone portal
sudo wg-quick up wg0

macOS

  1. Install WireGuard from App Store
  2. Import config from Firezone portal
  3. Activate tunnel

Windows

  1. Download WireGuard client
  2. Import config file
  3. Activate tunnel

iOS/Android

  1. Install WireGuard app
  2. Scan QR code from Firezone portal
  3. Activate tunnel

Documentation

### 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 user
CREATE USER firezone WITH PASSWORD 'your_secure_password';
-- Create database
CREATE DATABASE firezone OWNER firezone;
-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE firezone TO firezone;
-- Connect to firezone database
\c firezone
-- Grant schema privileges
GRANT ALL ON SCHEMA public TO firezone;

Verify Connection

Test connection from your local machine:

Terminal window
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 accounts
  • devices - VPN devices and configurations
  • rules - Access control rules
  • sites - Multi-tenant site configurations
  • settings - Application settings
  • audit_logs - Authentication and connection logs
  • sessions - Active user sessions
  • saml_identity_providers - SAML SSO configurations
  • oidc_providers - OpenID Connect configurations

Backup Recommendations

Terminal window
# Full database backup
pg_dump -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone > firezone_backup.sql
# Restore from backup
psql -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:
```yaml
version: '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:

Terminal window
docker-compose up -d
docker-compose logs -f
# Access at http://localhost:13000

Step 8: Initialize Git Repository

Terminal window
# Create .gitignore
cat > .gitignore << 'EOF'
.env
.env.local
*.log
node_modules/
.DS_Store
docker-compose.override.yml
*.sql
backups/
EOF
# Initialize repository
git add .
git commit -m "Initial Firezone deployment setup"
# Add GitHub remote
git remote add origin https://github.com/yourusername/firezone-klutch.git
git branch -M main
git push -u origin main

Deploying on Klutch.sh

  1. ### 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
  2. ### 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.
  3. ### Create a New Project
    - Click **"New Project"**
    - Enter a project name: **"Firezone VPN"**
    - Click **"Create Project"**
  4. ### Create New App
    - Inside your project, click **"New App"**
    - Enter app name: **"firezone-vpn"** (or your preferred name)
    - Click **"Create App"**
  5. ### Connect GitHub Repository
    - Click **"Connect Repository"**
    - Select your GitHub account
    - Choose the repository you created earlier
    - Select the **main** branch
    - Click **"Connect"**
  6. ### 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
  7. ### Set Environment Variables
    In the Klutch.sh dashboard, add the following environment variables (update with your values):
    **Core Configuration**:
    ```bash
    EXTERNAL_URL=https://example-app.klutch.sh
    DEFAULT_ADMIN_EMAIL=admin@yourdomain.com
    DEFAULT_ADMIN_PASSWORD=your_secure_admin_password
    ```
    **Database Configuration**:
    ```bash
    DATABASE_HOST=your-postgres-app.klutch.sh
    DATABASE_PORT=8000
    DATABASE_NAME=firezone
    DATABASE_USER=firezone
    DATABASE_PASSWORD=your_secure_db_password
    DATABASE_POOL_SIZE=10
    ```
    **Secret Keys** (generate with `openssl rand -base64 48`):
    ```bash
    SECRET_KEY_BASE=your_generated_secret_key_base
    LIVE_VIEW_SIGNING_SALT=your_generated_signing_salt
    GUARDIAN_SECRET_KEY=your_generated_guardian_key
    ```
    **WireGuard Configuration**:
    ```bash
    WIREGUARD_ENDPOINT=example-app.klutch.sh
    WIREGUARD_PORT=51820
    WIREGUARD_IPV4_ENABLED=true
    WIREGUARD_IPV4_NETWORK=10.3.2.0/24
    WIREGUARD_IPV4_ADDRESS=10.3.2.1
    WIREGUARD_DNS=1.1.1.1,1.0.0.1
    WIREGUARD_MTU=1280
    ```
    **Email Configuration** (SMTP):
    ```bash
    OUTBOUND_EMAIL_FROM=noreply@yourdomain.com
    OUTBOUND_EMAIL_ADAPTER=Swoosh.Adapters.SMTP
    OUTBOUND_EMAIL_ADAPTER_OPTS_RELAY=smtp.gmail.com
    OUTBOUND_EMAIL_ADAPTER_OPTS_PORT=587
    OUTBOUND_EMAIL_ADAPTER_OPTS_USERNAME=your-email@gmail.com
    OUTBOUND_EMAIL_ADAPTER_OPTS_PASSWORD=your-app-password
    OUTBOUND_EMAIL_ADAPTER_OPTS_TLS=always
    ```
    **Security Settings**:
    ```bash
    PHOENIX_HTTP_PORT=13000
    SECURE_COOKIES=true
    RATE_LIMIT_ENABLED=true
    LOG_LEVEL=info
    TELEMETRY_ENABLED=true
    ```
  8. ### Attach Persistent Volume
    For storing Firezone data and logs:
    - Click **"Add Volume"**
    - Mount path: `/var/firezone`
    - Recommended size: **10GB** (for configurations, logs, and certificates)
  9. ### 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
  10. ### 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

  1. Navigate to your Firezone URL
  2. Login with the admin credentials you set: - Email: Value from `DEFAULT_ADMIN_EMAIL` - Password: Value from `DEFAULT_ADMIN_PASSWORD`
  3. You'll be prompted to change your password immediately
  4. Set a strong new admin password and save

Step 2: Configure WireGuard Settings

  1. Navigate to **Settings → General**
  2. Verify WireGuard endpoint is correct (your domain or Klutch.sh URL)
  3. Confirm IPv4 network range doesn't conflict with existing networks
  4. Set DNS servers for VPN clients (e.g., `1.1.1.1, 1.0.0.1`)
  5. Configure split tunneling if needed
  6. Save settings

Step 3: Create Users

  1. Navigate to **Users** in the sidebar
  2. Click **"Add User"**
  3. Enter user details: - Email address - Role (Admin or User)
  4. User will receive an invitation email
  5. Repeat for all users needing VPN access

Step 4: Generate Device Configurations

  1. Login as a user (or admin)
  2. Navigate to **Devices**
  3. Click **"Add Device"**
  4. Enter device details: - Device name (e.g., "John's MacBook") - Description (optional)
  5. Click **"Generate Configuration"**
  6. Download configuration file or scan QR code

Step 5: Configure SSO (Optional)

For SAML 2.0 or OpenID Connect integration:

  1. Navigate to **Settings → SSO**
  2. Choose SSO method (SAML or OIDC)
  3. Enter provider details: - For Google: Use OAuth 2.0 client credentials - For Okta: Configure SAML app integration - For Azure AD: Use OpenID Connect
  4. Configure callback URLs
  5. Test SSO login
  6. Enable auto-user creation if desired

Client Setup and Connection

Linux Client Setup

Terminal window
# Install WireGuard
sudo apt update
sudo apt install wireguard -y
# Download config from Firezone portal
# Save as /etc/wireguard/wg0.conf
# Start VPN tunnel
sudo wg-quick up wg0
# Enable on boot
sudo systemctl enable wg-quick@wg0
# Check connection status
sudo wg show
# Stop tunnel
sudo wg-quick down wg0

macOS Client Setup

Terminal window
# Install via Homebrew
brew install wireguard-tools
# Or download WireGuard app from App Store
# Download config from Firezone portal
# Import into WireGuard app
# Activate tunnel

Using WireGuard App:

  1. Download WireGuard from App Store
  2. Open WireGuard app
  3. Click “Import tunnel(s) from file”
  4. Select downloaded config file
  5. Click “Activate” to connect

Windows Client Setup

  1. Download WireGuard for Windows
  2. Install and launch WireGuard
  3. Click “Import tunnel(s) from file”
  4. Select downloaded config file from Firezone
  5. Click “Activate” to connect
  6. Check system tray icon for connection status

iOS Client Setup

  1. Install WireGuard from App Store
  2. Open Firezone portal on your phone
  3. Navigate to Devices → Add Device
  4. Scan QR code with WireGuard app
  5. Name the tunnel
  6. Toggle switch to activate

Android Client Setup

  1. Install WireGuard from Play Store
  2. Open Firezone portal on your phone
  3. Navigate to Devices → Add Device
  4. Scan QR code with WireGuard app
  5. Name the tunnel
  6. Toggle switch to activate

Verifying Connection

Once connected, verify VPN is working:

Terminal window
# Check assigned VPN IP
ip addr show wg0 # Linux/macOS
ipconfig /all # Windows
# Test connectivity
ping 10.3.2.1 # VPN gateway
# Check public IP (should show VPN exit IP)
curl ifconfig.me
# DNS test
nslookup google.com

Integration Examples

API Integration (Python)

import requests
import 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 example
if __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 example
async 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 directly
if (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:

Terminal window
# Restrict allowed IPs in environment variables
WIREGUARD_ALLOWED_IPS=10.0.0.0/8,192.168.0.0/16
# Enable secure cookies
SECURE_COOKIES=true
# Configure trusted proxies
PHOENIX_EXTERNAL_TRUSTED_PROXIES=["10.0.0.0/8"]
# Enable rate limiting
RATE_LIMIT_ENABLED=true
RATE_LIMIT_MAX_REQUESTS=10
RATE_LIMIT_WINDOW_SECONDS=60

Certificate 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:

Terminal window
# Enable comprehensive logging
LOG_LEVEL=info
TELEMETRY_ENABLED=true
# Export logs for external analysis
# Configure log forwarding to SIEM or monitoring system

Performance Optimization

Database Tuning:

Terminal window
# Increase connection pool for high load
DATABASE_POOL_SIZE=20
# Enable connection pooling
DATABASE_SSL=false # Set to true if database supports SSL

Resource Allocation:

  • Monitor CPU and memory usage in Klutch.sh dashboard
  • Scale vertically for more concurrent connections
  • Consider horizontal scaling for geographic distribution

WireGuard Optimization:

Terminal window
# Tune MTU for your network
WIREGUARD_MTU=1420 # Default: 1280, adjust based on network
# Set persistent keepalive
WIREGUARD_PERSISTENT_KEEPALIVE=25 # Helps with NAT traversal
# Enable IPv6 if supported
WIREGUARD_IPV6_ENABLED=true

Monitoring and Observability

Health Checks:

Terminal window
# Monitor application health
curl -f https://vpn.yourdomain.com/health
# Check WireGuard status
sudo wg show

Metrics Collection:

Terminal window
# Enable Prometheus metrics
ENABLE_PROMETHEUS_METRICS=true
# Access metrics endpoint
curl https://vpn.yourdomain.com/metrics

Connection 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:

Terminal window
# Automated daily backups
DATABASE_BACKUP_ENABLED=true
DATABASE_BACKUP_SCHEDULE="0 2 * * *"
# Manual backup
pg_dump -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone > firezone_backup_$(date +%Y%m%d).sql
# Restore from backup
psql -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone < firezone_backup.sql

Configuration Backups:

Terminal window
# Backup environment variables (store securely)
# Document all custom settings
# Version control Dockerfile and scripts
# Backup volume data
# Klutch.sh provides automatic volume snapshots

Disaster Recovery Plan:

  1. Document database connection details
  2. Store secrets in secure vault (e.g., 1Password, LastPass)
  3. Maintain off-site backup copies
  4. Test restore procedures quarterly
  5. Document recovery time objectives (RTO)
  6. 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

Terminal window
# Check database connectivity
pg_isready -h postgres-app.klutch.sh -p 8000 -U firezone
# Verify environment variables
echo $DATABASE_HOST
echo $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

Terminal window
# Check client configuration
wg show
# Verify endpoint is correct
# Should match WIREGUARD_ENDPOINT environment variable
# Test UDP connectivity
nc -uz vpn.example.com 51820
# Solution: Ensure WIREGUARD_ENDPOINT matches your public URL
# Check NAT traversal settings
# Verify WIREGUARD_PERSISTENT_KEEPALIVE is set

Issue: Users not receiving invitation emails

Terminal window
# Check SMTP configuration
# Verify OUTBOUND_EMAIL_ADAPTER settings
# Test SMTP connection
telnet 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 emails

Issue: Admin panel not loading

Terminal window
# Check application health
curl -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 correctly

Issue: High memory usage

Terminal window
# Check connection pool size
echo $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 logs

Issue: SSL/TLS certificate errors

Terminal window
# Verify domain configuration
nslookup vpn.yourdomain.com
# Check certificate validity
openssl 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.sh

Debugging Tips

Enable Debug Logging:

Terminal window
# Set in environment variables
LOG_LEVEL=debug
# Redeploy to apply changes
# Review detailed logs in Klutch.sh dashboard

Check WireGuard Status:

Terminal window
# On server (if accessible)
wg show
# On client
wg show wg0
# Check routes
ip route show table all | grep wg0

Database Query Debugging:

-- Connect to database
psql -h postgres-app.klutch.sh -p 8000 -U firezone -d firezone
-- Check active connections
SELECT count(*) FROM pg_stat_activity WHERE datname = 'firezone';
-- Review recent audit logs
SELECT * FROM audit_logs ORDER BY inserted_at DESC LIMIT 20;
-- Check user and device counts
SELECT
(SELECT count(*) FROM users) as total_users,
(SELECT count(*) FROM devices) as total_devices;

Network Diagnostics:

Terminal window
# Test HTTP endpoint
curl -v https://example-app.klutch.sh
# Check DNS resolution
dig vpn.yourdomain.com
# Test WireGuard UDP port
nc -uz example-app.klutch.sh 51820
# Trace route
traceroute example-app.klutch.sh

Advanced Configuration

Custom DNS Configuration

Configure custom DNS servers for VPN clients:

Terminal window
# Multiple DNS servers (comma-separated)
WIREGUARD_DNS=1.1.1.1,1.0.0.1,8.8.8.8
# Internal DNS for corporate network
WIREGUARD_DNS=10.0.0.53,1.1.1.1
# DNS with search domains
# Configure in WireGuard client config manually

Split Tunneling Setup

Configure which traffic routes through VPN:

Terminal window
# Only route specific networks through VPN
WIREGUARD_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 manually

Multi-Site Configuration

Deploy multiple Firezone instances for different offices:

Site 1 (US East):

Terminal window
EXTERNAL_URL=https://vpn-us-east.yourdomain.com
WIREGUARD_ENDPOINT=vpn-us-east.yourdomain.com
WIREGUARD_IPV4_NETWORK=10.1.0.0/24

Site 2 (EU West):

Terminal window
EXTERNAL_URL=https://vpn-eu-west.yourdomain.com
WIREGUARD_ENDPOINT=vpn-eu-west.yourdomain.com
WIREGUARD_IPV4_NETWORK=10.2.0.0/24

SAML Integration Example (Okta)

Terminal window
# Okta SAML Configuration
SAML_ENTITY_ID=https://vpn.yourdomain.com
SAML_KEYFILE_PATH=/var/firezone/saml/key.pem
SAML_CERTFILE_PATH=/var/firezone/saml/cert.pem
# Auto-create users from SAML
AUTO_CREATE_OIDC_USERS=true
# Map SAML attributes
# Configure in Okta SAML app:
# - Email: user.email
# - FirstName: user.firstName
# - LastName: user.lastName
# - Groups: user.groups

Google Workspace SSO Integration

Terminal window
# Google Workspace OIDC
OIDC_DISCOVERY_DOCUMENT_URI=https://accounts.google.com/.well-known/openid-configuration
OIDC_CLIENT_ID=your-client-id.apps.googleusercontent.com
OIDC_CLIENT_SECRET=your-client-secret
OIDC_REDIRECT_URI=https://vpn.yourdomain.com/auth/oidc/callback
OIDC_RESPONSE_TYPE=code
OIDC_SCOPE=openid email profile
# Auto-create users
AUTO_CREATE_OIDC_USERS=true
# Domain restriction (optional)
# Implement via custom middleware or OIDC claims filtering

API Rate Limiting

Terminal window
# Enable rate limiting
RATE_LIMIT_ENABLED=true
# Configure limits
RATE_LIMIT_MAX_REQUESTS=10 # Requests per window
RATE_LIMIT_WINDOW_SECONDS=60 # Window duration
# Apply to authentication endpoints
RATE_LIMIT_AUTH_ATTEMPTS=5
RATE_LIMIT_AUTH_WINDOW=300

Custom Branding

Customize Firezone appearance:

  1. Create custom logo and favicon
  2. Store in persistent volume: /var/firezone/assets
  3. Configure asset paths in environment variables
  4. 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

Community and Support


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.