Repository navigation
fix: a first boot nobody can answer asks nothing, and names the machine - #39
Merged
Merged
Conversation
Three findings of the Web 19.0-3 booted headless in an LXC container with no console attached (2026-10-03). 31fqdn stopped the first boot for good: unless FQDN=SKIP was preseeded, its screen waited on tty1, a pty nobody read. lib/console.sh is now the one rule for run's notices and for every hook that draws a screen (30rootpass, 31fqdn, 75keel-role and 80keel-cloud through lib/keel-firstboot.sh, 85secalerts, 95secupdates, 99reboot): nobody can answer a console with no size, one that does not take a 128 KiB probe of NUL bytes within 2 s (an unread pty blocks after about 17 KB, so a small write passes and the screen after it hangs), or no terminal at all. run asks once, exports the answer as INITHOOKS_UNATTENDED, and sends the hooks' output to the inithooks log from then on, since a console nobody reads blocks its writer once full. Each hook does what it does with no answer and logs one line: the password is kept, the name is kept and recorded as instance.hostname and instance.fqdn when it has a domain, confconsole's screens run without a terminal, no alert email is set, and security updates are installed and a new kernel rebooted into as SEC_UPDATES=FORCE does, the headless preseed's value. /etc/hosts had no line for the hostname when 31fqdn was skipped: common drops 127.0.1.1 at export and 31fqdn wrote the entry only for an answer. 31fqdn now always ends with `127.0.1.1 <fqdn> <hostname>`, or `127.0.1.1 <hostname>`, the form keel spec apply --system writes; a kept name keeps the domain its hosts line gives it (fqdn.py --machine). The certificate said CN=core on a machine named web. turnkey-make-ssl-cert given no names takes them from `hostname -A`, a reverse lookup of the machine's addresses. 15regen-sslcert now passes the fqdn and hostname, with --ip (lib/sslcert.sh), and 31fqdn makes the certificate again when the settled name is not the CN of a self-signed one; a certificate an authority signed is kept. No key is generated at build time.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three findings of the Web image (keel-web 19.0-3, inithooks 2.3.6+keel21) booted headless in an LXC container with no console attached, 2026-10-03.
1.
31fqdnheld the first boot. UnlessFQDN=SKIPwas preseeded, its screen waited on tty1, a pty nobody reads.lib/console.shis now the one rule forrun's notices and every hook that draws a screen. Nobody can answer a console with no size (stty0 0), one that does not take a 128 KiB NUL probe within 2 s, or no terminal at all. A small write is not enough: an unread pty takes about 17 KB before it blocks (measured on 6.12), so the screen after a small write would still hang.runasks once and exportsINITHOOKS_UNATTENDED. From then on the hooks' output goes to the inithooks log, because a console nobody reads blocks its writer once its buffer is full (95secupdates prints the whole upgrade). Each hook logs one line and does what it does with no answer:SEC_UPDATES=FORCE(the headless preseed) doesThe README's preseed example lists
FQDNand says an unattended boot skips the questions.2.
CN=coreon a machine namedweb. Given no names, the fork'sturnkey-make-ssl-certsets CN and SAN fromhostname -A, a reverse lookup of every address, which falls back tohostname. It supports SANs and--ip. 15regen-sslcert now passes the fqdn and the hostname with--ip(lib/sslcert.sh, names fromfqdn.py --machine, no DNS). 31fqdn makes the certificate again when the name it settles is not the CN of a self-signed one. A certificate signed by an authority (confconsole's Let's Encrypt writes the same files) is kept. Nothing is generated at build time.3. No
/etc/hostsline after a skip. 31fqdn now ends every first boot with127.0.1.1 <fqdn> <hostname>, or127.0.1.1 <hostname>without a domain, which matches what keel'sapply --systemwrites (keel/system/hosts.py). A kept name keeps the domain its hosts line already gives it.Tested. New
tests/test-console.bats: every interactive hook runs on an unsized pty and on a sized pty whose master is never read, within a deadline, and must finish. Run against master's 31fqdn, those tests fail. Also added: hosts and certificate tests intest-fqdn.bats(CN after a rename with real openssl),test-run.bats,test-secupdates.bats,test-keel-firstboot.bats,test-regen-sslcert.bats, and pytest for--machine. Local run: 367 bats, including the real-dialog pty tests, and 530 pytest. Shell coverage is 99.69 and Python 99.