roof 0773179962
Unit Tests / test (push) Successful in 8m55s
Gitignore .coverage files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 06:28:40 -04:00
2025-09-12 23:04:52 +03:00
2026-05-10 06:28:40 -04:00

Personal Internet Cell (PIC)

PIC is a self-hosted digital infrastructure platform. It packages DNS, DHCP, NTP, WireGuard VPN, email, calendar/contacts (CalDAV), file storage (WebDAV), a reverse proxy, a certificate authority, and optional third-party services — all managed through a single REST API and a React web UI. No manual config file editing is required for normal operations.


Architecture

Browser
  └── React SPA (cell-webui :8081)
        └── Flask REST API (cell-api :3000, bound to 127.0.0.1)
              └── Service managers + Docker SDK
                    ├── cell-caddy        :80/:443       Caddy reverse proxy (HTTPS/TLS)
                    ├── cell-dns          :53            CoreDNS
                    ├── cell-dhcp         :67/udp        dnsmasq
                    ├── cell-ntp          :123/udp       chrony
                    ├── cell-wireguard    :51820/udp     WireGuard VPN
                    ├── cell-mail         :25/:587/:993  Postfix + Dovecot
                    ├── cell-radicale     127.0.0.1:5232 CalDAV/CardDAV
                    ├── cell-webdav       127.0.0.1:8080 WebDAV
                    ├── cell-rainloop     127.0.0.1:8888 Webmail (RainLoop)
                    ├── cell-filegator    127.0.0.1:8082 File manager (Filegator)
                    └── cell-webui        :8081          React UI (Nginx)

All containers run on a custom Docker bridge network (cell-network, default subnet 172.20.0.0/16). Static IPs per container are set in docker-compose.yml and can be overridden via .env.

The Flask API (api/app.py) contains REST endpoints and a background health-monitoring thread. Service managers are instantiated as singletons in api/managers.py. The single source of truth for runtime configuration is config/api/cell_config.json, managed by ConfigManager.

The React frontend (webui/) is built with Vite + Tailwind CSS. All API calls go through src/services/api.js (Axios).

Web UI pages: Dashboard, Peers, Network Services, WireGuard, Email, Calendar, Files, Routing, Vault, Containers, Cell Network, Connectivity, Service Store, Logs, Settings.


