Domains, TLS & Cloudflare
A public Haven needs a domain and HTTPS. This page covers the DNS and TLS layout that keeps cookies, CORS and CSP simple.
The recommended hostname layout
Section titled “The recommended hostname layout”Put everything on one registrable domain:
| Hostname | Points at | Purpose |
|---|---|---|
crimson.example.com |
client (:8080) |
the website |
backend.crimson.example.com |
backend (:8000) |
the API |
dev.crimson.example.com / dev-backend.… |
the dev stack | staging |
docs.crimson.example.com |
GitLab Pages | this documentation |
Same registrable domain means same-site cookies, easy CORS (ALLOWED_ORIGINS) and a
simple CSP.
Option A: Cloudflare (recommended)
Section titled “Option A: Cloudflare (recommended)”Cloudflare gives you free DNS, TLS and a tunnel that avoids opening ports.
- Add your domain to Cloudflare and point your registrar at Cloudflare’s nameservers.
- Cloudflare Tunnel (no inbound ports): install
cloudflaredon your server, create a tunnel, and map public hostnames to local services:~/.cloudflared/config.yml tunnel: <tunnel-id>ingress:- hostname: crimson.example.comservice: http://localhost:8080- hostname: backend.crimson.example.comservice: http://localhost:8000- service: http_status:404Terminal window cloudflared tunnel run - TLS is terminated at Cloudflare’s edge, which sets
X-Forwarded-ProtoandX-Forwarded-For. The backend image already trusts forwarded headers (uvicorn runs with--proxy-headers --forwarded-allow-ips "*"), so it seeshttpsand the real client IP.
Option B: A reverse proxy with Let’s Encrypt
Section titled “Option B: A reverse proxy with Let’s Encrypt”To terminate TLS yourself, Caddy is the simplest (automatic certificates):
# Caddyfilecrimson.example.com { reverse_proxy localhost:8080}backend.crimson.example.com { reverse_proxy localhost:8000}nginx with Certbot works too; make sure it sets X-Forwarded-Proto and
X-Forwarded-Host so the backend emits https:// URLs.
CORS, after you have domains
Section titled “CORS, after you have domains”Tell the backend which origin the client lives on:
ALLOWED_ORIGINS=https://crimson.example.comUnset, it falls back to the reference instance’s origins (https://crimsonhaven.to
and https://www.crimsonhaven.to), which will not match your domain.
The docs site (this very site)
Section titled “The docs site (this very site)”The docs are an Astro + Starlight site published to GitLab Pages, separately from
your servers. The repo’s .gitlab-ci.yml builds and deploys it on push to the default
branch.
- In the
crimson-docsproject, open Settings → Pages and add your docs hostname as a custom domain. - Create the DNS records GitLab shows there (the hostname record plus a
TXTverification record). With Cloudflare, keep the hostname record DNS only / grey cloud until the certificate is issued. - Enable automatic certificate management on that page, if your GitLab instance supports it, so HTTPS is provisioned once DNS resolves.
public/CNAME is left over from the GitHub Pages setup and has no effect on GitLab.
A quick sanity checklist
Section titled “A quick sanity checklist”- The client loads over HTTPS at its hostname.
-
https://backend.…/healthreturns"status": "healthy". -
ALLOWED_ORIGINSincludes the client’s HTTPS origin. - The backend sees
X-Forwarded-Proto: https(no mixed-content blocks on streams). -
docs.…serves the documentation.
