Ubuntu autoinstall
Author, validate, and debug Ubuntu Server autoinstall configuration (the Subiquity installer's `autoinstall:` schema, version 1) for Ubuntu Server LTS 24.04 and 26.04, focused on unattended on-premise and air-gapped installs — identity, storage (LVM/direct/ZFS/encryption/RAID), apt mirror-selection + proxy + offline fallback, ssh, packages, kernel, late-commands/early-commands, and zero-touch delivery via a NoCloud seed. The `network:` block is netplan v2 (use the ubuntu-netplan skill); the `user-data:` block is cloud-config for the installed system (use the ubuntu-cloud-init skill).From its SKILL.md
npx -y skills add air-gapped/skills --skill ubuntu-autoinstallAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
11.0 KB, ~2.6k tokens by cl100k_base, as published. Nobody here has run it
ubuntu-autoinstall
Autoinstall is the configuration format for Ubuntu Server's Subiquity installer.
A version: 1 document tells the installer how to partition, install, and configure
the system unattended. This skill is authoring-led (produce a correct
autoinstall config from a description) with a strong validation/debug path, aimed at
unattended on-prem / air-gapped Ubuntu Server LTS installs.
Autoinstall nests the other two domains:
- its
network:key is netplan v2 → use the ubuntu-netplan skill; - its
user-data:key is cloud-config for the installed system → use the ubuntu-cloud-init skill; - and the config is itself delivered via cloud-init NoCloud.
See The two delegation boundaries and Delivery.
Authoring workflow
- Pick the delivery method (Delivery, below). Air-gapped → usually a NoCloud seed on the ISO/USB or an HTTP seed.
- Write the
version: 1document.versionis the only schema-required key, butidentityis required at runtime unlessuser-data:is present. - Set the air-gapped essentials — local mirror, proxy, offline fallback (see the Air-gapped essentials section below for the exact keys).
- Author
network:as netplan v2 (ubuntu-netplan skill) and any installed-system first-boot config underuser-data:(ubuntu-cloud-init skill). - Validate with the subiquity repo's
validate-autoinstall-user-data.py(see Validation — the script ships in the installer source, not in this skill). - Boot with the
autoinstallkernel keyword to skip the disk-wipe confirmation for true zero-touch.
The two delegation boundaries (critical)
#cloud-config
# (1) top-level cloud-config here configures the EPHEMERAL installer environment
autoinstall: # processed by Subiquity → configures the TARGET system
version: 1
network: # (2) netplan v2 → ubuntu-netplan skill
version: 2
ethernets: { ... }
identity: { ... }
user-data: # (3) cloud-config → ubuntu-cloud-init skill
# runs on the INSTALLED system's FIRST BOOT (not at install time)
packages: [ ... ]
network:is netplan v2 only. Default if omitted is DHCPv4 onen*/eth*.match:insideethernetsaccepts onlyname/macaddress/driver. (A rarely-used double-wrappednetwork: {network: {...}}form also validates; prefer the plain form.)user-data:is cloud-config for the installed system, merged with the installer-generated user-data. Timing matters: users fromidentityare created during install; users defined inuser-dataare created on first boot. Supplyinguser-datamakesidentityoptional — but then ensure a login path exists. Don't define the same user in both.
Delivery & the NoCloud seed
Autoinstall config reaches the installer in two families:
- Via cloud-init
#cloud-configuser-data — requires the#cloud-configfirst line and the config nested under a top-levelautoinstall:key. - Directly on the install media as a file named
autoinstall.yaml— here theautoinstall:wrapper is optional (a bareversion: 1 ...works). This wrapper acceptance for on-media files arrived in 24.04.
Precedence — the installer uses the FIRST that exists:
--autoinstall <path>CLI arg (empty string explicitly disables autoinstall)- kernel cmdline
subiquity.autoinstallpath=... autoinstall.yamlat the root of the install system- cloud-config-supplied
run/subiquity/cloud.autoinstall.yaml cdrom/autoinstall.yamlbaked into the ISO
So kernel cmdline and on-media files outrank cloud-config.
NoCloud seeding (the on-prem workhorse — see the ubuntu-cloud-init skill for full NoCloud detail):
- HTTP seed: kernel cmdline
autoinstall ds=nocloud-net;s=http://SERVER:PORT/, servinguser-data+meta-data(+ optionalnetwork-config) at that base URL. - Volume seed (USB/ISO): build with
cloud-localds seed.iso user-data meta-data; cloud-init finds it by thecidata/CIDATAfilesystem label.meta-datamust exist (may be empty:touch meta-data). - The bare
autoinstallkernel keyword is separate fromds=— it suppresses the interactive "Continue with autoinstall?" disk-wipe confirmation. True zero-touch needs both the config delivery andautoinstallon the cmdline. - Quote the whole kernel
-append '... ds=nocloud-net;s=...'—;is a shell metacharacter (and ends a GRUB statement).
Full delivery/seeding detail (precedence source, ISO remastering, the on-media
"only the autoinstall key" rule) is in references/delivery-and-seeding.md.
Top-level schema (version 1) — quick reference
Only version is schema-required; unknown keys produce a warning in v1 (will be
fatal in a future version). Common keys:
| Key | Purpose |
|---|---|
version | Must be 1. Required. |
identity | Initial user {realname, username, hostname, password}. Required at runtime unless user-data: present. |
storage | Disk layout — layout: {name: lvm|direct|zfs|hybrid} or a curtin action list. |
network | netplan v2 (→ ubuntu-netplan skill). |
ssh | {install-server, authorized-keys, allow-pw}. |
apt | Mirror selection, proxy, components, fallback (air-gapped core). |
proxy | HTTP proxy for install + target apt/snapd. |
packages / snaps | Extra packages / snaps to install. |
user-data | cloud-config for the installed system (→ ubuntu-cloud-init skill). |
late-commands | Commands after install (target mounted at /target). |
early-commands | Commands before probing (config is re-read after). |
interactive-sections | Sections to still prompt for; must be a list (['*'], not '*'). |
updates | security (default) or all. |
refresh-installer | {update: bool, channel} — installer self-update (set false air-gapped). |
kernel | {package} or {flavor}. |
timezone, locale, keyboard, source, drivers, codecs, oem, reporting, error-commands | see references/schema.md. |
kernel-crash-dumps, zdevs | 24.10+ only — not in 24.04. |
Full per-key reference (storage layouts, apt mirror-selection details, identity, ssh,
command timing) is in references/schema.md.
Air-gapped essentials
refresh-installer:
update: false # don't try to self-update from the snap store
proxy: http://proxy.internal:3128 # NOT applied to the geoip lookup
apt:
geoip: false # disable geoip.ubuntu.com lookup (10s hang otherwise)
preserve_sources_list: false
mirror-selection:
primary:
- uri: "http://mirror.internal/ubuntu"
arches: [amd64]
fallback: abort # set explicitly; don't silently go offline-from-ISO
updates: security
- Wrapping
primaryinsidemirror-selectionenables Subiquity's mirror probing (picks the first usable). A bareprimary:list uses legacy curtin behavior. apt.fallback∈abort|offline-install|continue-anyway. The docs disagree on the default — always set it explicitly.offline-installfalls back to the ISO's seed;continue-anywayis not recommended.- Snaps requiring the store fail offline — only ship snaps seeded on the ISO, or omit
snaps:.source.id: ubuntu-server-minimalreduces footprint.
storage (quick)
storage:
layout:
name: lvm # lvm | direct | zfs | hybrid
password: LUKS_PASSPHRASE # LVM + LUKS
sizing-policy: all # use whole VG ('scaled' default leaves snapshot room)
Pick a disk with match: {ssd: true} / {serial: ...} / {size: largest}. For
advanced partitioning use a curtin config: action list (when layout is present,
config is ignored). See references/schema.md.
Validation & debugging
# validate-autoinstall-user-data.py ships in the subiquity SOURCE repo — it is NOT
# bundled in this skill. Get it with: git clone https://github.com/canonical/subiquity
# && cd subiquity && make install_deps. Run from that checkout, NEVER as sudo:
python3 scripts/validate-autoinstall-user-data.py user-data # #cloud-config-wrapped
python3 scripts/validate-autoinstall-user-data.py --no-expect-cloudconfig autoinstall.yaml
cloud-init schema -c user-data # validate the cloud-config body
Install logs live in /var/log/installer/; the delivered autoinstall (with password
hash) is saved to /var/log/installer/autoinstall-user-data. Full validation
workflow, the JSON schema location, and common pitfalls are in
references/validation-and-debugging.md.
Common pitfalls
- Missing
#cloud-configheader, or a misspelledautoinstall:key → the installer goes interactive instead of crashing. - In the on-media
autoinstall.yaml, no other top-level keys may sit besideautoinstall:— it's fatal. (The#cloud-configdelivery is the opposite: top-level cloud-config configures the installer env.) late-commandsrun in the installer environment; the target is at/target. Usecurtin in-target -- <cmd>to run inside the installed system.interactive-sections: '*'(string) fails schema — use['*']. If any interactive section is set,reportingis ignored.- Quote the password hash and the kernel
-appendstring. - Don't pin a
kernel:together withoem.install: true(conflicting requirements).
Reference files
references/schema.md— full top-level key reference: storage layouts & curtin actions, apt mirror-selection, identity/ssh, command timing, all keys. (Has a TOC.)references/delivery-and-seeding.md— delivery precedence, NoCloud seeds, ISO/USB, HTTP serving, zero-touch, the on-media rules.references/validation-and-debugging.md— the validator script, JSON schema, logs, pitfalls, and 24.04-vs-26.04 version notes.references/examples.md— minimal config + a complete air-gapped server install.
What ships with it: 7 files
34.4 KB alongside SKILL.md
references/
- delivery-and-seeding.md4.4 KB
- examples.md3.2 KB
- improvement-backlog.md6.6 KB
- schema.md8.6 KB
- sources.md4.9 KB
- trigger-evals.json1.8 KB
- validation-and-debugging.md5.0 KB