Features

  • First-run wizard — browser-based setup at /setup. On first start, all API requests redirect to /setup (HTTP 428) until the wizard is completed. Sets cell name, domain mode, timezone, admin password, and initial services. No manual .env editing required for identity.
  • Session-based auth — admin and peer roles. All /api/* endpoints require an authenticated session after setup. CSRF protection on all state-changing requests.
  • WireGuard VPN — peer lifecycle management, automatic key generation, QR code config export, per-peer routing policy.
  • Caddy HTTPS — automatic TLS via Let's Encrypt (DNS-01 or HTTP-01) or an internal CA, depending on domain mode.
  • DDNS (pic.ngo) — registers a <cell-name>.pic.ngo subdomain. Supported providers: pic_ngo, cloudflare, duckdns, noip, freedns. A background thread re-publishes the public IP every 5 minutes.
  • Service store — install/remove optional third-party services from the pic-services index at git.pic.ngo. Manifests declare container images, Caddy routes, and iptables rules.
  • Extended connectivity — per-peer egress routing through alternate exits: WireGuard external, OpenVPN, or Tor. Configured via policy routing (fwmark + ip rule) in the WireGuard container.
  • Cell-to-cell networking — WireGuard-based site-to-site links between PIC cells with service-level access control (calendar, files, mail, WebDAV) and a peer-sync protocol.
  • Certificate authorityvault_manager issues and revokes TLS certificates for internal services.
  • Network services — CoreDNS (.cell TLD), dnsmasq DHCP, chrony NTP.
  • Email — Postfix + Dovecot via docker-mailserver.
  • Calendar/contacts — Radicale CalDAV/CardDAV.
  • File storage — WebDAV with per-user accounts; Filegator for browser-based file management.
  • Container manager — start/stop/inspect containers, pull images, manage volumes via the Docker SDK.
  • Firewall manager — iptables rule management (firewall_manager.py).
  • Structured logging — JSON logs with rotation (5 MB / 5 backups per service), log search, and per-service verbosity control.

Requirements

  • Linux host with the WireGuard kernel module loaded (modprobe wireguard to verify)
  • Docker Engine and Docker Compose (v2 plugin or v1 standalone)
  • Python 3.10+ (for make setup and local development; not needed at runtime)
  • 2 GB+ RAM, 10 GB+ disk
  • Ports available: 53, 67/udp, 80, 443, 51820/udp, 25, 587, 993

Quick Start

See QUICKSTART.md for step-by-step instructions.

The short version:

git clone gitea@192.168.31.50:roof/pic.git pic
cd pic
make start
# open http://<host-ip>:8081 — the setup wizard appears automatically

Configuration

Port assignments and container IPs are configured in .env in the project root. A .env file is not required for first start — all variables have defaults. Create one only if you need to change ports or container IPs.

Variable Default Description
CELL_NETWORK 172.20.0.0/16 Docker bridge subnet
CADDY_IP through FILEGATOR_IP 172.20.0.2.13 Static IP per container
DNS_PORT 53 DNS (UDP + TCP)
DHCP_PORT 67 DHCP (UDP)
NTP_PORT 123 NTP (UDP)
WG_PORT 51820 WireGuard listen port (UDP)
API_PORT 3000 Flask API (127.0.0.1 only)
WEBUI_PORT 8081 React UI
MAIL_SMTP_PORT 25 SMTP
MAIL_SUBMISSION_PORT 587 SMTP submission
MAIL_IMAP_PORT 993 IMAP
RADICALE_PORT 5232 CalDAV (127.0.0.1 only)
WEBDAV_PORT 8080 WebDAV (127.0.0.1 only)
RAINLOOP_PORT 8888 Webmail
FILEGATOR_PORT 8082 File manager UI
WEBDAV_USER admin WebDAV basic-auth username
WEBDAV_PASS (unset) WebDAV basic-auth password
FLASK_DEBUG (unset) Set to 1 for Flask debug mode; do not use in production
PUID / PGID current user UID/GID passed to the WireGuard container

Cell identity (cell name, domain mode, timezone) is set through the first-run wizard on first start, or later through the Settings page in the UI.


Security

Ports exposed on all interfaces by default:

  • 80 / 443 — Caddy (HTTP/HTTPS reverse proxy)
  • 51820/udp — WireGuard
  • 25 / 587 / 993 — mail
  • 53 — DNS
  • 67/udp — DHCP
  • 8081 — Web UI

Ports bound to 127.0.0.1 only:

  • 3000 — Flask API
  • 5232 — Radicale (CalDAV)
  • 8080 — WebDAV
  • 8888 — Webmail
  • 8082 — Filegator

The API uses session-based authentication (admin and peer roles). The Docker socket is mounted into cell-api; treat access to port 3000 as equivalent to root access on the host.

Before setup is complete, all /api/* requests except /api/setup/* and /health return HTTP 428 and a redirect to /setup.

CSRF protection (double-submit token in X-CSRF-Token header) applies to all POST, PUT, DELETE, and PATCH requests on /api/* once a user session exists, except /api/auth/* and /api/setup/*.

Cell-to-cell peer-sync endpoints (/api/cells/peer-sync/*) authenticate via source IP and WireGuard public key, not session cookies.

For internet-facing deployments, place the host behind a firewall and restrict access to the API and UI ports.


Development

# Start the full stack (builds api and webui images)
make start

# Rebuild a single image after code changes
make build-api
make build-webui

# Run Flask API locally without Docker (port 3000)
pip install -r api/requirements.txt
python api/app.py

# Run React UI dev server locally (port 5173, proxies /api to :3000)
cd webui && npm install && npm run dev

# Follow all container logs
make logs

# Follow logs for one service
make logs-api

# Open a shell inside a container
make shell-api

Testing

make test            # run all unit tests (pytest, excludes e2e and integration)
make test-coverage   # run with coverage; HTML report in htmlcov/
make test-api        # run API endpoint tests only

Tests live in tests/. Integration tests require a running stack:

make test-integration             # full suite (creates peers, modifies state)
make test-integration-readonly    # read-only checks, safe to run anytime

End-to-end tests use Playwright:

make test-e2e-deps    # install Playwright and dependencies (run once)
make test-e2e-api     # API-level e2e tests
make test-e2e-ui      # UI-level e2e tests

Management Commands

make start           # docker compose up -d --build (full profile)
make stop            # docker compose down
make restart         # docker compose restart
make status          # container status + API health check
make logs            # follow all service logs
make logs-<svc>      # follow logs for one service (e.g. make logs-api)
make shell-<svc>     # shell inside a container (e.g. make shell-api)

make update          # git pull + rebuild + restart
make reinstall       # full wipe of config/ and data/, then setup + start
make uninstall       # stop containers; prompts whether to also delete config/ and data/

make backup          # tar config/ + data/ into backups/
make restore         # list available backups

make list-peers      # show WireGuard peers via API
make show-routes     # wg show inside the wireguard container

make show-admin-password    # print current admin password
make reset-admin-password   # generate and set a new random admin password

License

MIT — see LICENSE.

S
Description
No description provided
Readme 1.6 MiB
Languages
Python 79.6%
JavaScript 18.7%
Shell 0.9%
Makefile 0.6%