diff --git a/deploy/STATIC.md b/deploy/STATIC.md new file mode 100644 index 0000000..b79e41a --- /dev/null +++ b/deploy/STATIC.md @@ -0,0 +1,49 @@ +# Hosting the static build + +Tera's map view is a static bundle. It makes **no network calls at all** — the +sun is computed locally by `src/engine/solar.ts`, the traffic is simulated, and +the office is a data file — so it needs a file server and nothing else. No API, +no keys, no account. + +```bash +npm ci +npm run build # -> dist/ +``` + +Serve `dist/` from anything. A Content-Security-Policy of `default-src 'self'` +is sufficient; the build references no external fonts, CDNs or images. + +## Caddy + +``` +tera.example.com { + root * /var/www/tera + encode zstd gzip + try_files {path} {path}/index.html /index.html + file_server + header { + Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; object-src 'none'" + } +} +``` + +`try_files … /index.html` matters if you add client-side routes later: without +it a route that exists only in JavaScript 404s for anyone who types it or +refreshes on it. + +`img-src` needs `data:` and `blob:` because every texture in the asset library +is drawn on a canvas at runtime rather than shipped as a file — see +ARCHITECTURE.md §3.1 for why that is a licensing decision and not a technical +one. + +## Serving the API too + +Only needed for live weather, real ADS-B, or markers from an external source. +The map runs fully without it. See `deploy/tera-api.service`, +`deploy/Caddyfile.snippet` and `deploy/docker-compose.yml`. + +## Base path + +Deployed at a subdomain root, no configuration is needed. Under a subpath, set +`TERA_BASE` at build time (`TERA_BASE=/tera/ npm run build`) — the trailing +slash matters, since every asset URL resolves against it.