- README.md: project overview, two sources of truth (config vs registrations), quick start, development, architecture - docs/registrations.md: complete API reference for service registrations — fields, types, defaults, what Central does per combination, examples for each use case Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
146 lines
5.7 KiB
Markdown
146 lines
5.7 KiB
Markdown
# Service Registrations
|
|
|
|
Wild Central provides DNS, proxy routing, TLS, and DDNS for services on the LAN. External consumers (Wild Cloud, Wild Works) register their domains with Central's API, and Central handles the networking.
|
|
|
|
## Registration API
|
|
|
|
```
|
|
POST /api/v1/services Register a domain
|
|
GET /api/v1/services List all registrations
|
|
GET /api/v1/services/{domain} Get registration details
|
|
PATCH /api/v1/services/{domain} Update a registration
|
|
DELETE /api/v1/services/{domain} Remove a registration
|
|
```
|
|
|
|
The domain is the unique key. One registration per domain.
|
|
|
|
## Fields
|
|
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `domain` | string | yes | — | FQDN to route. Unique key. |
|
|
| `source` | string | no | `"manual"` | Who registered this: `wild-cloud`, `wild-works`, `manual`. |
|
|
| `backend.address` | string | yes | — | Target host:port (e.g., `192.168.8.240:443`). |
|
|
| `backend.type` | string | yes | — | `tcp-passthrough` or `http`. |
|
|
| `subdomains` | bool | no | `false` | If true, also routes `*.domain` traffic to this backend. |
|
|
| `reach` | string | yes | — | `internal` or `public`. |
|
|
| `tls` | string | no | inferred | `passthrough` or `terminate`. Defaults based on type. |
|
|
|
|
### `backend.type`
|
|
|
|
**`tcp-passthrough`** — Layer 4. Central passes TLS traffic through to the backend without terminating it. The backend handles its own TLS (e.g., a k8s cluster with traefik and its own wildcard cert). HAProxy routes by SNI.
|
|
|
|
**`http`** — Layer 7. Central terminates TLS (using a certbot-provisioned certificate) and reverse-proxies HTTP to the backend. HAProxy routes by Host header.
|
|
|
|
### `subdomains`
|
|
|
|
Controls whether `*.domain` traffic is also routed to this backend.
|
|
|
|
- **`false`** (default): Only exact-match `domain` is routed. Use for custom domains like `payne.io` or `civilsociety.dev` where you only want that specific hostname.
|
|
- **`true`**: Both `domain` and `*.domain` are routed. Use for instance primary domains like `cloud.payne.io` where apps are served at subdomains (`matrix.cloud.payne.io`, `vaultwarden.cloud.payne.io`).
|
|
|
|
### `reach`
|
|
|
|
Controls DNS visibility and external access.
|
|
|
|
- **`internal`**: Domain resolves only on the LAN (dnsmasq `local=/` + `address=/`). Not added to DDNS. Not routable from the internet.
|
|
- **`public`**: Domain resolves on the LAN (dnsmasq `address=/`) AND externally via DDNS A record. Routable from the internet through Central's HAProxy.
|
|
|
|
### `tls`
|
|
|
|
- **`passthrough`**: Central does not terminate TLS — the backend handles it. Default for `tcp-passthrough`.
|
|
- **`terminate`**: Central provisions a TLS certificate (via certbot + Cloudflare DNS-01) and terminates TLS at HAProxy. Default for `http`.
|
|
|
|
## What Central does per registration
|
|
|
|
| | `tcp-passthrough` | `http` |
|
|
|---|---|---|
|
|
| **Internal DNS** | `address=/<domain>/<backend-IP>` — LAN clients connect directly to the backend | `address=/<domain>/<central-IP>` — LAN clients connect to Central's HAProxy |
|
|
| **DNS (internal reach)** | Also `local=/<domain>/` — prevents upstream DNS forwarding | Same |
|
|
| **External DNS (public reach)** | DDNS A record at Cloudflare | Same |
|
|
| **HAProxy** | L4 SNI → backend. `subdomains: true` adds `*.domain` matching. | L7 Host header → reverse proxy to backend. Always exact match. |
|
|
| **TLS** | Passthrough — backend handles TLS | Terminate — Central provisions cert via certbot |
|
|
|
|
## Examples
|
|
|
|
### Wild Cloud k8s instance (primary domain with subdomains)
|
|
|
|
```json
|
|
{
|
|
"domain": "cloud.payne.io",
|
|
"source": "wild-cloud",
|
|
"backend": {"address": "192.168.8.240:443", "type": "tcp-passthrough"},
|
|
"subdomains": true,
|
|
"reach": "public"
|
|
}
|
|
```
|
|
|
|
Result:
|
|
- DNS: `cloud.payne.io` → 192.168.8.240, `*.cloud.payne.io` → 192.168.8.240
|
|
- HAProxy: SNI `cloud.payne.io` and `*.cloud.payne.io` → passthrough to 192.168.8.240:443
|
|
- DDNS: A record for `cloud.payne.io` → public IP
|
|
- TLS: handled by k8s traefik (passthrough)
|
|
|
|
### Wild Cloud k8s instance (internal-only domain)
|
|
|
|
```json
|
|
{
|
|
"domain": "internal.cloud.payne.io",
|
|
"source": "wild-cloud",
|
|
"backend": {"address": "192.168.8.240:443", "type": "tcp-passthrough"},
|
|
"subdomains": true,
|
|
"reach": "internal"
|
|
}
|
|
```
|
|
|
|
Result:
|
|
- DNS: `local=/internal.cloud.payne.io/` + `address=/internal.cloud.payne.io/192.168.8.240`
|
|
- No DDNS record (internal only)
|
|
- HAProxy: SNI matching for internal domain (in case traffic comes through Central)
|
|
|
|
### Custom app domain (exact match, no subdomains)
|
|
|
|
```json
|
|
{
|
|
"domain": "payne.io",
|
|
"source": "wild-cloud",
|
|
"backend": {"address": "192.168.8.240:443", "type": "tcp-passthrough"},
|
|
"subdomains": false,
|
|
"reach": "public"
|
|
}
|
|
```
|
|
|
|
Result:
|
|
- DNS: `address=/payne.io/192.168.8.240`
|
|
- HAProxy: SNI exact match `payne.io` only (NOT `*.payne.io`)
|
|
- DDNS: A record for `payne.io` → public IP
|
|
|
|
### Wild Cloud app (HTTP reverse proxy, internal only)
|
|
|
|
```json
|
|
{
|
|
"domain": "wild-cloud.payne.io",
|
|
"source": "wild-cloud",
|
|
"backend": {"address": "127.0.0.1:5055", "type": "http"},
|
|
"reach": "internal"
|
|
}
|
|
```
|
|
|
|
Result:
|
|
- DNS: `local=/wild-cloud.payne.io/` + `address=/wild-cloud.payne.io/192.168.8.151`
|
|
- HAProxy: L7 Host `wild-cloud.payne.io` → reverse proxy to 127.0.0.1:5055
|
|
- TLS: Central provisions cert via certbot
|
|
- No DDNS (internal only)
|
|
|
|
## What is NOT a registration
|
|
|
|
Central's own services are driven by Central config, not registrations:
|
|
|
|
- **Central's UI domain** (`cloud.central.domain` in config)
|
|
- **VPN** (`cloud.vpn.*` in config) — WireGuard endpoint, firewall port
|
|
- **Firewall rules** (`cloud.nftables.*` in config)
|
|
- **DHCP** (`cloud.dnsmasq.dhcp.*` in config)
|
|
- **CrowdSec**, certbot credentials, DDNS provider config
|
|
|
|
These are managed through Central's own UI and config file. They don't go through the registration API.
|