Skip to content

Deployment

Stefano Bertelli edited this page Apr 3, 2026 · 1 revision

Deployment

Docker (Recommended)

WireGUI is distributed as a Docker image with automatic database migrations.

Minimal Production Setup

# compose.prod.yml
services:
  postgres:
    image: postgres:17
    environment:
      POSTGRES_USER: wiregui
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: wiregui
    volumes:
      - postgres_data:/var/lib/postgresql/data

  valkey:
    image: valkey/valkey:8
    volumes:
      - valkey_data:/data

  wiregui:
    image: ghcr.io/bartei/wiregui:latest
    ports:
      - "13000:13000"
      - "51820:51820/udp"
    environment:
      WG_DATABASE_URL: postgresql+asyncpg://wiregui:${DB_PASSWORD}@postgres/wiregui
      WG_REDIS_URL: redis://valkey:6379/0
      WG_SECRET_KEY: ${SECRET_KEY}
      WG_WG_ENABLED: "true"
      WG_EXTERNAL_URL: https://vpn.example.com
      WG_ENDPOINT_HOST: vpn.example.com
      WG_ADMIN_EMAIL: admin@example.com
      WG_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
      WG_LOG_TO_FILE: "false"
    cap_add:
      - NET_ADMIN
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv6.conf.all.forwarding=1
    depends_on:
      - postgres
      - valkey

volumes:
  postgres_data:
  valkey_data:

Required Capabilities

WireGUI needs NET_ADMIN capability and IP forwarding sysctls to manage WireGuard interfaces and nftables rules.

Environment File

Create a .env file for secrets:

DB_PASSWORD=strong-random-password
SECRET_KEY=another-strong-random-value
ADMIN_PASSWORD=initial-admin-password

Starting

docker compose -f compose.prod.yml up -d

The container automatically:

  1. Runs alembic upgrade head to apply database migrations
  2. Starts the WireGUI application

Exposed Ports

Port Protocol Description
13000 TCP Web UI and REST API
51820 UDP WireGuard VPN tunnel

Reverse Proxy

In production, place WireGUI behind a reverse proxy (nginx, Caddy, Traefik) for TLS termination.

nginx Example

server {
    listen 443 ssl;
    server_name vpn.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:13000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Important: WebSocket support (Upgrade and Connection headers) is required for the NiceGUI real-time UI to function.

Caddy Example

vpn.example.com {
    reverse_proxy localhost:13000
}

Caddy automatically handles TLS and WebSocket proxying.

Updating

docker compose -f compose.prod.yml pull wiregui
docker compose -f compose.prod.yml up -d wiregui

Database migrations run automatically on startup, so updates are typically zero-downtime for schema-compatible changes.

Backup

Back up the PostgreSQL database regularly:

docker compose exec postgres pg_dump -U wiregui wiregui > backup.sql

The database is the single source of truth. WireGuard interface state is fully reconciled from the database on startup.

Clone this wiki locally