Files
ansible-pull-deploy/ubuntu-autoinstall

Ubuntu Server Autoinstall — Iron Legion G9

Headless, zero-touch Ubuntu 24.04 LTS deployment for GMKtec G9 mini-PCs. Replaces MAAS for small batches. Fully autonomous after USB boot.

Files

File Purpose
autoinstall.yaml Main config — save as user-data on USB
meta-data Empty companion file (required by nocloud)

Quick Start

1. Create the USB stick

  1. Download Ubuntu Server 24.04 LTS ISO (not Desktop)
  2. Flash to USB with Rufus (Windows) or dd (Linux)
    • Partition scheme: GPT
    • Target system: UEFI (non-CSM)
  3. Mount the USB's writable partition

2. Add autoinstall files

Create these two files in the root of the USB's writable partition:

user-data — copy autoinstall.yaml and rename it to user-data (no extension):

cp autoinstall.yaml /media/usb/user-data

meta-data — create an empty file literally named meta-data (no extension):

touch /media/usb/meta-data

Optional content for meta-data:

instance-id: iid-ironlegion01
local-hostname: ubuntu

3. Configure GRUB for headless boot

Edit boot/grub/grub.cfg on the USB. Find the first menuentry and add kernel params:

set timeout=5

menuentry "Try or Install Ubuntu Server" {
    linux   /casper/vmlinuz autoinstall ds=nocloud\;s=/cdrom/ quiet ---
    initrd  /casper/initrd
}

timeout=5 means 5-second countdown then auto-boots. Fully headless.

4. Boot the G9

  1. Plug USB into G9
  2. Power on
  3. Walk away — 5 minutes later it's done
  4. SSH in as jarvis / ubuntu

What Happens

Stage Action
Boot Ubuntu Server installer loads from USB
Storage GPT on /dev/nvme0n1 — 1GB boot + rest root (ext4)
Identity Creates jarvis user with fleet SSH key
Hostname Sets from MAC → mk-33, mk-34, mk-39, mk-42, or g9-<last4>
Packages Installs Docker, Tailscale, git, curl, ufw, nfs-common
Docker Adds jarvis to docker group
Tailscale Installed, ready for tailscale up
Ansible Clones ansible-pull-deploy repo to ~/.ansible-repo
Network Wildcard DHCP on all en* interfaces
SSH Open on port 22, password auth enabled (fleet standard)
Firewall UFW enabled — allows SSH only
Final Reboots into fresh system

Post-Install (one command per node)

After the node is up:

# Join Tailscale (interactive — generates auth URL)
sudo tailscale up

# Or with pre-generated auth key:
sudo tailscale up --auth-key=tskey-auth-xxxxxxxx

# Run ansible-pull for remaining fleet config
cd ~/.ansible-repo && ansible-pull -U https://gitea.nb.bobbysh.me/Iron-Legion/ansible-pull-deploy.git -d .

MAC-to-Hostname Mapping

MAC Hostname
e0:51:d8:1c:5d:56 mk-33
e0:51:d8:1c:5c:75 mk-34
e0:51:d8:1c:5d:ca mk-39
e0:51:d8:1c:5d:5c mk-42
other g9-<last4mac>

Tailscale Auth Key

To auto-join without interaction, generate a reusable auth key:

tailscale login  # on Artemis or any node
tailscale web
tailscale authkeys create --reusable --preauthorized --tags=tag:g9

Add the key to late-commands in autoinstall.yaml:

- sudo tailscale up --auth-key=tskey-auth-xxxxxxxx

Troubleshooting

Symptom Fix
Stops at boot menu Check GRUB timeout is set, not # commented
Can't find user-data Verify files are on writable partition root, not inside a folder
Wrong disk Confirm G9 has 1TB NVMe in first slot (/dev/nvme0n1)
Hostname is ubuntu Check MAC is correct; check /etc/cloud/cloud-init.disabled exists
No SSH Verify openssh-server installed; check ufw status

Differences from MAAS

MAAS Autoinstall
PXE server Required (Shield) Not needed
Subnet Isolated /27 required Any network with DHCP
Internet during install Not available Available via your LAN
Time per node 15-30 min ~5 min
Touch required Power on + rename in UI Zero (headless)
Scale Excellent for 10+ nodes Ideal for 1-10 nodes
Phase 2 bootstrap Required manually Included in late-commands

Notes

  • Password is fleet standard: ubuntu
  • SSH key is the same fleet-wide key used on all nodes
  • Cloud-init is disabled post-install to prevent hostname stomping
  • If you get more G9s, just update the MAC→hostname mapping and re-flash

Version

  • Ubuntu 24.04 LTS (Noble Numbat)
  • Docker CE latest
  • Tailscale stable
  • Ansible 2.x (pulled from repo)