Metadata-Version: 2.4
Name: ign8saas
Version: 0.1.4
Summary: Ignite a multi-tenant SaaS control plane (Vaultwarden + wg-portal) fronted by Caddy on Hetzner Cloud.
License: MIT
Requires-Python: >=3.9
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Provides-Extra: dev
Requires-Dist: cloudflare (>=3)
Requires-Dist: cryptography (>=42)
Requires-Dist: hcloud (>=2)
Requires-Dist: mypy (>=1.10) ; extra == "dev"
Requires-Dist: paramiko (>=3)
Requires-Dist: pydantic (>=2)
Requires-Dist: pydantic-settings (>=2)
Requires-Dist: pytest (>=8) ; extra == "dev"
Requires-Dist: rich (>=13)
Requires-Dist: ruff (>=0.4) ; extra == "dev"
Requires-Dist: typer (>=0.12)
Description-Content-Type: text/markdown

# ign8saas

Ignite a multi-tenant SaaS control plane on Hetzner Cloud. One VPS runs
**Caddy** (TLS termination + wildcard certs via Cloudflare DNS-01),
**Vaultwarden** (Bitwarden-compatible password vault) and **wg-portal**
(WireGuard admin UI) — reachable at three subdomains of your parent zone.

## Quickstart

```bash
cp .env.example .env    # fill in Hetzner + Cloudflare credentials
ign8saas up             # provision server + DNS + docker stack
```

## What gets provisioned

For `IGN8_DOMAIN=traeck.it` you get:

| Subdomain                     | Purpose                                        |
|-------------------------------|------------------------------------------------|
| `saas.traeck.it`              | landing page ("SaaS control plane — coming soon") |
| `*.vaultwarden.traeck.it`     | Vaultwarden (vanity slug redirect on subdomain) |
| `*.vpn.traeck.it`             | wg-portal (WireGuard admin UI)                 |

Underneath, on a single Hetzner `cax11` VPS in `fsn1`:

- Docker + Compose plugin (installed via `get.docker.com`)
- `caddy` (`ghcr.io/caddybuilds/caddy-cloudflare:latest`) — ports 80/443, wildcard certs via DNS-01
- `vaultwarden` (`vaultwarden/server:latest`) — signups disabled, invitations enabled
- `wg-portal` (`ghcr.io/h44z/wg-portal:latest`) — port 51820/udp exposed for WireGuard
- Hetzner firewall: 22 / 80 / 443 / 51820-udp only

## State

Local state lives under `.ign8saas/` (gitignored):

- `.ign8saas/keys/ign8saas` — SSH private key for server access
- `.ign8saas/state.json` — Hetzner IDs, IPv4
- `.ign8saas/vaultwarden-init.json` — Vaultwarden admin token + wg-portal admin creds (chmod 600, **keep safe**)

## Status

This scaffold delivers the **shared infra** only. Per-customer onboarding
(`add-customer`, `del-customer`) is stubbed — see `CLAUDE.md` for the design
notes and the roadmap.

See [CLAUDE.md](CLAUDE.md) for architecture details.

