Support routes.
This commit is contained in:
@@ -21,12 +21,66 @@ The domain is the unique key. One registration per domain.
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `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`. |
|
||||
| `backend.address` | string | yes* | — | Target host:port (e.g., `192.168.8.240:80`). |
|
||||
| `backend.type` | string | yes* | — | `tcp-passthrough` or `http`. |
|
||||
| `backend.health` | string | no | — | Health check path for L7 services (e.g., `/health`). |
|
||||
| `subdomains` | bool | no | `false` | If true, also routes `*.domain` traffic to this backend. |
|
||||
| `subdomains` | bool | no | `false` | If true, also routes `*.domain` traffic. |
|
||||
| `public` | bool | no | `false` | If true, domain gets public DNS + internet exposure. |
|
||||
| `tls` | string | no | inferred | `passthrough` or `terminate`. Defaults based on backend type. |
|
||||
| `routes` | array | no* | — | Path-based multi-backend routing (see below). |
|
||||
|
||||
*A service must have either `backend` (simple) or `routes` (multi-backend), not both.
|
||||
|
||||
## Simple vs multi-backend services
|
||||
|
||||
### Simple (single backend)
|
||||
|
||||
Most services use a single backend. All traffic for the domain goes to one place:
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "my-api.payne.io",
|
||||
"backend": {"address": "192.168.8.60:9001", "type": "http"},
|
||||
"tls": "terminate"
|
||||
}
|
||||
```
|
||||
|
||||
### Multi-backend (path-based routing)
|
||||
|
||||
When different URL paths on the same domain need to reach different backends, use `routes`. Each route maps path prefixes to a backend with its own L7 options. Routes are evaluated in order — first match wins. A route with empty `paths` is a catch-all (should be last).
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "payne.io",
|
||||
"public": true,
|
||||
"tls": "terminate",
|
||||
"routes": [
|
||||
{
|
||||
"paths": ["/_matrix", "/.well-known/matrix"],
|
||||
"backend": {"address": "192.168.8.60:8008", "type": "http", "health": "/health"}
|
||||
},
|
||||
{
|
||||
"backend": {"address": "192.168.8.240:80", "type": "http"}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Here `/_matrix` and `/.well-known/matrix` go to a Matrix server, everything else goes to a website. Both backends can be on different hosts.
|
||||
|
||||
### Route fields
|
||||
|
||||
Each route in the `routes` array supports:
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `paths` | []string | no | Path prefixes to match (empty = catch-all). |
|
||||
| `backend.address` | string | yes | Target host:port. |
|
||||
| `backend.type` | string | yes | `http` (routes only support L7). |
|
||||
| `backend.health` | string | no | Health check path. |
|
||||
| `headers.request` | map | no | Request headers to set (e.g., `X-Forwarded-Proto: https`). |
|
||||
| `headers.response` | map | no | Response headers to set (e.g., CORS headers). |
|
||||
| `ipAllow` | []string | no | CIDR whitelist — deny requests not matching (e.g., `["10.0.0.0/8"]`). |
|
||||
|
||||
## User-facing concepts
|
||||
|
||||
@@ -50,7 +104,7 @@ The API fields map to three user-visible controls:
|
||||
|
||||
`tls: "passthrough"` or `tls: "terminate"`
|
||||
|
||||
- **Passthrough**: Central forwards encrypted traffic directly to the backend. The backend handles its own TLS certificates (e.g., a k8s cluster with traefik). Maps to `backend.type: "tcp-passthrough"`.
|
||||
- **Passthrough**: Central forwards encrypted traffic directly to the backend. The backend handles its own TLS certificates. Maps to `backend.type: "tcp-passthrough"`.
|
||||
- **Terminate**: Central provisions a TLS certificate and handles HTTPS. Traffic is decrypted at Central and proxied as HTTP to the backend. Maps to `backend.type: "http"`.
|
||||
|
||||
## What Central does per registration
|
||||
@@ -62,24 +116,26 @@ When a service is registered, Central automatically:
|
||||
| **LAN DNS** | `address=/<domain>/<backend-IP>` — direct to backend | `address=/<domain>/<central-IP>` — through Central |
|
||||
| **LAN DNS (private)** | Also `local=/<domain>/` — prevents upstream forwarding | Same |
|
||||
| **Public DNS** | DDNS A record if public | Same |
|
||||
| **Proxy** | L4 SNI passthrough. Subdomains adds `*.domain` matching. | L7 HTTP reverse proxy by Host header. |
|
||||
| **Proxy** | L4 SNI passthrough. Subdomains adds `*.domain` matching. | L7 HTTP reverse proxy by Host header. Routes add path-based ACLs. |
|
||||
| **TLS** | Backend handles — Central passes through | Central provisions cert via Let's Encrypt |
|
||||
|
||||
## Examples
|
||||
|
||||
### k8s cluster (passthrough, public, with subdomains)
|
||||
### Wild Cloud k8s cluster (terminate, public, wildcard)
|
||||
|
||||
Wild Cloud registers its instances as HTTP terminate services. Central handles TLS and forwards plain HTTP to the cluster's Traefik ingress controller.
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "cloud.payne.io",
|
||||
"source": "wild-cloud",
|
||||
"backend": {"address": "192.168.8.240:443", "type": "tcp-passthrough"},
|
||||
"backend": {"address": "192.168.8.240:80", "type": "http"},
|
||||
"subdomains": true,
|
||||
"public": true
|
||||
}
|
||||
```
|
||||
|
||||
Central creates: LAN DNS → 192.168.8.240, public DNS A record, HAProxy L4 SNI + wildcard *.cloud.payne.io, TLS passthrough.
|
||||
Central creates: LAN DNS → Central IP, public DNS A record, HAProxy L7 TLS terminate + wildcard `*.cloud.payne.io`, cert via certbot.
|
||||
|
||||
### Internal web app (terminate, private)
|
||||
|
||||
@@ -93,19 +149,60 @@ Central creates: LAN DNS → 192.168.8.240, public DNS A record, HAProxy L4 SNI
|
||||
|
||||
Central creates: LAN DNS → Central IP (with `local=/`), HAProxy L7 reverse proxy, TLS cert via certbot. No public DNS.
|
||||
|
||||
### Custom domain (passthrough, public, exact match)
|
||||
### Service with custom response headers
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "keila.cloud.payne.io",
|
||||
"source": "wild-cloud",
|
||||
"routes": [{
|
||||
"backend": {"address": "192.168.8.240:80", "type": "http"},
|
||||
"headers": {
|
||||
"response": {
|
||||
"Access-Control-Allow-Origin": "https://cloud.payne.io"
|
||||
}
|
||||
}
|
||||
}],
|
||||
"public": true
|
||||
}
|
||||
```
|
||||
|
||||
### Service with IP whitelisting (internal only)
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "headlamp.internal.cloud.payne.io",
|
||||
"source": "wild-cloud",
|
||||
"routes": [{
|
||||
"backend": {"address": "192.168.8.240:80", "type": "http"},
|
||||
"ipAllow": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### L4 passthrough (non-HTTP services)
|
||||
|
||||
For services that handle their own TLS (e.g., standalone apps with built-in cert management):
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "payne.io",
|
||||
"source": "wild-cloud",
|
||||
"backend": {"address": "192.168.8.240:443", "type": "tcp-passthrough"},
|
||||
"subdomains": false,
|
||||
"public": true
|
||||
}
|
||||
```
|
||||
|
||||
Central creates: LAN DNS → 192.168.8.240, public DNS A record, HAProxy L4 SNI exact match only. No wildcard.
|
||||
Central creates: LAN DNS → backend IP, public DNS A record, HAProxy L4 SNI passthrough. TLS handled by backend.
|
||||
|
||||
## Wild Cloud integration
|
||||
|
||||
Wild Cloud instances with `central.registration: per-app` in their instance config use a client-go Ingress watcher that automatically registers domains with Central:
|
||||
|
||||
- One wildcard registration per instance domain (e.g., `*.cloud.payne.io` with `subdomains: true`)
|
||||
- One wildcard registration per internal domain (e.g., `*.internal.cloud.payne.io`)
|
||||
- Individual registrations for apps with special routing needs (custom headers, IP whitelisting, extra domains)
|
||||
- Apps define special routing via a `central` section in their manifest config
|
||||
|
||||
## What is NOT a registration
|
||||
|
||||
|
||||
Reference in New Issue
Block a user