No description
  • Python 87.1%
  • HTML 10%
  • CSS 2.3%
  • JavaScript 0.3%
  • Dockerfile 0.3%
Find a file
Kenzi Marcel e8f52bedab
Some checks failed
Container Build / build (push) Successful in 46s
SonarQube / sonarqube (push) Failing after 1m45s
fix: replace bind IP dropdown with free-text input; fix required field error
Servers with private SSH hosts (NAT setups) couldn't enter their public IP
via the dropdown. Replaced it with a plain text input so any IP can be typed.
Empty value still means auto-detect on sync. Fixed SocksBindIpForm defaulting
to "" so saving without a bind IP no longer returns a 422 Field required error.
2026-07-04 14:07:02 +00:00
.forgejo/workflows Revert "ci: harden Forgejo image and Sonar workflows" 2026-05-31 22:29:34 +00:00
app fix: replace bind IP dropdown with free-text input; fix required field error 2026-07-04 14:07:02 +00:00
tests feat: add force remove for unreachable servers 2026-07-04 11:42:42 +00:00
vendor/binaries feat: add HTTP/HTTPS proxy and improve 3proxy deployment 2026-06-07 23:54:02 +00:00
web fix: replace bind IP dropdown with free-text input; fix required field error 2026-07-04 14:07:02 +00:00
.dockerignore feat: add Forgejo container build pipeline 2026-05-29 13:07:53 +00:00
.env.development.example feat: add route config tab and development autoreload env 2026-05-30 07:28:25 +00:00
.env.example feat: add route config tab and development autoreload env 2026-05-30 07:28:25 +00:00
.gitignore feat: improve provisioning UX and management flows 2026-05-29 10:57:41 +00:00
docker-compose.yml feat: add HTTP/HTTPS proxy and improve 3proxy deployment 2026-06-07 23:54:02 +00:00
Dockerfile feat: add HTTP/HTTPS proxy and improve 3proxy deployment 2026-06-07 23:54:02 +00:00
pytest.ini feat: improve provisioning UX and management flows 2026-05-29 10:57:41 +00:00
README.md feat: add HTTP/HTTPS proxy and improve 3proxy deployment 2026-06-07 23:54:02 +00:00
requirements.txt feat: improve provisioning UX and management flows 2026-05-29 10:57:41 +00:00
sonar-project.properties ci: add Forgejo SonarQube analysis workflow 2026-05-31 20:42:54 +00:00

wg-manager

Small panel to manage WireGuard on multiple Debian VPS nodes.

What it does:

  • add servers over SSH
  • provision WireGuard remotely
  • create multi-server devices
  • create one-off single-server profiles
  • download config + gluetun snippet

quick start

cd /root/vpn
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
python -m app.main

Then open http://127.0.0.1:8080.

docker

cp .env.example .env   # set PANEL_SECRET and ADMIN_PASSWORD
mkdir -p data ssh_keys && chown -R 10001:10001 data ssh_keys
docker compose pull && docker compose up -d

Image: git.stackken.com/kenzim/wg-manager:latest. Put VPS SSH keys in ssh_keys/ before use. In Portainer, leave Command and Entrypoint empty (use image defaults), only mount data and ssh_keys — not /app itself.

development (autoreload)

cd /root/vpn
cp .env.development.example .env.development
set -a
source .env.development
set +a
source .venv/bin/activate
python -m app.main

APP_ENV=development or AUTO_RELOAD=true enables uvicorn autoreload.

basic flow

  1. put your VPS SSH key in ssh_keys/ (chmod 600)
  2. add server
  3. click provision
  4. add device or one-off profile
  5. sync
  6. download config

routing & NAT

Clients reach LANs behind a server via route groups (Route Config tab):

  • a server can be a full internet exit, a LAN/subnet gateway, or both
  • route groups bundle CIDRs and can be imported from the ZeroTier legacy API
  • give a route group a NAT interface to auto-apply iptables on the server: iptables -t nat -A POSTROUTING -s <wg-subnet> -o <iface> -j MASQUERADE
  • use the zt+ wildcard for ZeroTier (interface names are hashed per-network); ZeroTier imports default to zt+
  • the same rules also ACCEPT client traffic to the server's own overlay IPs, so you can still reach the server's ZeroTier address under a default-DROP INPUT policy

NAT rules are baked into the wg0 PostUp/PostDown at provision time (persisted across reboots) and applied/removed live when a group is attached to or detached from an already-provisioned server. Re-provision to persist groups attached after the initial provision across reboots.

SOCKS5 proxy

Optional authenticated SOCKS5 on each server (public bind IP):

  1. open the SOCKS Proxy tab
  2. create a global SOCKS user (assign to all or selected servers) and/or a server-only user
  3. per server: enable SOCKS, set bind IP and port, click Sync SOCKS
  4. connect with socks5://username:password@bind-ip:port (independent of WireGuard)

Sync installs 3proxy over SSH (from apt when packaged, otherwise uploads a bundled linux-amd64 binary) and opens an iptables INPUT rule for the chosen bind address.

Pytest

pytest

Latest local run: 36.61% total coverage.

Coverage breakdown (auto-updated by pytest):

File Coverage
app/dashboard_state.py 13.08%
app/ssh_ops.py 22.22%
app/services.py 26.38%
app/socks_ops.py 29.11%
app/wg_config.py 29.31%
app/routes/web.py 30.72%
app/wg_keys.py 38.1%
app/routes/api.py 46.61%
app/security.py 53.5%
app/auth.py 56.38%
app/logging_config.py 66.67%
app/main.py 68.18%
app/db.py 80%
app/middleware.py 93.33%
app/deps.py 94.44%
app/config.py 96.97%
app/__init__.py 100%
app/forms.py 100%
app/routes/__init__.py 100%
app/wg_defaults.py 100%