WireGuard VPN Setup for Debian 13

Overview

Personal WireGuard VPN server with IPv4/IPv6 support, client management via wireguard.sh, designed for 1 CPU / 1GB RAM VPS.

Development & Issue Tracking

This project uses beads (bd CLI) for issue tracking and Gitea for external issue tracking.

  • Agent instructions: See AGENTS.md and .agent/ directory for project-specific guidance
  • Issue tracking: Use bd ready to find available work
  • External issues: Gitea at https://gitea.calmcacil.dev

Theming

The TUI supports multiple color themes. Set the THEME environment variable to switch themes:

Available Themes

Theme Description Default
everforest Natural green/blue theme (default)
dracula Popular dark purple theme
default Standard blue-based theme
dark Purple-based dark theme
light Green-based light theme

Usage

# Use Everforest (default)
sudo wg-admin-tui

# Use Dracula theme
THEME=dracula sudo wg-admin-tui

# Use default theme
THEME=default sudo wg-admin-tui

# Use light theme
THEME=light sudo wg-admin-tui

Configuration

Configuration is managed through /etc/wg-admin/config.conf. Copy config.example to this location and customize for your environment.

Creating Configuration File

sudo mkdir -p /etc/wg-admin
sudo cp config.example /etc/wg-admin/config.conf
sudo nano /etc/wg-admin/config.conf

Configuration Variables

Variable Default Description
SERVER_DOMAIN Required Server domain or IP address (e.g., vpn.example.com)
WG_PORT 51820 WireGuard UDP port
VPN_IPV4_RANGE 10.10.69.0/24 VPN IPv4 address range
VPN_IPV6_RANGE fd69:dead:beef:69::/64 VPN IPv6 address range
WG_INTERFACE wg0 WireGuard interface name
DNS_SERVERS 8.8.8.8, 8.8.4.4 DNS servers for clients
LOG_FILE /var/log/wireguard-admin.log Log file location

Example Configuration

# Server domain or IP address (required)
SERVER_DOMAIN=vpn.example.com

# WireGuard UDP port (optional, default: 51820)
WG_PORT=51820

# VPN IPv4 range (optional, default: 10.10.69.0/24)
VPN_IPV4_RANGE=10.10.69.0/24

# VPN IPv6 range (optional, default: fd69:dead:beef:69::/64)
VPN_IPV6_RANGE=fd69:dead:beef:69::/64

# DNS servers (optional, default: 8.8.8.8, 8.8.4.4)
DNS_SERVERS=8.8.8.8, 8.8.4.4

Note: All values are optional except SERVER_DOMAIN. The script will use defaults if not specified.

Configuration Priority

  1. /etc/wg-admin/config.conf file (highest priority)
  2. Environment variables (e.g., SERVER_DOMAIN=vpn.example.com ./wireguard.sh install)
  3. Built-in defaults (lowest priority)

