Skip to Content
DocsServerAutoinstall

Ubuntu autoinstall Automated Deployment

autoinstall is the automated installation solution provided by Ubuntu Server’s Subiquity installer. It uses a YAML configuration file to enable unattended server deployment.

How It Works

autoinstall configuration can be provided through:

  1. cloud-init user-data - Passed via the cloud platform’s user-data
  2. Local file - Placed on the installation media or an accessible filesystem
  3. HTTP server - Loaded over the network

The installer searches for autoinstall configuration at startup. Once found, it automatically proceeds with installation without manual intervention.

Basic Configuration Structure

#cloud-config autoinstall: version: 1 # Language and keyboard locale: en_US.UTF-8 keyboard: layout: us # Network configuration network: version: 2 ethernets: eth0: dhcp4: true # Software sources apt: primary: - arches: [default] uri: http://archive.ubuntu.com/ubuntu # Disk configuration storage: layout: name: lvm # User configuration identity: hostname: ubuntu-server username: ubuntu password: "$6$rounds=4096$xyz$hashedpassword" # SSH configuration ssh: install-server: true allow-pw: false authorized-keys: - ssh-ed25519 AAAA... admin@workstation # Post-installation commands late-commands: - curtin in-target -- apt update - curtin in-target -- apt upgrade -y

Full Configuration Examples

Standard Server Installation

#cloud-config autoinstall: version: 1 # Interactive settings (which steps require manual confirmation) interactive-sections: [] # Empty means fully automatic locale: en_US.UTF-8 keyboard: layout: us variant: "" # Use updated installer refresh-installer: update: true # Network network: version: 2 ethernets: ens33: dhcp4: false addresses: - 192.168.1.100/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: - 8.8.8.8 - 1.1.1.1 # Proxy (leave empty if not used) proxy: "" # APT mirror apt: primary: - arches: [amd64] uri: http://archive.ubuntu.com/ubuntu geoip: false # Storage configuration - using LVM storage: layout: name: lvm sizing-policy: scaled # Or specify root partition size # sizing-policy: all # System identity identity: hostname: prod-web-01 username: deploy # Generated with: mkpasswd --method=sha-512 password: "$6$rounds=4096$saltsalt$hashedpasswordhere" # SSH ssh: install-server: true allow-pw: false authorized-keys: - ssh-ed25519 AAAA... deploy@admin # Snap packages to install snaps: - name: docker channel: latest/stable classic: false # Deb packages to install packages: - ubuntu-server-minimal - vim - htop - curl - wget - git - ufw - fail2ban # Automatic security updates updates: security # Post-installation commands late-commands: # Set timezone - curtin in-target -- timedatectl set-timezone America/New_York # Configure firewall - curtin in-target -- ufw allow ssh - curtin in-target -- ufw --force enable # Write custom configuration files - | cat <<'SYSCTL' > /target/etc/sysctl.d/99-custom.conf net.ipv4.ip_forward = 1 net.core.somaxconn = 65535 vm.swappiness = 10 SYSCTL # Enable services - curtin in-target -- systemctl enable fail2ban # Reboot automatically after installation completes shutdown: reboot

Custom Partitioning Scheme

#cloud-config autoinstall: version: 1 locale: en_US.UTF-8 storage: config: # Disk - id: disk0 type: disk ptable: gpt path: /dev/sda wipe: superblock-recursive grub_device: false # EFI partition - id: efi-part type: partition device: disk0 size: 512M flag: boot grub_device: true # Boot partition - id: boot-part type: partition device: disk0 size: 1G # Remaining space for LVM - id: lvm-part type: partition device: disk0 size: -1 # All remaining space # EFI filesystem - id: efi-fs type: format volume: efi-part fstype: fat32 # Boot filesystem - id: boot-fs type: format volume: boot-part fstype: ext4 # LVM volume group - id: vg0 type: lvm_volgroup name: vg0 devices: - lvm-part # LVM logical volume - root - id: lv-root type: lvm_partition volgroup: vg0 name: lv-root size: 20G # LVM logical volume - var - id: lv-var type: lvm_partition volgroup: vg0 name: lv-var size: 30G # LVM logical volume - home - id: lv-home type: lvm_partition volgroup: vg0 name: lv-home size: -1 # Format logical volumes - id: root-fs type: format volume: lv-root fstype: ext4 - id: var-fs type: format volume: lv-var fstype: ext4 - id: home-fs type: format volume: lv-home fstype: ext4 # Mount points - id: mount-efi type: mount device: efi-fs path: /boot/efi - id: mount-boot type: mount device: boot-fs path: /boot - id: mount-root type: mount device: root-fs path: / - id: mount-var type: mount device: var-fs path: /var - id: mount-home type: mount device: home-fs path: /home identity: hostname: custom-server username: admin password: "$6$rounds=4096$saltsalt$hash" ssh: install-server: true

