You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
nginx site role writes http2 on; (nginx >= 1.25.1) and leaves an invalid vhost enabled when validation fails #66
Converging a new domain (domains.yml, cloudfall_nginx_site) on a Debian 12 host with nginx 1.22.1 wrote a virtual host containing http2 on;. That directive exists only from nginx 1.25.1, so nginx -t failed:
[emerg] unknown directive "http2" in /etc/nginx/sites-enabled/demo.cloudfall.dev.conf:19
The role's validation worked: nginx was not reloaded, and the running sites kept serving. But the failed vhost stayed in sites-available and enabled in sites-enabled, so the host's configuration on disk no longer passed nginx -t. Any later reload (a certbot renewal hook, another deploy, a restart after a reboot) would have failed for every site on that host. It was repaired by hand within minutes (listen 443 ssl http2;, the pre-1.25 form).
Two defects
The template assumes nginx ≥ 1.25.1. Debian 12 ships 1.22.1. The vhost should use listen ... ssl http2; below 1.25.1 and http2 on; from it, keyed on the installed version (the role can read nginx -v or the package version), or leave HTTP/2 out when it cannot tell
A vhost that fails validation is left enabled. When nginx -t fails after the vhost is written, the role should restore the previous file (or remove a new one and its sites-enabled link) before failing, so a failed converge never leaves the host's configuration invalid on disk
Reproduce
Debian 12, nginx from the distribution, any declared Domain with tls.mode: required, run domains.yml with certificate issuance.
Notes
Found deploying the hackathon demo to a production host; that host's vhost now differs from the template until this is fixed, so the next converge there must wait for the fix.
Triage: implement. Both defects are confirmed on main (070c781):
templates/domain-site.conf.j2 always writes listen 443 ssl; plus http2 on; in the TLS server block, whatever nginx is installed
tasks/main.yml renders the vhost, links it into sites-enabled, and only then runs nginx -t; a failed check stops the play with the new file and link left in place. This holds for both renders (the HTTP-only one before issuance and the TLS one after)
Plan, one PR:
Read the installed nginx version on the host (nginx -v, which prints to stderr) after the install task, and fail the converge with a clear message when it can't be parsed, rather than guessing. The template writes listen 443 ssl http2; / listen [::]:443 ssl http2; below 1.25.1 and http2 on; from 1.25.1. A template test covers both sides of 1.25.1
Wrap render, enable and nginx -t in a block/rescue: before rendering, note whether the vhost file and its sites-enabled link existed and keep a backup of the previous file; on a failed nginx -t, restore the previous file (or remove a new file and the link it created), then fail with nginx's error. Nginx is never reloaded on a failed check, as now
No change to the Domain schema, the receipt, or the rendered output on nginx ≥ 1.25.1
On the production host repaired by hand: the next converge rewrites the vhost from the template, which on its nginx 1.22.1 will then render the same listen 443 ssl http2; form, so it can run once this lands.
Triage: #67 fixes both defects. The role reads nginx -v and fails the converge when it can't parse it; below 1.25.1 the vhost uses listen 443 ssl http2;, and from 1.25.1 the output is byte-identical to before. Each render runs as a block/rescue behind nginx -t: a rejected render restores the previous file (or removes a new file and the link this run created), then fails without reloading.
Trade-offs: nginx is now started only after the first nginx -t passes, and the certbot timer is enabled only after the final check passes. The rollback path is covered by task-level tests, lint and the syntax check, but has not yet run against a live host.
Activity
shipmill-romamo commentedon Oct 9, 2026
Triage: implement. Both defects are confirmed on
main(070c781):templates/domain-site.conf.j2always writeslisten 443 ssl;plushttp2 on;in the TLS server block, whatever nginx is installedtasks/main.ymlrenders the vhost, links it intosites-enabled, and only then runsnginx -t; a failed check stops the play with the new file and link left in place. This holds for both renders (the HTTP-only one before issuance and the TLS one after)Plan, one PR:
nginx -v, which prints to stderr) after the install task, and fail the converge with a clear message when it can't be parsed, rather than guessing. The template writeslisten 443 ssl http2;/listen [::]:443 ssl http2;below 1.25.1 andhttp2 on;from 1.25.1. A template test covers both sides of 1.25.1nginx -tin ablock/rescue: before rendering, note whether the vhost file and itssites-enabledlink existed and keep a backup of the previous file; on a failednginx -t, restore the previous file (or remove a new file and the link it created), then fail with nginx's error. Nginx is never reloaded on a failed check, as nowOn the production host repaired by hand: the next converge rewrites the vhost from the template, which on its nginx 1.22.1 will then render the same
listen 443 ssl http2;form, so it can run once this lands.shipmill-romamo commentedon Oct 9, 2026
Triage: #67 fixes both defects. The role reads
nginx -vand fails the converge when it can't parse it; below 1.25.1 the vhost useslisten 443 ssl http2;, and from 1.25.1 the output is byte-identical to before. Each render runs as ablock/rescuebehindnginx -t: a rejected render restores the previous file (or removes a new file and the link this run created), then fails without reloading.Trade-offs: nginx is now started only after the first
nginx -tpasses, and the certbot timer is enabled only after the final check passes. The rollback path is covered by task-level tests, lint and the syntax check, but has not yet run against a live host.shipmill-romamo commentedon Oct 9, 2026
Released in v0.6.0rc12.