Other Directories

  • Server-side peer configs: /etc/wireguard/conf.d/client-*.conf (loaded dynamically)
  • Client-side configs: /etc/wireguard/clients/*.conf (for distribution)

Installation

1. Upload script to VPS

scp wireguard.sh calmcacil@your-vps.com:~/
scp config.example calmcacil@your-vps.com:~/

2. Configure the script

# Copy example config and customize
sudo mkdir -p /etc/wg-admin
sudo cp ~/config.example /etc/wg-admin/config.conf
sudo nano /etc/wg-admin/config.conf

# Set at minimum:
# SERVER_DOMAIN=vpn.yourdomain.com

3. Run installation

chmod +x ~/wireguard.sh
sudo ~/wireguard.sh install

Usage

Dynamic client loading

WireGuard automatically loads clients from /etc/wireguard/conf.d/:

  • Add/remove client configs in /etc/wireguard/conf.d/client-*.conf
  • Run sudo ~/wireguard.sh load-clients to reload
  • Changes are applied immediately without restarting

Add a new client

sudo ~/wireguard.sh add myphone

This creates:

  • Server config in /etc/wireguard/conf.d/client-myphone.conf
  • Client config in /etc/wireguard/clients/myphone.conf
  • QR code in /etc/wireguard/clients/myphone.qr

List all clients

sudo ~/wireguard.sh list

Show client config

sudo ~/wireguard.sh show myphone

Show QR code

sudo ~/wireguard.sh qr myphone

Remove a client

sudo ~/wireguard.sh remove myphone

Server Management

Check WireGuard status

sudo wg show

Check service status

sudo systemctl status wg-quick@wg0

Restart WireGuard

sudo systemctl restart wg-quick@wg0

Reload clients (automatic on add/remove)

sudo ~/wireguard.sh load-clients

Firewall management

The setup configures nftables with:

  • Dual-stack IPv4/IPv6 support in a single ruleset
  • Default drop incoming, accept outgoing
  • SSH access allowed (port 22)
  • WireGuard allowed (UDP 51820)
  • Forwarding from wg0 interface allowed
  • NAT masquerade for VPN internet access

View firewall rules:

sudo nft list ruleset

Reload firewall:

sudo nft -f /etc/nftables.conf

Note: nftables rules are automatically loaded on boot by the nftables service from /etc/nftables.conf. No manual intervention required after reboot.

Allow additional ports if needed:

sudo nft add rule inet wireguard input tcp dport 80 accept    # HTTP
sudo nft add rule inet wireguard input tcp dport 443 accept   # HTTPS

Manual Client Configuration

To manually add a client, create a file in /etc/wireguard/conf.d/:

[Peer]
# mydevice
PublicKey = <client_public_key>
AllowedIPs = 10.10.69.2/32, fd69:dead:beef:69::2/128

Then run:

sudo ~/wireguard.sh load-clients

Text Selection & Copying

To copy client configurations or other text from the terminal UI:

Text Selection

  • Hold SHIFT key while dragging your mouse with the left button
  • This bypasses TUI mouse handling and enables your terminal's native text selection
  • Then use your terminal's copy shortcut:
    • Linux/WSL: Ctrl+Shift+C (or terminal-specific shortcut)
    • macOS: Cmd+C
    • Windows: Click right (or use terminal copy)

Copy Buttons (when available)

  • Some modals may have explicit copy buttons (e.g., "C" to copy config)
  • These work when clipboard API is available (native Linux, macOS, WSL)
  • Over SSH requires X11 forwarding (ssh -X) for clipboard access

Client Setup

Importing the config

  • Desktop: Import /etc/wireguard/clients/<name>.conf into WireGuard app
  • Mobile: Scan QR code with WireGuard app, or import config file

Test connectivity

# On client
ping 10.10.69.1
ping -6 fd69:dead:beef:69::1

# Check your IP
curl -4 https://ifconfig.me
curl -6 https://ifconfig.me

Troubleshooting

Check firewall

sudo nft list ruleset

Check IP forwarding

sysctl net.ipv4.ip_forward
sysctl net.ipv6.conf.all.forwarding

View logs

sudo journalctl -u wg-quick@wg0 -f

Check client directory

ls -la /etc/wireguard/conf.d/

Manual reload if needed

sudo ~/wireguard.sh load-clients

Notes

  • /etc/wireguard/conf.d/ - Server-side peer configs, loaded automatically by wireguard.sh
  • /etc/wireguard/clients/ - Client-side configs (import to WireGuard apps) and QR codes
  • Clients are automatically reloaded when added/removed
  • IPv4 and IPv6 NAT are configured (MASQUERADE)
  • nftables firewall is configured with dual-stack IPv4/IPv6 support
  • Single nftables ruleset handles both IPv4 and IPv6
  • SSH (port 22) and WireGuard (UDP 51820) are allowed by default
  • Keepalive is set to 25 seconds for better stability
  • Server private keys are stored in /etc/wireguard/server_private.key
  • Server public key is displayed after installation
Description
No description provided
Readme 1.1 MiB
Languages
Shell 100%