Providing the autoinstall Configuration

Method 1: Modify the ISO

# Mount the original ISO mkdir -p /mnt/iso sudo mount -o loop ubuntu-26.04-live-server-amd64.iso /mnt/iso # Copy the contents mkdir -p ~/custom-iso cp -rT /mnt/iso ~/custom-iso sudo umount /mnt/iso # Add the autoinstall configuration mkdir -p ~/custom-iso/autoinstall cp autoinstall.yaml ~/custom-iso/autoinstall/user-data touch ~/custom-iso/autoinstall/meta-data # Modify the GRUB configuration to add an autoinstall boot entry # Add the following to ~/custom-iso/boot/grub/grub.cfg: cat >> ~/custom-iso/boot/grub/grub.cfg << 'EOF' menuentry "Autoinstall Ubuntu Server" { set gfxpayload=keep linux /casper/vmlinuz autoinstall ds=nocloud\;s=/cdrom/autoinstall/ --- initrd /casper/initrd } EOF # Regenerate the ISO sudo apt install xorriso -y xorriso -as mkisofs \ -r -V "Ubuntu 26.04 Autoinstall" \ -o ~/ubuntu-26.04-autoinstall.iso \ -J -joliet-long \ --grub2-mbr /usr/lib/grub/i386-pc/boot_hybrid.img \ -partition_offset 16 \ -append_partition 2 0xEF ~/custom-iso/boot/grub/efi.img \ -appended_part_as_gpt \ -eltorito-boot boot/grub/bios.img \ -eltorito-catalog boot/grub/boot.cat \ --no-emul-boot -boot-load-size 4 -boot-info-table --grub2-boot-info \ -eltorito-alt-boot -e '--interval:appended_partition_2:all::' --no-emul-boot \ ~/custom-iso

Method 2: HTTP Server

# Start an HTTP server on another machine mkdir -p ~/autoinstall-server cp autoinstall.yaml ~/autoinstall-server/user-data touch ~/autoinstall-server/meta-data cd ~/autoinstall-server python3 -m http.server 8080 # During installation, add the kernel parameter in the GRUB command line: # autoinstall ds=nocloud-net;s=http://192.168.1.50:8080/

Method 3: PXE Network Boot

Suitable for large-scale deployment, combined with TFTP + HTTP servers:

# Install PXE-related software sudo apt install tftpd-hpa -y # Place the kernel and initrd in the TFTP directory sudo cp /mnt/iso/casper/vmlinuz /srv/tftp/ sudo cp /mnt/iso/casper/initrd /srv/tftp/ # Add kernel parameters in the PXE configuration # kernel vmlinuz # append initrd=initrd autoinstall ds=nocloud-net;s=http://192.168.1.50:8080/ ---

Generate a Password Hash

# Method 1: Using mkpasswd sudo apt install whois -y mkpasswd --method=sha-512 # Method 2: Using openssl openssl passwd -6 # Note: Python 3.13 removed the crypt module; use the mkpasswd or openssl methods above instead

Export an Existing System’s autoinstall Configuration

After installation, you can export the current system’s install configuration to use as a template:

# View the autoinstall configuration used during installation sudo cat /var/log/installer/autoinstall-user-data # This file contains the full installation configuration and can be reused as a template

Validate the Configuration

# Validate syntax with cloud-init cloud-init schema --config-file autoinstall.yaml # Check YAML format with Python python3 -c "import yaml; yaml.safe_load(open('autoinstall.yaml'))"

Common Issues

Installation Stalls at a Confirmation Step

Make sure interactive-sections is set to an empty list:

autoinstall: interactive-sections: []

Network Configuration Not Applied

Verify the network interface name is correct. You can check the actual interface name in the installation environment with ip link.

late-commands Failing

  • Use the curtin in-target -- prefix to execute commands inside the target system
  • For direct path operations, use the /target/ prefix
  • Check logs at: /var/log/installer/curtin-install.log
Last updated on