docs(deployment): add runbooks for store subdomains, custom domains, and new platforms
- Update origin cert config: wildcards for omsflow.lu, rewardflow.lu, hostwizard.lu - Add wildcard Caddy blocks to production Caddyfile example - Replace "Future" section with actionable runbooks: - Add a Store Subdomain (self-service, no infra changes) - Add a Custom Store Domain (Cloudflare + Caddy + DB) - Add a New Platform Domain (full setup) - Document wizard.lu exception (no wildcard due to git.wizard.lu DNS-only) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -758,7 +758,7 @@ Then restart Gitea:
|
||||
cd ~/gitea && docker compose up -d gitea
|
||||
```
|
||||
|
||||
### Future: Multi-Tenant Store Routing
|
||||
### Multi-Tenant Store Routing
|
||||
|
||||
Stores on each platform use two routing modes:
|
||||
|
||||
@@ -769,49 +769,204 @@ Both modes are handled by the `StoreContextMiddleware` which reads the `Host` he
|
||||
|
||||
#### Wildcard Subdomains (for store subdomains)
|
||||
|
||||
When stores start using subdomains like `acme.omsflow.lu`, add wildcard blocks:
|
||||
Each non-main platform uses a wildcard Caddy block so any store subdomain (e.g. `acme.omsflow.lu`, `parcelproxy.hostwizard.lu`) is automatically routed without per-store Caddy changes.
|
||||
|
||||
The wildcard blocks use the same origin cert as the platform root domain. The origin cert must include `*.<platform_domain>` — see [Step 21.4](#214-generate-origin-certificates) for how to generate it.
|
||||
|
||||
```caddy
|
||||
*.omsflow.lu {
|
||||
tls /etc/caddy/certs/omsflow.lu/cert.pem /etc/caddy/certs/omsflow.lu/key.pem
|
||||
reverse_proxy localhost:8001
|
||||
}
|
||||
|
||||
*.rewardflow.lu {
|
||||
tls /etc/caddy/certs/rewardflow.lu/cert.pem /etc/caddy/certs/rewardflow.lu/key.pem
|
||||
reverse_proxy localhost:8001
|
||||
}
|
||||
|
||||
*.wizard.lu {
|
||||
*.hostwizard.lu {
|
||||
tls /etc/caddy/certs/hostwizard.lu/cert.pem /etc/caddy/certs/hostwizard.lu/key.pem
|
||||
reverse_proxy localhost:8001
|
||||
}
|
||||
```
|
||||
|
||||
!!! warning "Wildcard SSL requires DNS challenge"
|
||||
Let's Encrypt cannot issue wildcard certificates via HTTP challenge. Wildcard certs require a **DNS challenge**, which means installing a Caddy DNS provider plugin (e.g. `caddy-dns/cloudflare`) and configuring API credentials for your DNS provider. See [Caddy DNS challenge docs](https://caddyserver.com/docs/automatic-https#dns-challenge).
|
||||
!!! warning "No wildcard for wizard.lu"
|
||||
`wizard.lu` cannot use a wildcard block because `git.wizard.lu` is DNS-only (grey cloud in Cloudflare) and uses a Let's Encrypt cert. A wildcard origin cert would conflict. For wizard.lu subdomains, add each one explicitly (same pattern as `api.wizard.lu`, `flower.wizard.lu`).
|
||||
|
||||
#### Custom Store Domains (for premium stores)
|
||||
**Cloudflare DNS**: Add a wildcard DNS record for each platform:
|
||||
|
||||
When premium stores bring their own domains (e.g. `acme.lu`), use Caddy's **on-demand TLS**:
|
||||
- `*.omsflow.lu` → A `91.99.65.229` (proxied, orange cloud)
|
||||
- `*.rewardflow.lu` → A `91.99.65.229` (proxied, orange cloud)
|
||||
- `*.hostwizard.lu` → A `91.99.65.229` (proxied, orange cloud)
|
||||
|
||||
With this in place, adding a new store subdomain only requires a database entry (via admin UI) — no DNS or Caddy changes needed.
|
||||
|
||||
#### Runbook: Add a Store Subdomain
|
||||
|
||||
When a merchant creates a store with subdomain `acme` on the OMS platform:
|
||||
|
||||
1. **Database**: Create the store via admin UI — set `subdomain = "acme"` and link to the platform. The `StoreContextMiddleware` will resolve `acme.omsflow.lu` automatically.
|
||||
2. **DNS**: Already covered by the wildcard `*.omsflow.lu` record in Cloudflare.
|
||||
3. **Caddy**: Already covered by the `*.omsflow.lu` block.
|
||||
4. **SSL**: Already covered by the wildcard origin cert.
|
||||
5. **Verify**: `curl -I https://acme.omsflow.lu/`
|
||||
|
||||
No infrastructure changes needed — it's fully self-service.
|
||||
|
||||
#### Runbook: Add a Custom Store Domain
|
||||
|
||||
When a premium store brings their own domain (e.g. `wizamart.com`), the domain must be added to **your** Cloudflare account. This ensures you control SSL, WAF, and DNS — critical since you are responsible for the infrastructure.
|
||||
|
||||
**Step 1: Add domain to Cloudflare**
|
||||
|
||||
1. In [Cloudflare Dashboard](https://dash.cloudflare.com), click **Add a site** > enter `wizamart.com`
|
||||
2. Select the Free plan
|
||||
3. Cloudflare assigns NS records — give these to the store owner to update at their registrar
|
||||
4. Wait for NS propagation (can take up to 24h, usually minutes)
|
||||
|
||||
**Step 2: Configure DNS in Cloudflare**
|
||||
|
||||
Add A records (proxied, orange cloud):
|
||||
|
||||
| Type | Name | Content | Proxy |
|
||||
|------|------|---------|-------|
|
||||
| A | `wizamart.com` | `91.99.65.229` | Proxied |
|
||||
| A | `www` | `91.99.65.229` | Proxied |
|
||||
|
||||
**Step 3: Generate origin certificate**
|
||||
|
||||
1. In Cloudflare: **SSL/TLS** > **Origin Server** > **Create Certificate**
|
||||
2. Hostnames: `wizamart.com, www.wizamart.com`
|
||||
3. Validity: 15 years
|
||||
4. Download cert and key (key shown only once!)
|
||||
|
||||
**Step 4: Install cert on server**
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /etc/caddy/certs/wizamart.com
|
||||
sudo nano /etc/caddy/certs/wizamart.com/cert.pem # paste certificate
|
||||
sudo nano /etc/caddy/certs/wizamart.com/key.pem # paste private key
|
||||
sudo chown -R caddy:caddy /etc/caddy/certs/wizamart.com
|
||||
sudo chmod 600 /etc/caddy/certs/wizamart.com/key.pem
|
||||
```
|
||||
|
||||
**Step 5: Add to Caddyfile**
|
||||
|
||||
```bash
|
||||
sudo nano /etc/caddy/Caddyfile
|
||||
```
|
||||
|
||||
Add:
|
||||
|
||||
```caddy
|
||||
https:// {
|
||||
tls {
|
||||
on_demand
|
||||
}
|
||||
# ─── Custom store domain: wizamart.com ────────────────────────
|
||||
wizamart.com {
|
||||
tls /etc/caddy/certs/wizamart.com/cert.pem /etc/caddy/certs/wizamart.com/key.pem
|
||||
reverse_proxy localhost:8001
|
||||
}
|
||||
|
||||
www.wizamart.com {
|
||||
tls /etc/caddy/certs/wizamart.com/cert.pem /etc/caddy/certs/wizamart.com/key.pem
|
||||
redir https://wizamart.com{uri} permanent
|
||||
}
|
||||
```
|
||||
|
||||
**Step 6: Reload Caddy**
|
||||
|
||||
```bash
|
||||
sudo systemctl reload caddy
|
||||
sudo systemctl status caddy
|
||||
```
|
||||
|
||||
**Step 7: Configure Cloudflare settings**
|
||||
|
||||
In Cloudflare dashboard for `wizamart.com`:
|
||||
|
||||
| Setting | Location | Value |
|
||||
|---|---|---|
|
||||
| SSL mode | SSL/TLS > Overview | Full (Strict) |
|
||||
| Always Use HTTPS | SSL/TLS > Edge Certificates | On |
|
||||
| Bot Fight Mode | Security > Settings | On |
|
||||
|
||||
**Step 8: Register domain in database**
|
||||
|
||||
Via admin UI: create a `StoreDomain` record linking `wizamart.com` to the store and platform.
|
||||
|
||||
**Step 9: Verify**
|
||||
|
||||
```bash
|
||||
curl -I https://wizamart.com/
|
||||
```
|
||||
|
||||
The `StoreContextMiddleware` will detect `wizamart.com` as a custom domain, look it up in the `store_domains` table, and route to the correct store.
|
||||
|
||||
#### Runbook: Add a New Platform Domain
|
||||
|
||||
When adding an entirely new platform (e.g. `newplatform.lu`):
|
||||
|
||||
**Step 1: Cloudflare**
|
||||
|
||||
1. Add `newplatform.lu` as a site in Cloudflare
|
||||
2. Configure NS at registrar
|
||||
3. Add DNS records (all proxied):
|
||||
- `newplatform.lu` → A `91.99.65.229`
|
||||
- `www.newplatform.lu` → A `91.99.65.229`
|
||||
- `*.newplatform.lu` → A `91.99.65.229` (for store subdomains)
|
||||
|
||||
**Step 2: Generate origin certificate**
|
||||
|
||||
In Cloudflare: **SSL/TLS** > **Origin Server** > **Create Certificate**
|
||||
|
||||
Hostnames: `newplatform.lu, www.newplatform.lu, *.newplatform.lu`
|
||||
|
||||
**Step 3: Install cert and update Caddyfile**
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /etc/caddy/certs/newplatform.lu
|
||||
sudo nano /etc/caddy/certs/newplatform.lu/cert.pem
|
||||
sudo nano /etc/caddy/certs/newplatform.lu/key.pem
|
||||
sudo chown -R caddy:caddy /etc/caddy/certs/newplatform.lu
|
||||
sudo chmod 600 /etc/caddy/certs/newplatform.lu/key.pem
|
||||
```
|
||||
|
||||
Add to Caddyfile:
|
||||
|
||||
```caddy
|
||||
# ─── Platform: NewPlatform (newplatform.lu) ───────────────────
|
||||
newplatform.lu {
|
||||
tls /etc/caddy/certs/newplatform.lu/cert.pem /etc/caddy/certs/newplatform.lu/key.pem
|
||||
reverse_proxy localhost:8001
|
||||
}
|
||||
|
||||
www.newplatform.lu {
|
||||
tls /etc/caddy/certs/newplatform.lu/cert.pem /etc/caddy/certs/newplatform.lu/key.pem
|
||||
redir https://newplatform.lu{uri} permanent
|
||||
}
|
||||
|
||||
*.newplatform.lu {
|
||||
tls /etc/caddy/certs/newplatform.lu/cert.pem /etc/caddy/certs/newplatform.lu/key.pem
|
||||
reverse_proxy localhost:8001
|
||||
}
|
||||
```
|
||||
|
||||
On-demand TLS auto-provisions SSL certificates when a new domain connects. Add an `ask` endpoint to validate that the domain is registered in the `store_domains` table, preventing abuse:
|
||||
|
||||
```caddy
|
||||
tls {
|
||||
on_demand
|
||||
ask http://localhost:8001/api/v1/internal/verify-domain
|
||||
}
|
||||
```bash
|
||||
sudo systemctl reload caddy
|
||||
```
|
||||
|
||||
!!! note "Not needed yet"
|
||||
Wildcard subdomains and custom domains are future work. The current Caddyfile handles all platform root domains and service subdomains.
|
||||
**Step 4: Cloudflare settings**
|
||||
|
||||
Same as other platforms — see [Step 21.6](#216-cloudflare-settings-per-domain).
|
||||
|
||||
**Step 5: Database**
|
||||
|
||||
Create the platform record via `init_production.py` or admin UI with `domain = "newplatform.lu"`.
|
||||
|
||||
**Step 6: Verify**
|
||||
|
||||
```bash
|
||||
curl -I https://newplatform.lu/
|
||||
curl -I https://teststore.newplatform.lu/
|
||||
```
|
||||
|
||||
## Step 15: Gitea Actions Runner
|
||||
|
||||
@@ -2007,15 +2162,15 @@ Disable DNSSEC at the registrar before switching NS — re-enable later via Clou
|
||||
Cloudflare Origin Certificates (free, 15-year validity) avoid ACME challenge issues when traffic is proxied:
|
||||
|
||||
1. In Cloudflare: **SSL/TLS** > **Origin Server** > **Create Certificate**
|
||||
2. Generate for each domain with **specific subdomains** (not wildcards):
|
||||
- `wizard.lu`: `wizard.lu, api.wizard.lu, www.wizard.lu, flower.wizard.lu, grafana.wizard.lu`
|
||||
- `omsflow.lu`: `omsflow.lu, www.omsflow.lu`
|
||||
- `rewardflow.lu`: `rewardflow.lu, www.rewardflow.lu`
|
||||
- `hostwizard.lu`: `hostwizard.lu, www.hostwizard.lu`
|
||||
2. Generate for each domain:
|
||||
- `wizard.lu`: `wizard.lu, api.wizard.lu, www.wizard.lu, flower.wizard.lu, grafana.wizard.lu` (**specific subdomains, no wildcard**)
|
||||
- `omsflow.lu`: `omsflow.lu, www.omsflow.lu, *.omsflow.lu` (wildcard for store subdomains)
|
||||
- `rewardflow.lu`: `rewardflow.lu, www.rewardflow.lu, *.rewardflow.lu` (wildcard for store subdomains)
|
||||
- `hostwizard.lu`: `hostwizard.lu, www.hostwizard.lu, *.hostwizard.lu` (wildcard for store subdomains)
|
||||
3. Download the certificate and private key (private key is shown only once)
|
||||
|
||||
!!! warning "Do NOT use wildcard origin certs for wizard.lu"
|
||||
A `*.wizard.lu` wildcard cert will match `git.wizard.lu`, which needs a Let's Encrypt cert (DNS-only, not proxied through Cloudflare). Use specific subdomains instead.
|
||||
A `*.wizard.lu` wildcard cert will match `git.wizard.lu`, which is DNS-only (grey cloud) and uses a Let's Encrypt cert. A wildcard origin cert would conflict. Use specific subdomains instead. For new wizard.lu subdomains, add them explicitly to this cert and to the Caddyfile.
|
||||
|
||||
Install on the server:
|
||||
|
||||
@@ -2090,6 +2245,22 @@ www.hostwizard.lu {
|
||||
redir https://hostwizard.lu{uri} permanent
|
||||
}
|
||||
|
||||
# ─── Store subdomains (wildcard — all except wizard.lu) ──────
|
||||
*.omsflow.lu {
|
||||
tls /etc/caddy/certs/omsflow.lu/cert.pem /etc/caddy/certs/omsflow.lu/key.pem
|
||||
reverse_proxy localhost:8001
|
||||
}
|
||||
|
||||
*.rewardflow.lu {
|
||||
tls /etc/caddy/certs/rewardflow.lu/cert.pem /etc/caddy/certs/rewardflow.lu/key.pem
|
||||
reverse_proxy localhost:8001
|
||||
}
|
||||
|
||||
*.hostwizard.lu {
|
||||
tls /etc/caddy/certs/hostwizard.lu/cert.pem /etc/caddy/certs/hostwizard.lu/key.pem
|
||||
reverse_proxy localhost:8001
|
||||
}
|
||||
|
||||
# ─── Services (wizard.lu origin cert) ───────────────────────
|
||||
api.wizard.lu {
|
||||
tls /etc/caddy/certs/wizard.lu/cert.pem /etc/caddy/certs/wizard.lu/key.pem
|
||||
|
||||
Reference in New Issue
Block a user