WGDashboard API Client
For 4.3.3 and earlier
An async Python SDK for the WGDashboard REST API. Manage WireGuard and AmneziaWG configurations, peers, backups, scheduled jobs, and dashboard settings programmatically.
Features
- Fully async — built on
httpxandasyncio - Type-safe — Pydantic models for all API responses
- Complete API coverage — configurations, peers, backups, jobs, email, system tools
- Pythonic interface — snake_case attributes, context managers, proper exceptions
- Tolerant parsing — handles newer WGDashboard versions adding fields
- Automatic repairs — works around dashboard quirks (e.g., stale peer addresses in the database)
Installation
pip install wgdashboard
Or from source:
git clone https://github.com/zerolink-m/wgdashboardapi.git
cd wgdashboardapi
pip install -e .
Quick Start
import asyncio
from wgdashboard import WGDashboardClient
async def main():
async with WGDashboardClient(
base_url="https://vpn.example.com:10086",
api_key="your-api-key-here"
) as client:
# List all configurations
configs = await client.configurations.list()
for config in configs:
print(f"{config.name}: {config.connected_peers}/{config.total_peers} peers connected")
# Get detailed info about a configuration
info = await client.configurations.get_info("wg0")
print(f"Address: {info.configuration_info.address}")
# List peers
peers = await client.peers.list("wg0")
for peer in peers:
print(f" {peer.name}: {peer.allowed_ip}")
asyncio.run(main())
Authentication
Create an API key in the WGDashboard web interface:
- Navigate to Settings → API Keys
- Click Generate API Key
- Set an expiration date or choose "Never expire"
- Copy the generated key
Pass the key to the client:
client = WGDashboardClient(
base_url="https://vpn.example.com:10086",
api_key="wg_api_abc123..."
)
Configuration
Basic Setup
client = WGDashboardClient(
base_url="https://vpn.example.com:10086",
api_key="your-api-key",
timeout=30.0, # Request timeout in seconds
verify_ssl=True, # Set to False for self-signed certificates
)
Custom HTTP Client
Reuse a connection pool or customize transport:
import httpx
http_client = httpx.AsyncClient(
timeout=60.0,
limits=httpx.Limits(max_connections=10)
)
client = WGDashboardClient(
base_url="https://vpn.example.com:10086",
api_key="your-api-key",
http_client=http_client
)
URL Prefix
If the dashboard is served under a URL prefix:
client = WGDashboardClient(
base_url="https://vpn.example.com:10086",
api_key="your-api-key",
app_prefix="/wgdashboard" # Matches the app_prefix setting
)
Core Concepts
Resources
The client organizes API operations into resource namespaces:
client.configurations— WireGuard/AmneziaWG interfacesclient.peers— Peer management (add, update, restrict, delete)client.backups— Backup and restore configurationsclient.jobs— Scheduled automation (traffic limits, time-based actions)client.dashboard— Dashboard settings, API keys, localizationclient.email— Email peer configurationsclient.system— Host metrics, ping, traceroute
Models
Every response is parsed into a Pydantic model:
config = await client.configurations.get("wg0")
print(config.name) # "wg0"
print(config.listen_port) # 51820
print(config.total_peers) # 12
print(config.connected_peers) # 8
Models use snake_case attributes but accept the API's wire names as aliases:
from wgdashboard import Configuration
# Both work
config = Configuration(ListenPort=51820)
config = Configuration(listen_port=51820)
Exceptions
All exceptions inherit from WGDashboardError:
WGDashboardConnectionError— Network failure, timeoutWGDashboardResponseError— Invalid response formatWGDashboardAuthError— Invalid API key, authentication disabledWGDashboardAPIError— API reported a failureWGDashboardNotFoundError— Configuration or peer not found
from wgdashboard import WGDashboardNotFoundError
try:
peer = await client.peers.get("wg0", "unknown_public_key")
except WGDashboardNotFoundError as e:
print(f"Peer not found: {e}")
Common Operations
Configurations
Create a configuration
await client.configurations.create(
name="wg1",
address="10.0.30.1/24",
listen_port=51821,
private_key="<base64-private-key>",
post_up="iptables -A FORWARD -i wg1 -j ACCEPT",
post_down="iptables -D FORWARD -i wg1 -j ACCEPT"
)
Update a configuration
updated = await client.configurations.update(
"wg0",
listen_port=51822,
post_up="iptables -A FORWARD -i wg0 -j ACCEPT"
)
Toggle a configuration on/off
is_up = await client.configurations.toggle("wg0")
print(f"Configuration is now {'up' if is_up else 'down'}")
Peers
Add a peer
# Let the dashboard generate everything
peers = await client.peers.add("wg0")
# Specify settings
peers = await client.peers.add(
"wg0",
name="laptop",
allowed_ips=["10.0.20.5/32"],
endpoint_allowed_ip="0.0.0.0/0",
dns_addresses="1.1.1.1, 1.0.0.1",
keep_alive=25
)
Add multiple peers at once
peers = await client.peers.add_bulk(
"wg0",
amount=10,
endpoint_allowed_ip="0.0.0.0/0",
dns_addresses="1.1.1.1"
)
Update a peer
await client.peers.update(
"wg0",
peer_id="<peer-public-key>",
name="laptop-updated",
dns="8.8.8.8, 8.8.4.4"
)
Restrict/unrestrict peers
# Block a peer from connecting
await client.peers.restrict("wg0", peer_public_key)
# Allow access again
await client.peers.allow_access("wg0", peer_public_key)
Download peer configuration
config = await client.peers.download("wg0", peer_public_key)
print(config.file_name) # "laptop.conf"
print(config.file) # The .conf file contents
Share a peer configuration
# Create a public share link
link = await client.peers.create_share_link(
"wg0",
peer_public_key,
expire_date="2024-12-31 23:59:59"
)
print(f"Share link: https://vpn.example.com/share/{link.share_id}")
# Anyone with the link can download the config
config = await client.peers.get_shared_peer(link.share_id)
Backups
# Create a backup
backups = await client.backups.create("wg0")
# List backups
backups = await client.backups.list("wg0")
for backup in backups:
print(f"{backup.filename}: {backup.backup_date}")
# Restore a backup
await client.backups.restore("wg0", "wg0_backup_20241001.conf")
Scheduled Jobs
Automate peer actions based on traffic or time:
from wgdashboard import PeerJob
# Restrict a peer after 10 GB of total traffic
job = PeerJob(
configuration="wg0",
peer=peer_public_key,
field="total_data",
operator="lgt", # "less/greater than"
value="10",
action="restrict"
)
await client.jobs.save(job)
# View job execution logs
logs = await client.jobs.get_logs("wg0")
for log in logs:
print(f"{log.log_date}: {log.message}")
# Check if email is configured
if await client.email.is_ready():
# Send a peer's configuration via email
await client.email.send(
receiver="user@example.com",
subject="Your VPN Configuration",
body="Hi {{ peer.name }}, attached is your VPN config.",
configuration="wg0",
peer_id=peer_public_key,
include_attachment=True
)
System Tools
# Get host metrics
status = await client.system.status()
print(f"CPU usage: {status.cpu['percent']}%")
print(f"Memory: {status.memory['used_GB']}/{status.memory['total_GB']} GB")
# Ping from the server
result = await client.system.ping("1.1.1.1", count=4)
print(f"Average RTT: {result.avg_rtt} ms")
print(f"Packet loss: {result.package_loss}%")
# Traceroute
hops = await client.system.traceroute("example.com")
for hop in hops:
print(f"{hop.hop}: {hop.ip} - {hop.avg_rtt} ms")
Advanced Usage
Working with Raw Configuration Files
# Read the raw .conf file
raw = await client.configurations.get_raw_file("wg0")
print(raw.content)
# Modify and write it back (use with caution)
modified = raw.content.replace("ListenPort = 51820", "ListenPort = 51821")
await client.configurations.update_raw_file("wg0", modified)
AmneziaWG Support
# Create an AmneziaWG configuration
await client.configurations.create(
name="awg0",
address="10.0.40.1/24",
listen_port=51823,
private_key="<base64-private-key>",
protocol="awg"
# Obfuscation parameters are auto-generated
)
# Override obfuscation parameters
await client.configurations.create(
name="awg0",
address="10.0.40.1/24",
listen_port=51823,
private_key="<base64-private-key>",
protocol="awg",
advanced={
"Jc": "7",
"Jmin": "50",
"Jmax": "1000",
"H1": "1234567",
"H2": "7654321"
}
)
Error Handling
from wgdashboard import (
WGDashboardConnectionError,
WGDashboardAuthError,
WGDashboardNotFoundError,
WGDashboardAPIError
)
try:
config = await client.configurations.get("wg0")
except WGDashboardConnectionError:
print("Cannot reach the server")
except WGDashboardAuthError:
print("Invalid API key")
except WGDashboardNotFoundError:
print("Configuration wg0 does not exist")
except WGDashboardAPIError as e:
print(f"API error: {e.message}")
print(f"Endpoint: {e.endpoint}")
print(f"Status code: {e.status_code}")
Known Issues
Dashboard ≤ v4.3.3: Backup Endpoints
The server cannot see backups of configurations that still exist, due to a typo in the filename pattern. On affected versions:
backups.create()writes the backup but returns an empty listbackups.list()always returns emptybackups.restore()andbackups.delete()fail
Backups of deleted configurations work correctly via backups.list_all().
Pre-shared Keys and AppArmor
On Debian/Ubuntu with wireguard-tools ≥ 1.0.2025, the wg AppArmor profile blocks pre-shared key operations. Check with:
dmesg | grep 'apparmor.*profile="wg"'
If affected, add an AppArmor rule on the server or disable the profile.
Peer Address Updates
The dashboard applies a changed allowed_ip to the interface and .conf file but never updates its database. The SDK works around this by reading the address from the .conf file in peers.list(), peers.get(), and peers.update().
Requirements
- Python 3.8+
httpx— async HTTP clientpydantic— data validation and parsing
Development
# Clone the repository
git clone https://github.com/zerolink-m/wgdashboardapi.git
cd wgdashboardapi
# Install in development mode
pip install -e .
# Run tests (if available)
pytest
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the Apache-2.0 License — see the LICENSE file for details.
Links
- WGDashboard: https://github.com/donaldzou/WGDashboard
- WireGuard: https://www.wireguard.com/
- AmneziaWG: https://github.com/amnezia-vpn/amneziawg-linux-kernel-module
Acknowledgments
Built for the WGDashboard project by Donald Zou. This SDK is an independent client implementation and is not officially affiliated with WGDashboard.
Metadata
Release files for wgdashboard 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wgdashboard-0.1.1.tar.gz | 37.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wgdashboard-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 71.3 kB
Release files / wgdashboard-0.1.1.tar.gz
| Download URL | wgdashboard-0.1.1.tar.gz |
|---|---|
| Size | 37.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
885d3c89c3887e64d13b1b0a8bafae99529eb46106ac6e3cf529e45f42806404
|
|
BLAKE2b-256 checksum How to use checksums |
5f9a283d635ece0c1f3a7acdb0ec7b6be9008c0bc82cba8bd050a2d9566c95e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / wgdashboard-0.1.1-py3-none-any.whl
| Download URL | wgdashboard-0.1.1-py3-none-any.whl |
|---|---|
| Size | 33.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0e8f787502dd0ff8bb904d6ec01a744273b581d6967d9ed285b0cac3d68d6251
|
|
BLAKE2b-256 checksum How to use checksums |
1ab01a3415b75f304acd4a0dc3cb687542d6ca62379f56acb84ff006197fcf1c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log