feat: a proper Keel default site in a simple installation (keel-web 0.2.0) #4

Merged
marcos-mendez merged 5 commits from feat/keel-default-site into master 2026-10-03 06:55:32 -03:00
marcos-mendez commented 2026-10-02 23:15:03 -03:00 (Migrated from github.com)

On a live Keel Web container (keel-web 0.1.1, cloud.mode simple) Nginx served Debian's stock default site over an empty /var/www/html, so curl http://host/ got nginx's bare 404, nothing listened on 443, and the usage screen said http://. This makes a simple installation serve a proper Keel default site.

keel-web 0.2.0

  • /etc/nginx/sites-available/keel-default, a conffile like the front: the default server on [::]:80, 0.0.0.0:80, [::]:443 ssl, 0.0.0.0:443 ssl, http2 on, ssl_certificate /etc/ssl/private/cert.pem, cert.key, ssl_dhparam dhparams.pem, zz-ssl-ciphers' list, ssl_session_tickets off, no HSTS (after ACME, tracker#51), server_tokens off. HTTP is served, not redirected (http-01). /keel-health answers 204 on both schemes.
  • Pages at /var/www/keel-default (index.html, 404.html, 50x.html): plain, static, no external resource, no TurnKey wording, no version; they say this is a Keel Web node with no site configured yet and that the operator configures one with confconsole or /etc/keel/instance.yaml. Shipped under /usr/share/keel-web/default-site (lintian dir-or-file-in-var-www is an error); the postinst links /var/www/keel-default to it and leaves a directory of the operator's alone.
  • The postinst enables the site in Debian's place with the care 0042 asks: only an unedited Debian default link (nginx-common's conffile checksum) is removed, recorded in /var/lib/keel-web, then nginx -t, rolled back when refused. While /etc/ssl/private/cert.pem, cert.key or dhparams.pem is missing, as in fab's chroot (keel-host-keys and 15regen-sslcert make them at the first boot), the site stays enabled, nginx -t is skipped and one line says it runs at the first boot; conf.d/main checks only the links, so the build passes; an edited default, a link of the operator's or none leaves the default server theirs and says so. An upgrade never re-enables a site the operator disabled. The postrm takes both sites out of sites-enabled on remove as on purge (the pages leave with the package) and gives Debian's link back.
  • The anubis state hook swaps keel-default and default-anubis, never Debian's: the two are mutually exclusive on every path, nginx -t refuses them together. A 0.1.1 machine in a cloud mode gets keel-default the next time the overlay is turned off.
  • default-anubis serves the same pages, with the 404/50x pages and server_tokens off; its 443 server has them too, so a 502 while Anubis is down shows the Keel 50x page, not nginx's.
  • /usr/lib/systemd/system/nginx.service.d/keel-web.conf: Wants= and After=keel-host-keys.service. The postinst and postrm run systemctl daemon-reload on a machine.

Recipe (19.0 release 3)

  • services.txt: Web: https://..., which keel_banner_web_scheme reads for the banner. conf.d/main fails the build unless keel-default is enabled, Debian's is not (its file kept), the three pages resolve and the usage screen says https. The overlay's /var/www/html/index.html goes.

Tests

  • tests/package.bats (62): the built package, both sites, the pages, and the postinst and postrm against a scratch root through DPKG_ROOT with a stub dpkg-query.
  • tests/anubis-front.bats (27) and tests/image-conf.bats (20); kcov 100 percent on anubis-front and conf.d/main.
  • tests/site.bats (21), new check site / trixie: on a booted trixie container with Nginx and common's nginx and anubis overlays (built from the pinned 19.x commit; keel, keel-core, anubis and the coraza overlay are equivs stand-ins), nginx -t, /keel-health on both loopbacks and both schemes, the placeholder over HTTP and HTTPS verified against cert.crt, HTTP/2, TLS 1.2/1.3 and not 1.1, Server: nginx with no version, the 404 page, the drop-in, the hook enabled and disabled twice over (443 then answers 502 with the Keel 50x page), dpkg -r (Debian's "Welcome to nginx!" back), -i, -P, -i, the postinst's rollback when nginx -t refuses, and an install with the certificate moved away that keeps the site enabled.

Decisions taken

  • web.listen.ipv4 exists in decision 0042 but not in keel's docs/spec.md, so the file is static with IPv4 on; keel honours the field when it renders the sites (tracker#51), and the file says so.
  • /keel-health on the default site answers everyone, not the loopback only: it is the manifest's probe path and leaks nothing; the loopback on 80 stays the overlay's server.
  • The name keel-default sits in keel's keel-* namespace of 0042 (keel-default.conf with the header). It is what was asked; when tracker#51 lands, keel-web's file and hook give way, as COVERAGE.md's plan records.
  • Nginx without the certificate starts on no port, 80 included. keel-host-keys.service already generates a missing pair (turnkey-make-ssl-cert --default) on every boot and is ordered Before=nginx.service; the drop-in adds Wants=/After= so Nginx pulls it in wherever it is started from. Not an ExecStartPre=: a drop-in's is appended after nginx.service's own nginx -t, which fails first, and replacing the list would copy Debian's line. A Wants= of a unit that is not installed is no error. A certificate present but broken is not covered: nothing short of regenerating it would be.
  • The existing default-anubis keeps cert.crt; the new site uses cert.pem as asked. Both are the same certificate.

Not run here: keel spec apply --system on a built image (the existing jobs do not cover it; tests/README.md describes the run to repeat).

Also: allow_unpublished leaves tests.yml. The appliance job refused it on this branch because the mirror now answers for web.manifest (the attended release of 2026-10-02), which COVERAGE.md plan item 1 said would happen.

