Release to our nginx server¶
This page takes a checkout of this repository to a running release on
our own server: the site, the docs and the embeddable elements served
by nginx, and our own service behind it. It is for whoever does the
release. You need this repository set up (make setup, make
web-setup) and shell access to the server, which runs nginx and
Python 3.12.
Where it is served¶
Everything that depends on where the release lives comes from one set of
deploy settings. Copy deploy.env.example to deploy.env (ignored by
git) and edit it, or set the same names in the environment, which wins:
| Setting | Default | What it sets |
|---|---|---|
GD_URL_PREFIX |
/ |
the URL path the site is served under: /, or a sub-path such as /games/ |
GD_SERVER_NAME |
games.example.org |
the host name nginx answers for, and the host in the oEmbed files' URLs |
GD_TLS_CERTIFICATE |
/etc/ssl/games.example.org/fullchain.pem |
the certificate chain on the server |
GD_TLS_CERTIFICATE_KEY |
/etc/ssl/games.example.org/privkey.pem |
its private key on the server |
GD_WEB_ROOT |
/srv/grounded-decision/current/web |
the directory holding dist/web on the server (a link switched per release; step 2) |
GD_SERVICE_UPSTREAM |
127.0.0.1:8700 |
our own service's address, HOST:PORT or unix:/path |
make dist renders every nginx file from the templates in ops/nginx/
with these values, and refuses a value that isn't valid (a prefix that
doesn't start and end with /, a relative path, an unknown setting).
Nothing else needs them: the site and the docs link to each other and to
their assets with relative URLs, and the browser reaches our service at
ws/ under the site's own root, so the same dist/web works under any
prefix. tests/test_deploy_settings.py serves a release with real nginx
at / and under /games/.
1. Build everything locally¶
make check WEB=1 # every test, lint, type check and the strict docs build
make dist # writes dist/web, dist/service and dist/nginx
make web-e2e-nginx # optional: the browser tests against dist/ through real nginx
| Directory | What it holds | Where it goes on the server |
|---|---|---|
dist/web/ |
the site, docs/, elements/, the Python engine files, replays, ambient |
a release directory, linked as GD_WEB_ROOT |
dist/nginx/ |
the server block, the site's locations, the service proxy, generated headers | /etc/nginx/grounded-decision/ |
dist/service/ |
our own service: wheels for an offline install, systemd unit, release.sh |
anywhere on the service machine, e.g. /tmp |
dist/nginx/grounded-decision-headers*.conf are generated from the
site's _headers files by tools/nginx_config.py, under the URL prefix.
The end-to-end tests apply the same files, so nginx sends exactly the
headers the tests checked. Don't edit anything in dist/nginx/; change
the deploy settings, the templates or _headers, and rebuild.
2. Copy the static files and switch to them¶
With the default GD_WEB_ROOT (/srv/grounded-decision/current/web):
VERSION=$(date -u +%Y%m%dT%H%M%SZ)
rsync -a dist/web/ server:/srv/grounded-decision/releases/$VERSION/web/
ssh server "ln -sfn /srv/grounded-decision/releases/$VERSION /srv/grounded-decision/current.new \
&& mv -T /srv/grounded-decision/current.new /srv/grounded-decision/current"
The mv -T makes the switch atomic: a visitor sees either the old
release or the new one, never a mix.
3. Install the nginx configuration (first time, or when it changed)¶
Include it once from the http { } block of /etc/nginx/nginx.conf:
and check and reload:
To serve the site inside an existing server { } block instead (say,
under /games/ on a host that serves other things), include the pieces
yourself: in http { }, map_hash_bucket_size 128; and
map_hash_max_size 4096; first, then grounded-decision-http.conf and
grounded-decision-headers-maps.conf; inside that server block,
grounded-decision-site.conf.
4. Install or upgrade our own service¶
Copy dist/service/ to the service machine and run its release script.
It installs the release offline into its own directory, switches to it,
restarts the service and checks its health, and switches back by itself
if the new release is unhealthy:
rsync -a dist/service/ server:/tmp/grounded-decision-service/
ssh server "sudo /tmp/grounded-decision-service/bin/release.sh upgrade"
The first install, the systemd unit, settings and logs are on Run our own service.
5. Check it¶
- Open the site at
https://+GD_SERVER_NAME+GD_URL_PREFIX: the home page, a game's play page,docs/. curl -Ion that URL shows theContent-Security-Policyheader.- On the server,
curl http://127.0.0.1:8700/healthzanswers with the service's version. Through nginx,healthzunder the prefix answers only from the server itself.
Roll back¶
- Static files: point
currentat the previous directory under/srv/grounded-decision/releases/the same way as step 2. - Service:
release.sh rollback. - nginx config: copy the previous
dist/nginx/, thennginx -t && nginx -s reload.
What can go wrong¶
| Symptom | Cause | Fix |
|---|---|---|
make dist stops with a settings error |
a deploy setting isn't valid, or is misspelt | fix deploy.env (or the environment) as the message says |
| Every page is 404 | GD_URL_PREFIX doesn't match the URL in use |
set it to the path you serve from, make dist again, copy dist/nginx/ |
| The live engine never starts; the console mentions WebAssembly | nginx serves .wasm with the wrong type |
keep grounded-decision-site.conf included; it maps application/wasm |
nginx -t fails on map_hash_bucket_size |
the directive is set twice, or after a map |
keep one copy, before the first map in the http block |
| Embedded elements on our other sites don't load | that site's Content Security Policy | add the entries listed on Embed the games and demos |
api/ answers 502 |
the service isn't running | systemctl status 'grounded-decision@*'; see Run our own service |