{"id":51649673,"url":"https://github.com/gen1nya/wg-admin","last_synced_at":"2026-07-14T02:32:32.438Z","repository":{"id":364384116,"uuid":"1247096649","full_name":"gen1nya/wg-admin","owner":"gen1nya","description":"Self-hostable web UI and host-side agent for native WireGuard, with declarative exit/routing management","archived":false,"fork":false,"pushed_at":"2026-06-12T21:16:37.000Z","size":190,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-12T21:24:46.787Z","etag":null,"topics":["go","policy-based-routing","self-hosted","sqlite","vpn","vue","wg-easy-alternative","wg-quick","wireguard"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gen1nya.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-22T22:38:48.000Z","updated_at":"2026-06-12T21:19:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gen1nya/wg-admin","commit_stats":null,"previous_names":["gen1nya/wg-admin"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/gen1nya/wg-admin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gen1nya%2Fwg-admin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gen1nya%2Fwg-admin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gen1nya%2Fwg-admin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gen1nya%2Fwg-admin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gen1nya","download_url":"https://codeload.github.com/gen1nya/wg-admin/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gen1nya%2Fwg-admin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35443979,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-14T02:00:06.603Z","response_time":114,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","policy-based-routing","self-hosted","sqlite","vpn","vue","wg-easy-alternative","wg-quick","wireguard"],"created_at":"2026-07-14T02:32:30.856Z","updated_at":"2026-07-14T02:32:32.416Z","avatar_url":"https://github.com/gen1nya.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# wg-admin\n\nSelf-hostable web UI and host-side agent for managing native WireGuard\ninterfaces and their routing. Built to replace `wg-easy` plus a pile of\nhand-written split-routing shell scripts with one declarative system.\n\n## Goals\n\n1. Manage peers from the web UI and CLI (create, delete, download `.conf`).\n2. Model \"where traffic goes\" as a first-class entity (`exit`), so clients\n   can be switched between exits declaratively (direct / EU tunnel / etc).\n3. Keep the source of truth in **SQLite on the agent** — WireGuard configs,\n   `iptables`/`nft` rules, and `ipset` entries are derived artifacts.\n4. Make kernel changes safe via a two-phase **`plan → apply (+watchdog) →\n   confirm`** flow: a misapplied change is automatically rolled back if you\n   don't confirm it in time.\n5. Drop the `wg-easy` Docker overhead and reduce script entropy.\n\n## Architecture\n\n```\n   browser / CLI\n        │\n        ▼\n   ┌─────────────────────┐\n   │   wg-admin app      │  Node + Vue 3 SPA, stateless\n   │   (HTTPS, auth)     │\n   └──────────┬──────────┘\n              │ unix socket /run/wg-agent.sock (X-Actor from session)\n              ▼\n   ┌─────────────────────┐\n   │   wg-agent          │  Go daemon, runs on the host\n   │   (SQLite + kernel) │  owns wg / ip / ipset / nft\n   └──────────┬──────────┘\n              ▼\n        kernel state\n```\n\n- **`app/`** — Node 22 + Express + Vue 3 + Vite SPA. Pure frontend; no\n  business logic. Proxies `/api/*` to the agent's unix socket and attaches\n  the authenticated user as `X-Actor` so the agent can audit per-user.\n- **`agent/`** — Go daemon. Owns `/var/lib/wg-admin/state.db` (SQLite) and\n  exposes an HTTP API over `unix:/run/wg-agent.sock`. Has a mock kernel\n  mode for local development without root.\n\nPer-host state: each agent has its own local `state.db`. Mesh links\nbetween hosts have to be registered on **both** endpoints (each agent\nkeeps its own peer database).\n\n## Status\n\nSkeleton, working end-to-end against the mock kernel. Real-kernel mode\n(`wg`/`ip`/`ipset`/`nft` actually applied) is being stood up.\n\n- Frontend: all 8 spec pages closed, `npm run lint` clean, `npm test` 31\n  green, `npm audit` 0 vulnerabilities, SPA ~155 KB gzipped.\n- Agent: HTTP API, store, plan/apply/confirm engine, importer for\n  existing `/etc/wireguard` backups, renderer for client `.conf` output.\n\n## Quick start (dev, mock kernel)\n\n```sh\n# Terminal 1: agent\ncd agent\ngo mod tidy\ngo run ./cmd/wg-agent daemon -mock \\\n  -socket /tmp/wg-agent.sock \\\n  -db     /tmp/wg-admin-state.db\n\n# Terminal 2: app\ncd app\ncp dev-app.conf.example dev-app.conf\n# generate password hash and put it into dev-app.conf\nnpx tsx server/hash-cli.ts 'your-dev-password'\nnpm install\nnpm run dev\n# open http://127.0.0.1:5173/, login with admin / your-dev-password\n```\n\nIn another terminal you can also hit the agent directly:\n\n```sh\ncurl --unix-socket /tmp/wg-agent.sock http://unix/status\ncurl --unix-socket /tmp/wg-agent.sock http://unix/interfaces\n```\n\n## Running tests\n\n```sh\n# Go agent\ncd agent \u0026\u0026 go test ./...\n\n# Node app (unit tests)\ncd app \u0026\u0026 npm test\n\n# Importer end-to-end against a real /etc/wireguard backup\n# (skipped if env var is not set; set it to point at the dir)\nexport WG_ADMIN_IMPORTER_FIXTURE=/path/to/etc-wireguard-backup\ncd agent \u0026\u0026 go test ./internal/importer/...\n```\n\n## Layout\n\n```\nagent/\n  cmd/wg-agent/     entrypoint and subcommand dispatch\n  internal/\n    api/            HTTP handlers\n    auth/           token auth, X-Actor extraction\n    devseed/        dev-mode DB seed (mock interfaces and exits)\n    importer/       /etc/wireguard backup → DB\n    kernel/         kernel abstraction (real + mock impls)\n    model/          record types\n    plan/           plan/apply/confirm engine\n    reconcile/      post-boot heal: kernel ← DB\n    renderer/       DB row → client .conf text\n    server/         unix socket listener\n    store/          SQLite + migrations\n    wgconf/         WireGuard config file parsing\n    wgkey/          curve25519 keypair generation\n  systemd/          wg-agent.service unit\napp/\n  server/           Node/Express: auth, /api proxy, hash CLI\n  src/              Vue 3 SPA (pages, components, API client)\n  systemd/          wg-admin-app.service unit\n```\n\n## Design notes\n\n- **API first, never direct SQL.** Peers, interfaces, and plans go through\n  the HTTP API only (`POST /interfaces/{name}/peers`, `GET /peers/{id}/config`,\n  the `/plan` flow). Mutating the SQLite file by hand desynchronizes DB ↔\n  kernel ↔ on-disk WireGuard configs.\n- **Plan → apply → confirm.** Any state change that touches the kernel\n  produces a plan diff (`ipsets`/`routes`/`rules`/`nft`). Apply sets a\n  watchdog timer; if you don't `POST /plans/{id}/confirm` within the\n  timeout, the change is auto-reverted. This prevents one-click outages.\n- **Per-host state, no central DB.** Each agent owns its own `state.db`.\n  Mesh links must be registered on both ends. There is intentionally no\n  master / cluster.\n\n## License\n\nMIT — see `LICENSE`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgen1nya%2Fwg-admin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgen1nya%2Fwg-admin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgen1nya%2Fwg-admin/lists"}