···1818 services.nginx.virtualHosts.${domain} = {
1919 enableACME = true;
2020 forceSSL = true;
2121- # nginx hands out the client straight from the store. The game server is a
2222- # single event loop: every .js it serves during a join burst is time it is
2323- # not spending on the world tick, and a crowd arriving costs six files
2424- # each.
2525- # …the very package the service runs, so the client never lags the server.
2121+ # nginx hands out the client straight from the store — the very package
2222+ # the service runs, so the page never lags the server. The game is a
2323+ # single event loop: every .js it serves during a join burst is a tick it
2424+ # is not spending on the world, and a crowd arriving costs six files each.
2625 root = config.services.mazegame.package.static;
2726 locations."/" = {
2827 index = "index.html";
2928 tryFiles = "$uri $uri/ =404";
3030- extraConfig = ''
3131- # Versions ride in the store path, but the URLs never change, so let
3232- # the browser revalidate rather than cache a stale client.
3333- add_header Cache-Control "no-cache";
3434- '';
2929+ # Versions ride in the store path but the URLs never change, so let the
3030+ # browser revalidate against the ETag rather than cache a stale client.
3131+ # add_header does not inherit into the exact-match locations below.
3232+ extraConfig = ''add_header Cache-Control "no-cache";'';
3533 };
3636- locations."= /play".tryFiles = "/index.html =404";
3737- locations."= /watch".tryFiles = "/watch.html =404";
3434+ locations."= /play" = {
3535+ tryFiles = "/index.html =404";
3636+ extraConfig = ''add_header Cache-Control "no-cache";'';
3737+ };
3838+ locations."= /watch" = {
3939+ tryFiles = "/watch.html =404";
4040+ extraConfig = ''add_header Cache-Control "no-cache";'';
4141+ };
38423943 # Player and watcher sockets stay open for as long as someone is in the
4044 # maze; players heartbeat every 3s, watchers every 3s, so the default