From 817b7c409c86e97c45ea696b6d7dde282039fb47 Mon Sep 17 00:00:00 2001 From: Mike Teehan Date: Sat, 9 May 2026 20:56:32 +0000 Subject: [PATCH] Show all missing env vars with usage when install.sh is run without required variables --- README.md | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++ install.sh | 23 ++++++++-- 2 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 README.md mode change 100644 => 100755 install.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..802150a --- /dev/null +++ b/README.md @@ -0,0 +1,123 @@ +# Vacuum Wall + +A zone-based firewall appliance with a built-in SSL reverse proxy. Combines firewalld policy control, DHCP/DNS, WireGuard VPN, and automated certificate provisioning into a single device managed through one web UI. + +## Tech Stack + +- Debian 13 (trixie) target platform +- Python 3.13+, Flask 3.x web UI +- firewalld (nftables backend), dnsmasq, nginx, WireGuard +- acme.sh for Let's Encrypt +- HTMX + Jinja2 templates + +--- + +## For Operators + +### Prerequisites + +- Clean Debian 13 system with root access +- git installed +- One public-facing NIC (external) and at least one LAN NIC (internal) +- A DNS A record pointing to the appliance's public IP for the management domain +- Minimum hardware: 1 CPU, 512 MB RAM, 4 GB disk + +### Install + +```bash +MGMT_DOMAIN=wall.example.com \ +MGMT_PASS="strongpassword" \ +MGMT_USER="admin" \ +ACME_EMAIL="admin@example.com" \ +bash install.sh +``` + +| Variable | Required | Description | +|---|---|---| +| `MGMT_DOMAIN` | Yes | Public domain for the management WebUI | +| `MGMT_PASS` | Yes | HTTP basic auth password for the WebUI | +| `MGMT_USER` | No | WebUI username (defaults to `admin`) | +| `ACME_EMAIL` | Yes | Let's Encrypt registration email | + +After installation, access the WebUI at `https://`. The initial certificate is self-signed — use the Certs tab to issue a real one once DNS is propagating. + +### Next Steps + +1. **Assign interfaces** to zones from the Interfaces tab +2. **Configure DHCP** ranges for your LAN +3. **Add proxy domains** with Let's Encrypt certificates +4. **Set up WireGuard** (optional) + +See [docs/deployment.md](docs/deployment.md) for the full guide, including troubleshooting. + +--- + +## For Developers + +### Local Development + +```bash +git clone && cd vacuum-wall +python3 -m venv .venv && . .venv/bin/activate +pip install -e ".[dev]" +``` + +Start the WebUI locally (binds to 127.0.0.1:9090): + +```bash +.venv/bin/python webui/server.py +``` + +### Lint and Format + +```bash +.venv/bin/ruff check lib/ webui/ tests/ +.venv/bin/ruff format lib/ webui/ tests/ +``` + +### Tests + +```bash +.venv/bin/python -m pytest tests/ -v +``` + +Tests mock all subprocess calls (firewalld, acme.sh, WireGuard, nginx, dnsmasq) — no system services required. + +### Documentation MCP Server + +This project uses `docs-mcp-server` for grounded, real-time documentation lookups during development. + +```bash +pipx install docs-mcp-server +docs-mcp init +``` + +Then run with Claude Code or Opencode to activate it. It automatically checks live docs before answering technical questions — no manual doc search needed. + +### Architecture + +``` +Client ──→ nginx (SSL + basic auth) ──→ Flask (127.0.0.1:9090) +Flask ──→ lib/*.py ──→ sudo ──→ system service +``` + +| Blueprint | URL prefix | Backend module | +|---|---|---| +| `webui/api/firewall` | `/api/firewall/` | `lib.firewall` | +| `webui/api/dhcp` | `/api/dhcp/` | `lib.dnsmasq` | +| `webui/api/proxy` | `/api/proxy/` | `lib.nginx` | +| `webui/api/certs` | `/api/certs/` | `lib.acme` | +| `webui/api/wireguard` | `/api/wireguard/` | `lib.wireguard` | + +See [docs/architecture.md](docs/architecture.md) for detailed request flow and zone model. + +--- + +## Documentation + +- [Overview](docs/overview.md) — Feature summary and tech stack +- [Deployment Guide](docs/deployment.md) — Full installation and post-install configuration +- [Architecture](docs/architecture.md) — Request flow, subsystems, zone model +- [API Reference](docs/api.md) — REST API endpoints +- [Security Model](docs/security.md) — Privilege model and sudo whitelist +- [Configuration](docs/config.md) — Declarative config file formats and locations diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 54ad3dc..c0972a4 --- a/install.sh +++ b/install.sh @@ -15,10 +15,27 @@ err() { echo -e "${RED}[!!]${NC} $*"; exit 1; } PROJECT_DIR="/home/wall/vacuum-wall" USER_NAME="vacuum-wall" USER_HOME="/home/$USER_NAME" -DOMAIN="${MGMT_DOMAIN:?ERROR: Set MGMT_DOMAIN env var (e.g., wall.lan)}" +# --- Validate required env vars --- +missing=() +[[ -z "${MGMT_DOMAIN:-}" ]] && missing+=(MGMT_DOMAIN) +[[ -z "${MGMT_PASS:-}" ]] && missing+=(MGMT_PASS) +[[ -z "${ACME_EMAIL:-}" ]] && missing+=(ACME_EMAIL) + +if (( ${#missing[@]} )); then + echo -e "${RED}[!!]${NC} Missing required environment variables:" + for v in "${missing[@]}"; do + case "$v" in + MGMT_DOMAIN) echo ' export MGMT_DOMAIN="wall.lan" # Management UI hostname';; + MGMT_PASS) echo ' export MGMT_PASS="your-password" # WebUI basic auth password';; + ACME_EMAIL) echo " export ACME_EMAIL=\"you@example.com\" # Let's Encrypt email";; + esac + done + printf '\nTo run: MGMT_DOMAIN=wall.lan MGMT_PASS=pass ACME_EMAIL=you@example.com ./install.sh\n' + exit 1 +fi + +DOMAIN="$MGMT_DOMAIN" MGMT_USER="${MGMT_USER:-admin}" -MGMT_PASS="${MGMT_PASS:?ERROR: Set MGMT_PASS env var for WebUI basic auth}" -ACME_EMAIL="${ACME_EMAIL:?ERROR: Set ACME_EMAIL env var for Let's Encrypt}" # --- Pre-flight checks --- [[ $EUID -eq 0 ]] || err "This script must be run as root."