1
0
This repository has been archived on 2026-08-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tera/deploy/STATIC.md
T

2.5 KiB

Hosting the static build

Tera's map view is a static bundle that needs a file server and nothing else. No API, no keys, no account: the sun and moon are computed locally by src/engine/solar.ts, the traffic is simulated, the minimap is drawn from the city pack, and the office is a data file.

It does make two requests at boot, and both are meant to fail on a plain static host: GET /api/v1/health and GET /api/v1/session, which is how src/access.ts works out whether this deployment has accounts at all. Nothing answering means nothing to sign in to, so the visitor gets the full public experience and no sign-in link — see that file's header for why an unreachable API and an API that answered 5xx are deliberately not the same case. Your server log will show two 404s per load; that is the zero-config path working, not a misconfiguration.

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'"
		# Screen sharing remains a per-action browser prompt. Webcam capture stays
		# disabled until that separate feature is deliberately deployed.
		Permissions-Policy "display-capture=(self), camera=(), microphone=(), geolocation=(), payment=(), usb=()"
	}
}

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.