- Add Go TUI with bubbletea for WireGuard management - Implement client CRUD operations with QR code generation - Add configuration and validation modules - Install/update scripts for client setup - Update Makefile to build binaries to bin/ directory - Add .gitignore for Go projects
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.mdand.agent/directory for project-specific guidance - Issue tracking: Use
bd readyto find available work - External issues: Gitea at https://gitea.calmcacil.dev
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
/etc/wg-admin/config.conffile (highest priority)- Environment variables (e.g.,
SERVER_DOMAIN=vpn.example.com ./wireguard.sh install) - 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-clientsto 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
Client Setup
Importing the config
- Desktop: Import
/etc/wireguard/clients/<name>.confinto 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