Deployment: pages and fragments leave the container uncompressed, and the documentation does not say the proxy should compress them #1152

Open
opened 2026-10-31 03:04:22 +00:00 by tiagoagueda · 0 comments
Owner

What exists today

config/settings/base.py:94-132 lists the middleware: WhiteNoise compresses static files at build time (gzip and Brotli, see A3), but nothing compresses what views return; django.middleware.gzip.GZipMiddleware is absent. The image runs gunicorn bound to port 8000 (docker/Dockerfile:388-393), which does not compress either. So whether pages travel compressed depends entirely on the operator's proxy.

The documentation does not raise it. postulo.wiki/Installing-Postulo.md:267-270 says "Postulo serves its own static files through WhiteNoise, so the proxy only needs to pass requests through"; postulo.wiki/Hardening.md:46-50 ("Add at the proxy what an application cannot do for itself") lists rate limits and file headers but not compression. Proxies differ: Caddy compresses only with an encode directive, and nginx only with gzip on (Debian's packaged configuration sets it, and then compresses text/html alone, not htmx's JSON or the API's), so an operator following the pages as written will often serve uncompressed HTML.

Pages are large because of the server-rendered design (the unpaginated board in A5 is the extreme), and every signed-in page is Cache-Control: no-store (core/middleware.py:395-419, deliberate, #787), so each view is a full transfer.

What would change

Recommended: documentation only. A short section in Hardening.md (or Installing-Postulo.md step 6) saying that Postulo does not compress pages itself and that the proxy should, with the one line for Caddy (encode zstd gzip) and for nginx (gzip on; gzip_types text/html application/json ...;), and a sentence pointing at whatever the user decides about responses that carry secrets.

The alternative is Django's own GZipMiddleware (no extra library), which would compress for operators without a capable proxy. Its documentation carries a warning about BREACH; whether that applies to Postulo's pages is a security question and is left to the user, not assessed here.

What it saves or protects

medium: HTML is repetitive and compresses roughly tenfold (30 board cards' status menus: 165 kB raw, 2 kB gzip; see A5); the saving is per page view and per htmx swap, since signed-in pages are no-store

Accessibility

none

Decided by the maintainer (2026-10-31)

document compression at the reverse proxy (Hardening, Installing); no middleware

Decisions

  • Document proxy compression, or add GZipMiddleware? Recommended: document it at the proxy; it keeps the application's behaviour unchanged and leaves the security trade-off where the operator can see it. The user decides; the security side was not assessed.

Found by the efficiency and reliability audit of 2026-10-30 (finding A6; index postulo/postulo#1108). Checked against main at daee30b15 (2026-10-30).

## What exists today `config/settings/base.py:94-132` lists the middleware: WhiteNoise compresses static files at build time (gzip and Brotli, see A3), but nothing compresses what views return; `django.middleware.gzip.GZipMiddleware` is absent. The image runs gunicorn bound to port 8000 (`docker/Dockerfile:388-393`), which does not compress either. So whether pages travel compressed depends entirely on the operator's proxy. The documentation does not raise it. `postulo.wiki/Installing-Postulo.md:267-270` says "Postulo serves its own static files through WhiteNoise, so the proxy only needs to pass requests through"; `postulo.wiki/Hardening.md:46-50` ("Add at the proxy what an application cannot do for itself") lists rate limits and file headers but not compression. Proxies differ: Caddy compresses only with an `encode` directive, and nginx only with `gzip on` (Debian's packaged configuration sets it, and then compresses `text/html` alone, not htmx's JSON or the API's), so an operator following the pages as written will often serve uncompressed HTML. Pages are large because of the server-rendered design (the unpaginated board in A5 is the extreme), and every signed-in page is `Cache-Control: no-store` (`core/middleware.py:395-419`, deliberate, #787), so each view is a full transfer. ## What would change Recommended: documentation only. A short section in `Hardening.md` (or `Installing-Postulo.md` step 6) saying that Postulo does not compress pages itself and that the proxy should, with the one line for Caddy (`encode zstd gzip`) and for nginx (`gzip on; gzip_types text/html application/json ...;`), and a sentence pointing at whatever the user decides about responses that carry secrets. The alternative is Django's own `GZipMiddleware` (no extra library), which would compress for operators without a capable proxy. Its documentation carries a warning about BREACH; whether that applies to Postulo's pages is a security question and is left to the user, not assessed here. ## What it saves or protects medium: HTML is repetitive and compresses roughly tenfold (30 board cards' status menus: 165 kB raw, 2 kB gzip; see A5); the saving is per page view and per htmx swap, since signed-in pages are `no-store` ## Accessibility none ## Decided by the maintainer (2026-10-31) document compression at the reverse proxy (Hardening, Installing); no middleware ## Decisions - **Document proxy compression, or add `GZipMiddleware`?** Recommended: document it at the proxy; it keeps the application's behaviour unchanged and leaves the security trade-off where the operator can see it. The user decides; the security side was not assessed. --- Found by the efficiency and reliability audit of 2026-10-30 (finding A6; index postulo/postulo#1108). Checked against `main` at `daee30b15` (2026-10-30).
tiagoagueda added this to the 1.0.0 milestone 2026-10-31 03:04:22 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#1152
No description provided.