How the web pages load fast and stay up to date
The homepage, signup page, admin panel and webmail are served by corpsuited itself, with no third-party CDN. A few things make them load quickly and make sure a browser never mixes files from two releases.
Versioned assets
Every build has a version: the start of a SHA-256 over all the files the pages load (HTML, CSS, JavaScript, icons). It changes when any of them changes, and only then.
- Each page links its stylesheets, scripts and icon sprite with
?v=<version>, for example/assets/mail.js?v=3f9a1c2b7d4e. - A file asked for with the current version is sent with
Cache-Control: public, max-age=31536000, immutable, so the browser keeps it and does not ask again. - A file asked for without a version, or with an old one, is cached for an hour only.
- The pages themselves are sent with
Cache-Control: no-cache, so the browser checks for a new page on every visit and picks up new asset links straight after an upgrade. Nobody needs to clear their cache.
GET /api/version returns the running version as {"version":"3f9a1c2b7d4e"}. Open pages use it to notice an upgrade.
Preloading
Each page's response carries a Link header that lists its stylesheets and scripts with rel=preload. The browser starts downloading them while the HTML is still arriving, instead of after it has read the <link> and <script> tags.
Over HTTP/2, the same list is first sent as a 103 Early Hints response, before the page itself. Browsers that support it (Chrome, Edge, Firefox and Safari) start fetching the assets even earlier. Early Hints are not sent over HTTP/1.1, where some clients and proxies mishandle them. corpsuited offers HTTP/2 on its HTTPS port with ACME certificates and with certificates from files alike.
The pages use the system font stack and load nothing from other sites, so there are no fonts to preload and no other origins to preconnect to.
Compression
Scripts, stylesheets and the icon sprite are compressed with Brotli and gzip at the highest levels when Zappocity is built, and the copies are built into corpsuited. A browser that accepts Brotli (all current ones over HTTPS) gets the Brotli copy, an older one gzip, and anything else the plain file. Together the assets shrink from about 390 KB to about 65 KB. Pages themselves are gzipped when the server starts, since it fills in the build version then.
There is nothing to run by hand: make, which installs and upgrades already use, runs go run ./cmd/compress-assets before building. (Run make assets to do only that step.) The tool records a checksum of each file it compressed, and the server only uses a copy that matches the file built with it, so a binary built some other way (for example with plain go build after changing a script) serves the plain file rather than an out-of-date one.
Responses carry Vary: Accept-Encoding, so caches keep the versions apart.
Behind a reverse proxy
If you put a proxy or load balancer in front of corpsuited:
- Keep the
Linkheader. Most proxies pass it on unchanged. - Early Hints reach the browser only if the proxy speaks HTTP/2 to
corpsuitedand forwards 1xx responses; nginx does not, HAProxy 2.x and Caddy do. Without them, theLinkheader on the full response still helps. - Don't override
Cache-Controlon/assets/. - Turn off the proxy's own compression for
corpsuited, or let it passContent-Encodingthrough: the responses are compressed already, and compressing them again only costs CPU.