On a live Keel Web container (keel-web 0.1.1, `cloud.mode simple`) Nginx served Debian's stock `default` site over an empty `/var/www/html`, so `curl http://host/` got nginx's bare 404, nothing listened on 443, and the usage screen said `http://`. This makes a simple installation serve a proper Keel default site. **keel-web 0.2.0** - `/etc/nginx/sites-available/keel-default`, a conffile like the front: the default server on `[::]:80`, `0.0.0.0:80`, `[::]:443 ssl`, `0.0.0.0:443 ssl`, `http2 on`, `ssl_certificate /etc/ssl/private/cert.pem`, `cert.key`, `ssl_dhparam dhparams.pem`, zz-ssl-ciphers' list, `ssl_session_tickets off`, no HSTS (after ACME, tracker#51), `server_tokens off`. HTTP is served, not redirected (http-01). `/keel-health` answers 204 on both schemes. - Pages at `/var/www/keel-default` (`index.html`, `404.html`, `50x.html`): plain, static, no external resource, no TurnKey wording, no version; they say this is a Keel Web node with no site configured yet and that the operator configures one with confconsole or `/etc/keel/instance.yaml`. Shipped under `/usr/share/keel-web/default-site` (lintian `dir-or-file-in-var-www` is an error); the postinst links `/var/www/keel-default` to it and leaves a directory of the operator's alone. - The postinst enables the site in Debian's place with the care 0042 asks: only an unedited Debian `default` link (nginx-common's conffile checksum) is removed, recorded in `/var/lib/keel-web`, then `nginx -t`, rolled back when refused. While `/etc/ssl/private/cert.pem`, `cert.key` or `dhparams.pem` is missing, as in fab's chroot (keel-host-keys and 15regen-sslcert make them at the first boot), the site stays enabled, `nginx -t` is skipped and one line says it runs at the first boot; `conf.d/main` checks only the links, so the build passes; an edited default, a link of the operator's or none leaves the default server theirs and says so. An upgrade never re-enables a site the operator disabled. The postrm takes both sites out of `sites-enabled` on remove as on purge (the pages leave with the package) and gives Debian's link back. - The anubis state hook swaps `keel-default` and `default-anubis`, never Debian's: the two are mutually exclusive on every path, `nginx -t` refuses them together. A 0.1.1 machine in a cloud mode gets `keel-default` the next time the overlay is turned off. - `default-anubis` serves the same pages, with the 404/50x pages and `server_tokens off`; its 443 server has them too, so a 502 while Anubis is down shows the Keel 50x page, not nginx's. - `/usr/lib/systemd/system/nginx.service.d/keel-web.conf`: `Wants=` and `After=keel-host-keys.service`. The postinst and postrm run `systemctl daemon-reload` on a machine. **Recipe (19.0 release 3)** - `services.txt`: `Web: https://...`, which `keel_banner_web_scheme` reads for the banner. `conf.d/main` fails the build unless `keel-default` is enabled, Debian's is not (its file kept), the three pages resolve and the usage screen says https. The overlay's `/var/www/html/index.html` goes. **Tests** - `tests/package.bats` (62): the built package, both sites, the pages, and the postinst and postrm against a scratch root through `DPKG_ROOT` with a stub `dpkg-query`. - `tests/anubis-front.bats` (27) and `tests/image-conf.bats` (20); kcov 100 percent on `anubis-front` and `conf.d/main`. - `tests/site.bats` (21), new check `site / trixie`: on a booted trixie container with Nginx and common's nginx and anubis overlays (built from the pinned 19.x commit; keel, keel-core, anubis and the coraza overlay are equivs stand-ins), `nginx -t`, `/keel-health` on both loopbacks and both schemes, the placeholder over HTTP and HTTPS verified against `cert.crt`, HTTP/2, TLS 1.2/1.3 and not 1.1, `Server: nginx` with no version, the 404 page, the drop-in, the hook enabled and disabled twice over (443 then answers 502 with the Keel 50x page), `dpkg -r` (Debian's "Welcome to nginx!" back), `-i`, `-P`, `-i`, the postinst's rollback when `nginx -t` refuses, and an install with the certificate moved away that keeps the site enabled. **Decisions taken** - `web.listen.ipv4` exists in decision 0042 but not in keel's `docs/spec.md`, so the file is static with IPv4 on; keel honours the field when it renders the sites (tracker#51), and the file says so. - `/keel-health` on the default site answers everyone, not the loopback only: it is the manifest's probe path and leaks nothing; the loopback on 80 stays the overlay's server. - The name `keel-default` sits in keel's `keel-*` namespace of 0042 (`keel-default.conf` with the header). It is what was asked; when tracker#51 lands, keel-web's file and hook give way, as COVERAGE.md's plan records. - Nginx without the certificate starts on no port, 80 included. keel-host-keys.service already generates a missing pair (`turnkey-make-ssl-cert --default`) on every boot and is ordered `Before=nginx.service`; the drop-in adds `Wants=`/`After=` so Nginx pulls it in wherever it is started from. Not an `ExecStartPre=`: a drop-in's is appended after nginx.service's own `nginx -t`, which fails first, and replacing the list would copy Debian's line. A `Wants=` of a unit that is not installed is no error. A certificate present but broken is not covered: nothing short of regenerating it would be. - The existing `default-anubis` keeps `cert.crt`; the new site uses `cert.pem` as asked. Both are the same certificate. Not run here: `keel spec apply --system` on a built image (the existing jobs do not cover it; `tests/README.md` describes the run to repeat). **Also**: `allow_unpublished` leaves `tests.yml`. The appliance job refused it on this branch because the mirror now answers for `web.manifest` (the attended release of 2026-10-02), which COVERAGE.md plan item 1 said would happen.
Sign in to join this conversation.
No description provided.