{"id":48995750,"url":"https://github.com/wagga40/wireconf","last_synced_at":"2026-04-18T17:00:51.482Z","repository":{"id":349817619,"uuid":"1203397275","full_name":"wagga40/Wireconf","owner":"wagga40","description":"Bash-only WireGuard hub-and-spoke bootstrap for Debian/Ubuntu. Like Tailscale, but powered solely by optimism, duct tape, and bash scripts.","archived":false,"fork":false,"pushed_at":"2026-04-18T15:32:19.000Z","size":127,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-18T16:25:30.544Z","etag":null,"topics":["cli-tool","mesh-vpn","ubuntu","wireguard","wireguard-vpn"],"latest_commit_sha":null,"homepage":"https://github.com/wagga40/Wireconf","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wagga40.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-04-07T02:18:59.000Z","updated_at":"2026-04-18T15:32:21.000Z","dependencies_parsed_at":"2026-04-18T17:00:38.367Z","dependency_job_id":null,"html_url":"https://github.com/wagga40/Wireconf","commit_stats":null,"previous_names":["wagga40/wireconf"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/wagga40/Wireconf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wagga40%2FWireconf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wagga40%2FWireconf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wagga40%2FWireconf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wagga40%2FWireconf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wagga40","download_url":"https://codeload.github.com/wagga40/Wireconf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wagga40%2FWireconf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31976805,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T16:27:12.723Z","status":"ssl_error","status_checked_at":"2026-04-18T16:27:11.140Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["cli-tool","mesh-vpn","ubuntu","wireguard","wireguard-vpn"],"created_at":"2026-04-18T17:00:33.397Z","updated_at":"2026-04-18T17:00:51.463Z","avatar_url":"https://github.com/wagga40.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"docs/wireconf-logo.svg\" alt=\"Wireconf logo\" width=\"480\" /\u003e\n\u003c/div\u003e\n\n# Wireconf\n\nBash-only WireGuard **hub-and-spoke** bootstrap for Debian/Ubuntu. \nLike Tailscale, but powered solely by optimism, duct tape, and bash scripts.\n\nFirst host in an inventory becomes the hub; the rest become peers. Remote hosts are configured over SSH.\n\n```mermaid\nflowchart LR\n  Wireconf\n  Hub[Hub]\n  Peer1[Peer 1]\n  Peer2[Peer 2]\n  PeerN[Peer N...]\n  Wireconf --\u003e|SSH| Hub\n  Hub \u003c--\u003e|WireGuard| Peer1\n  Hub \u003c--\u003e|WireGuard| Peer2\n  Hub \u003c--\u003e|WireGuard| PeerN\n\n```\n\n## Install\n\nPick one:\n\n### Bash one-liner \n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/wagga40/Wireconf/main/scripts/install.sh | bash\n```\n\nDownloads the latest single-file release, verifies its SHA-256, and installs it to `/opt/wireconf/wireconf` (override with `WIRECONF_PREFIX=$HOME/.local bash`). Add `/opt/wireconf` to your `PATH` if it is not already there. Keep wireconf up to date later with `wireconf update`.\n\n### Git\n\n```bash\ngit clone https://github.com/wagga40/Wireconf.git \u0026\u0026 cd Wireconf\n./wireconf -V                    # run straight from the checkout\n```\n\n## Quick start\n\n```bash\nwireconf init                  # 1. Scaffold inventory + wireconf.env in the current directory\n```\n\nEdit the `inventory` file — place the hub on line 1, and list peers below:\n\n```text\nroot@hub.example.com no\nubuntu@peer1.example.com 2222 no\nroot@peer2.example.com yes\n```\n\n**(Optional)**  Edit `wireconf.env` — set `WG_HUB_ENDPOINT` to the hub's public IP or DNS name if it differs from the host portion of the first line in `inventory`:\n\n```bash\nWG_HUB_ENDPOINT=203.0.113.10\n```\n\nThen deploy:\n\n```bash\nwireconf plan                  # 2. Check SSH, OS, tools, and show IP layout\nwireconf apply                 # 3. Generate keys, upload configs, bring up tunnels\nwireconf verify                #    Confirm handshakes and hub→peer pings\n```\n\nFor a one-shot run use `wireconf up`, which chains `plan + apply + verify` and accepts hosts inline (no inventory file needed):\n\n```bash\nwireconf up                                    # uses ./inventory if present\nwireconf up root@hub.example.com root@peer1    # no inventory file; stateless run\n```\n\nThe `wireconf.env` file in the current directory is loaded automatically. To use a different file, run: `wireconf -e /path/to/wireconf.env plan`. Use `-y` to skip all interactive prompts (for CI/scripts).\n\nReplace `wireconf` with `./wireconf` in every example if you are running from a checkout rather than an installed binary.\n\n## Preparing hosts\n\nOn brand-new servers you usually need three things before `apply` can work: key-based SSH, passwordless `sudo`, and WireGuard userspace tools. Wireconf has two commands for this:\n\n```bash\nwireconf doctor                # auto-detects ./inventory (or pass inline hosts)\nwireconf doctor root@hub.example.com root@peer1     # one-off diagnostic\n```\n\n`doctor` runs every preflight check non-fatally and prints an exact fix command for each failure (DNS, TCP, SSH host key, key auth, passwordless sudo, Debian/Ubuntu OS, required tools, and the kernel WireGuard module).\n\n```bash\nwireconf bootstrap                                  # uses ./inventory if present\nwireconf bootstrap root@hub.example.com root@peer1  # inline hosts\n```\n\n`bootstrap` is idempotent and performs three steps per host, skipping each one when it is already satisfied:\n\n1. `ssh-copy-id` (prompts once on `/dev/tty` for the target password if needed).\n2. `/etc/sudoers.d/wireconf-\u003cuser\u003e` NOPASSWD drop-in, validated with `visudo -cf`. Skipped when the SSH user is `root` or `sudo -n` already works.\n3. `apt-get install -y wireguard` (Debian-family). Skipped when `wg`/`wg-quick` are already installed.\n\nTypical first-time flow:\n\n```bash\nwireconf bootstrap root@hub.example.com root@peer1 root@peer2\nwireconf doctor root@hub.example.com root@peer1 root@peer2\nwireconf up root@hub.example.com root@peer1 root@peer2\n```\n\n## Commands\n\nListed in typical lifecycle order. Run `./wireconf -h` for the full flag list.\n\n| Command | What it does |\n|---------|-------------|\n| `init` | Copy example files into the current directory (never overwrites existing files). |\n| `bootstrap [HOST...]` | Idempotent `ssh-copy-id` + `/etc/sudoers.d/` NOPASSWD drop-in + `apt install wireguard`. Sequential (may prompt for passwords). |\n| `doctor [HOST...]` | Non-fatal preflight report (DNS, TCP, SSH, sudo, OS, tools, wg module) with exact fix commands per host. |\n| `plan` | Validate SSH, OS, tools on every host; show VPN IP layout and preflight status. |\n| `up [HOST...]` | One-shot: `plan` + `apply` + `verify`. Inline `HOST` args skip the inventory file (stateless). |\n| `show` | Generate configs and print to stdout without deploying. Add `--redact` to hide private keys. |\n| `apply` | Run all `plan` checks, then deploy configs and bring up tunnels. Prompts on a TTY; `-y` skips. |\n| `verify` / `test` | Check handshakes, hub→peer pings, print ASCII topology. Exits on first failure. |\n| `status` | Non-fatal health check: interface state, handshake freshness, pings. Reports all issues. |\n| `add-peer HOST [PORT] [TUNNEL]` | Append a peer line to the inventory (same as editing the file by hand). |\n| `remove-peer HOST` | Remove a peer line from the inventory. Cannot remove the hub. |\n| `teardown` | Stop and disable WireGuard on all inventory hosts. `-f` also removes config files. |\n| `clean` | Delete local `inventory`, `*.wireconf.*` sidecars, and `wireconf.env`. Prompts first; `-y` skips. |\n| `update` | Fetch the latest single-file release from GitHub, verify SHA-256, replace the running binary. Single-file installs only. |\n\nAfter adding or removing peers, run `plan` then `apply` to push the change.\n\n### Updating\n\nFor single-file installs (the `curl \\| bash` path), run:\n\n```bash\nwireconf update                                # fetch latest, verify sha256, replace binary\nWIRECONF_VERSION=v0.3.1 wireconf update        # pin a specific tag\nWIRECONF_REPO=owner/fork wireconf update       # pull from a fork\nWIRECONF_VERIFY=0 wireconf update              # skip checksum (discouraged)\n```\n\n`wireconf update` refuses to run from a source checkout — use `git pull` or `task install` / `task dist-install` for those layouts.\n\n## Inventory format\n\nOne host per line. `#` comments and blank lines are ignored. Duplicate hosts are rejected.\n\n```text\nHOST [SSH_PORT] [FULL_TUNNEL]\n```\n\n- **HOST** — `user@host` or bare hostname (SSH target). Use `localhost` or `127.0.0.1` for a local hub.\n- **SSH_PORT** — optional; numeric second field overrides the default (`SSH_PORT` / `-S`, default 22).\n- **FULL_TUNNEL** — `yes` or `no`; defaults to `FULL_TUNNEL_DEFAULT`.\n\nVPN addresses follow line order: hub gets `.1`, first peer `.2`, and so on. Reordering lines changes IP assignments. Each `apply` regenerates all WireGuard keys.\n\n## Configuration\n\nCore settings live in `wireconf.env` (auto-loaded) or as CLI flags. See `./wireconf -h` for short flags.\n\n| Setting | Default | Purpose |\n|---------|---------|---------|\n| `INVENTORY` / `--inventory` / `-I` | `inventory` | Path to the host list |\n| `WG_INTERFACE` / `--iface` / `-n` | `wg0` | Interface and systemd unit name (1–15 chars) |\n| `WG_NETWORK` / `--network` / `-c` | `10.200.0.0/24` | VPN IPv4 CIDR (`/16`–`/30`, must fit all usable host addresses) |\n| `WG_PORT` / `--port` / `-p` | `51820` | Hub UDP listen port |\n| `WG_HUB_ENDPOINT` / `-H` | *(hub host, SSH user stripped)* | Public address peers use for `Endpoint=` |\n| `AUTO_START` / `--auto-start` / `-a` | `yes` | Enable `wg-quick@` on boot |\n| `FULL_TUNNEL_DEFAULT` / `-t` | `no` | Default full-tunnel mode for inventory lines |\n| `WG_KEEPALIVE` / `--keepalive` / `-k` | `25` | PersistentKeepalive seconds (0 = off) |\n| `SSH_PORT` / `--ssh-port` / `-S` | `22` | Default SSH port when not set per line |\n\n\u003cdetails\u003e\n\u003csummary\u003eMore settings\u003c/summary\u003e\n\n| Setting | Default | Purpose |\n|---------|---------|---------|\n| `WG_HUB_EGRESS` | *(auto)* | Hub egress interface for NAT; detected from default route if unset |\n| `WG_MTU` | *(none)* | MTU for all WireGuard interfaces |\n| `WG_PEER_DNS` | *(none)* | `DNS=` pushed to full-tunnel peers |\n| `WG_SPLIT_DNS` | *(none)* | `DNS=` pushed to split-tunnel peers |\n| `WG_HANDSHAKE_TIMEOUT` | `300` | Stale-handshake threshold in seconds for `verify`/`status` |\n| `SSH_ACCEPT_NEW` / `--ssh-accept-new` | `no` | Auto-add new SSH host keys (`StrictHostKeyChecking=accept-new`) |\n| `SSH_OPTS` | *(none)* | Extra `ssh`/`scp` options (don't add `-p`; use `SSH_PORT`) |\n| `--parallel` / `WG_PARALLEL` | `1` | Concurrent SSH operations during `apply` (1–64) |\n| `--force` / `-f` | — | Overwrite existing WireGuard state; with `teardown`, also removes configs |\n| `--backup-dir` / `-b` | — | Copy existing configs before replacing |\n| `--redact` | — | With `show`, omit `PrivateKey` lines from stdout |\n| `WIRECONF_YES` / `-y` | — | Skip all confirmation prompts |\n| `--env-file` / `-e` | `./wireconf.env` | Explicit env-file path (overrides auto-load) |\n\n\u003c/details\u003e\n\n## Requirements\n\n**Operator machine** (where you run `./wireconf`): `bash`, `openssh-client`, `awk`. `wg` is optional — if missing locally, keys are generated on the hub over SSH.\n\n**Every target host**: Debian/Ubuntu with `wireguard-tools`, `systemd`, `iproute2`, `ping`. Hub also needs `iptables` when any peer uses full-tunnel. Missing `wireguard-tools` on a target can be installed interactively during `plan`/`apply` (or automatically with `-y`).\n\n**SSH access**: key-based authentication to all non-local hosts; `sudo -n` must work without a password.\n\n## Safety and re-runs\n\n- `apply` is **re-runnable**. Changed inventory lines trigger per-host prompts instead of a blanket \"Proceed?\". Use `-y` to skip prompts in scripts.\n- Hosts **removed** from the inventory since the last `apply` are automatically torn down (same as `teardown`) before new configs are deployed.\n- Every mutating command (`apply`, `teardown`, `add-peer`, `remove-peer`) appends to `INVENTORY.wireconf.log`, an action log used for change detection.\n- Use `--backup-dir DIR` to save existing configs before replacing them.\n\n## Security notes\n\n- Treat `wireconf.env` and `inventory` like credentials — the env file is `source`d by bash. Keep both out of version control with your own `.gitignore` rules.\n- Hub `PostUp`/`PostDown` run under a shell on the server; interface-name validation prevents command injection.\n- `SSH_OPTS` is word-split into `ssh`/`scp` arguments; avoid putting secrets there.\n\n## Limits\n\n- IPv4 only for this version.\n- Hub **PostUp** uses `iptables` MASQUERADE when any peer is full-tunnel; hosts without `iptables` need manual adjustment.\n- Open the hub's **UDP** `WG_PORT` toward the Internet.\n\n## License\n\nUse and modify as you see fit for your infrastructure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwagga40%2Fwireconf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwagga40%2Fwireconf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwagga40%2Fwireconf/lists"}