{"id":50559129,"url":"https://github.com/vhscom/birdcage","last_synced_at":"2026-06-04T10:30:31.612Z","repository":{"id":345031590,"uuid":"1184138416","full_name":"vhscom/birdcage","owner":"vhscom","description":"Secure remote access for personal AI","archived":false,"fork":false,"pushed_at":"2026-04-02T06:45:26.000Z","size":1278,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-02T20:20:43.903Z","etag":null,"topics":["acme","go","remote-access","reverse-proxy","security","self-hosted","single-user","wireguard"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vhscom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","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-03-17T09:40:19.000Z","updated_at":"2026-04-01T00:45:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vhscom/birdcage","commit_stats":null,"previous_names":["vhscom/birdcage"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/vhscom/birdcage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vhscom%2Fbirdcage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vhscom%2Fbirdcage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vhscom%2Fbirdcage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vhscom%2Fbirdcage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vhscom","download_url":"https://codeload.github.com/vhscom/birdcage/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vhscom%2Fbirdcage/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33901305,"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-06-04T02:00:06.755Z","response_time":64,"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":["acme","go","remote-access","reverse-proxy","security","self-hosted","single-user","wireguard"],"created_at":"2026-06-04T10:30:30.854Z","updated_at":"2026-06-04T10:30:31.604Z","avatar_url":"https://github.com/vhscom.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# birdcage\n\nSecure remote access layer for personal AI. One user, one claw, accessible from any browser, privately.\n\n[![CI](https://img.shields.io/github/actions/workflow/status/vhscom/birdcage/ci.yml?style=for-the-badge\u0026label=CI)](https://github.com/vhscom/birdcage/actions/workflows/ci.yml)\n[![OpenClaw](https://img.shields.io/badge/OpenClaw-2026.4.2-C83232?style=for-the-badge)](https://github.com/openclaw/openclaw)\n[![Go](https://img.shields.io/badge/Go-1.26+-00ADD8?style=for-the-badge\u0026logo=go\u0026logoColor=white)](https://go.dev/)\n[![License](https://img.shields.io/badge/License-AGPL_3.0-blue?style=for-the-badge)](COPYING)\n\n```\nBrowser ──────► Birdcage (VPS) ────► OpenClaw (home)\n        cookie  auth + proxy   mesh  WireGuard agent\n```\n\nA claw is a local AI assistant like [OpenClaw](https://github.com/openclaw/openclaw) running on your home machine. Birdcage lets you reach it from anywhere after authenticating. Traffic is encrypted over WireGuard — your claw never touches the public internet.\n\n![Screenshot](docs/screenshot.png)\n\nSee the [demo video](docs/demo.mp4) for a walkthrough.\n\n## Quick start\n\nPoint a DNS A record to your VPS (DNS-only, not proxied). Open ports 443, 80, and 51820/udp.\n\n**Build** (on the VPS, or cross-compile with `GOOS=linux GOARCH=amd64`):\n\n```sh\ngit clone https://github.com/vhscom/birdcage.git \u0026\u0026 cd birdcage\ngo build -o birdcage .\nsudo mv birdcage /usr/local/bin/\n```\n\n**On the VPS:**\n\n```sh\napt install -y wireguard-tools\nmkdir -p /opt/birdcage \u0026\u0026 cd /opt/birdcage\nbirdcage init                    # prompts for BASE_URL and WG endpoint\nsudo birdcage serve install      # installs and starts as a system service\n```\n\n**On the home machine:**\n\n```sh\n# macOS\nbrew install wireguard-tools wireguard-go\n\n# Linux\napt install -y wireguard-tools\n\n# then\nbirdcage agent init https://your-domain.example.com \u003cagent-key\u003e\nsudo birdcage agent install\n```\n\n**Connect the gateway:** Configure your claw's gateway token, then edit `/opt/birdcage/.env` on the VPS:\n\n```sh\nGATEWAY_URL=http://10.0.0.2:18789     # claw's mesh address\nGATEWAY_TOKEN=\u003ctoken from your claw\u003e  # gateway auth token\n```\n\nRestart: `sudo systemctl restart birdcage`.\n\nOpen `https://your-domain.example.com` in a browser and register with the token printed during init.\n\n## What it does\n\n**Auth layer** — Token-gated registration (single owner), login with PBKDF2-SHA384 (210K iterations), adaptive proof-of-work on brute force, JWT dual-token pattern with refresh token rotation and reuse detection, session management with sliding expiry, OWASP security headers.\n\n**Control proxy** — HTTP reverse proxy and WebSocket bridge to the claw's web UI. Strips credentials before forwarding, injects gateway token and operator scopes into WebSocket connect frames.\n\n**WireGuard mesh** — Server provisions its own WireGuard interface and coordinates peers. Agent runs at home alongside the claw, manages WireGuard, discovers endpoints via STUN, falls back to relay when direct UDP fails, rotates keys on a configurable interval.\n\n**Ops API + TUI** — REST endpoints and an interactive terminal dashboard (`birdcage ctl`) for managing sessions, events, agent credentials, and mesh nodes. Includes cloak mode: when active, all ops and WebSocket endpoints return plain 404 to public IPs while WireGuard mesh addresses pass through unconditionally. Cloak auto-engages on attack (auth failures, TLS probes, rate-limit hits) and is on by default. See [ops documentation](docs/ops.md).\n\n## CLI\n\n```\nbirdcage init                          Generate server config (.env)\nbirdcage serve                         Start the server\nbirdcage serve install                 Install as system service\nbirdcage serve uninstall               Remove system service\nbirdcage agent                         Run the WireGuard mesh agent\nbirdcage agent init \u003cserver\u003e \u003ckey\u003e     Save agent config\nbirdcage agent install                 Install as system service\nbirdcage agent uninstall               Remove system service\nbirdcage ctl                           Open the management TUI\n```\n\n## Building\n\nRequires Go 1.26+.\n\n```sh\ngo build -o birdcage .\n```\n\nSingle binary, pure Go, no CGO.\n\n## TLS\n\nWhen `BASE_URL` starts with `https://`, Birdcage automatically obtains a TLS certificate from Let's Encrypt. No reverse proxy needed.\n\n- Listens on `:443` (HTTPS) and `:80` (ACME HTTP-01 challenges + redirect)\n- Renews the certificate ~30 days before expiry\n- Stores certificates in `./certs` (override with `CERT_DIR`)\n- Falls back to TLS-ALPN-01 if port 80 is unavailable\n\nRequirements: DNS A/AAAA record pointing to the server, ports 443 and 80 available.\n\nFor local development, use `BASE_URL=http://localhost:8080` (the default).\n\n## Safe deployment\n\n- **Keep generated secrets.** `birdcage init` generates 256-bit secrets and a registration token. Don't replace them with weaker values. The server refuses to start if JWT secrets are under 32 characters.\n\n## Design principles\n\n- **Single user, single purpose.** No multi-tenancy, no admin roles, no user management beyond the owner.\n- **Privacy by architecture.** Oauth-free. Traffic between the VPS and your home machine is encrypted via WireGuard.\n- **One binary.** Server, agent, CLI — same executable, different subcommands.\n- **No magic.** `birdcage init` shows you what it creates. `birdcage serve` does what it says. One `.env`, one database.\n- **Secure by default.** HTTPS is automatic. Cookies are SameSite=Strict. Headers are OWASP. PoW activates under brute force. Cloak mode auto-engages on attack and hides the ops surface from public IPs.\n\n## Documentation\n\n- [Ops API and TUI](docs/ops.md) — REST endpoints, WebSocket ops, management TUI\n- [Auth flows](docs/flows.md) — sequence diagrams for every authentication path\n- [Threat model](docs/threat-model.md) — STRIDE analysis and JWT pitfall catalogue\n\n## License\n\nAGPL-3.0 — see [COPYING](COPYING).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvhscom%2Fbirdcage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvhscom%2Fbirdcage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvhscom%2Fbirdcage/lists"}