mteehan 6106c1434d Add declarative firewall config with save-then-apply workflow
New two-step config flow: POST /config saves desired state to
config/firewall/config.json, GET /config/pending diffs against live
firewalld state, POST /config/apply synchronizes live state.  Adds target
normalization helpers and full test coverage for config CRUD and pending
diff logic.
2026-05-14 03:31:49 +00:00

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

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://<MGMT_DOMAIN>. 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 for the full guide, including troubleshooting.


For Developers

Local Development

git clone <repo-url> && 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):

.venv/bin/python webui/server.py

Lint and Format

.venv/bin/ruff check lib/ webui/ tests/
.venv/bin/ruff format lib/ webui/ tests/

Tests

.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.

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 <cmd> ──→ 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 for detailed request flow and zone model.


Documentation

S
Description
No description provided
Readme 2.8 MiB
Languages
Python 73.1%
JavaScript 24%
Shell 1.6%
CSS 1.3%