Ubuntu Version:
Ubuntu server 25.04
Problem Description:
I need to install Ubuntu server on a machine that doesn’t have a keyboard or screen attached. I don’t have a way of connecting either to it. The machine lives in my local network. I do have physical access.
What I’ve Tried:
When I boot the machine with the ubuntu-25.04-live-server-amd64.iso on a USB-stick, it soon shows up in my network with ubuntu-server as a hostname. When I ssh to it from my PC, the key/fingerprint thing happens, but I can’t login since I don’t have the login information. I’ve looked around, but apparently the ssh password is randomly generated on boot or something?
I’m looking for a way to define ssh login credentials on the install medium so I can ssh into the installer after it boots. I’ve found some information online that this can be done via editing the grub.cfg on the USB-stick, but nothing definitive. Can you help me?
The installer already starts an SSH server. It creates a throw-away user called installer and gives it a random password that only appears on the (missing) screen – that’s why you can’t log in.
Tell cloud-init what password or key you want. Drop a tiny “NoCloud” seed onto the same USB stick and point the kernel at it:On the USB stick
/nocloud/
├─ user-data # your settings
└─ meta-data # just one line: instance-id: nocloud
user-data (minimal example)
#cloud-config
autoinstall:
version: 1
interactive: true # keep the TUI instead of a full autopilot
ssh_authorized_keys:
- ssh-ed25519 .your_public_key
chpasswd:
expire: false
list:
- installer:$6$hash_of_a_password_you_choose
*Add one kernel parameter. Open grub.cfg on the stick, find the “linux” line, and append:
ds=nocloud;s=/cdrom/nocloud/ autoinstall
Boot, then SSH straight in:
ssh installer@<machine-IP>
Use the password you set (or rely on your SSH key). You’ll be dropped into the familiar Subiquity TUI to finish the install.
That’s it — no keyboard, no monitor, just a quick ISO tweak and you’re in. For the full syntax of the user-data file, the official autoinstall reference is handy.
2 Likes
Thank you very much, this seems to be going in the right direction, however it’s not working yet. Maybe you can help me narrow down why:
Here’s my grub.conf:
set timeout=30
loadfont unicode
set menu_color_normal=white/black
set menu_color_highlight=black/light-gray
menuentry "Try or Install Ubuntu Server" {
set gfxpayload=keep
linux /casper/vmlinuz ds=nocloud;s=/cdrom/nocloud/ autoinstall ---
initrd /casper/initrd
}
grub_platform
if [ "$grub_platform" = "efi" ]; then
menuentry 'Boot from next volume' {
exit 1
}
menuentry 'UEFI Firmware Settings' {
fwsetup
}
else
menuentry 'Test memory' {
linux16 /boot/memtest86+x64.bin
}
fi
And here’s my user-data
#cloud-config
autoinstall:
version: 1
identity:
hostname: augustus
interactive: true # keep the TUI instead of a full autopilot
ssh_authorized_keys:
- ssh-ed25519 SHA256:REDACTED
chpasswd:
expire: false
list:
- installer:{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=
(don’t worry, the password hash isn’t the one I’m actually using)
And finally, meta-data:
instance-id: nocloud
As far as I can tell, I’ve done it all correctly, however it doesn’t seem to be parsed at all, since the hostname the machine requests from my router isn’t “augustus” as I’ve specified in user-data, but ubuntu-server as is default.
Any ideas?
Kernel line: make sure the parameter is
before
the
and : —
- linux /casper/vmlinuz ds=nocloud;s=/cdrom/nocloud/ autoinstall ---
+ linux /casper/vmlinuz autoinstall ds=nocloud;s=/cdrom/nocloud/ ---
Everything after the first — is not passed to the kernel, so autoinstall
or ds= written on the wrong side never reach cloud-init.
Folder position
nocloud must sit at the top of the ISO/USB:
/cdrom/nocloud/{user-data,meta-data}
(the same level as casper/, not inside it).
YAML formatting
Use spaces, not tabs — YAML quietly breaks on tabs.
hostname belongs at top level (or as local-hostname:), not underidentity:. For example:
#cloud-config
hostname: augustus
autoinstall:
version: 1
interactive: true
ssh_authorized_keys:
- ssh-ed25519 your_key
chpasswd:
expire: false
list:
- installer:$6$your_hash
meta-data
needs a newline
Make sure instance-id: nocloud ends with an actual newline; some editors
omit it and cloud-init treats the file as empty.
Fix those four things, re-boot, and the box should appear on the network as
augustus and accept the SSH key / password you set. If it still doesn’t,
watch the boot logs (journalctl -b | grep cloud-init) for clues. Good luck!
1 Like
I’ve done that, but I still can’t make it work - the hostname is still unchanged, and then I can’t log in.
I’m afraid I don’t have a way of looking at the boot logs, since I can’t access the machine. Or does it write the boot logs somewhere on the USB stick so I can read them later on another machine?
Next-step debugging tips
Show cloud-init on the console Edit the same kernel line again and append
autoinstall debug --console=tty1
debug makes Subiquity + cloud-init extremely chatty.
console=tty1 keeps that chatter on the main screen, so you can watch it scroll instead of being dropped after the —.
Drop into the emergency shell Still on the kernel line, add one of these (pick whichever you prefer):
break=mount (stops right after the root fs is mounted)
systemd.unit=emergency.target (spawns a root shell early)Either gives you a prompt before the installer finishes, so you can run
journalctl -b | less # full boot log
cat /var/log/cloud-init.log # cloud-init debug
Grab logs from another machine If you can’t get a shell at all, you can still pull the logs offline:
# Live-USB, any Linux box
sudo mkdir /mnt/tgt
sudo mount /dev/sdX2 /mnt/tgt # replace sdX2 with the installed root
sudo less /mnt/tgt/var/log/cloud-init.log
sudo less /mnt/tgt/var/log/installer/subiquity-server-debug.log
The cloud-init and Subiquity logs are kept on the target disk even if the install aborts.
Two quick sanity checks
Hostname still wrong? Make sure the very first line in user-data is either
hostname: augustus
or
local-hostname: augustus
Login failure: Check the key line really begins with ssh-ed25519 (or ssh-rsa) and that the full key is on one line with no extra spaces or line-breaks. Also confirm you placed it under ssh_authorized_keys: without a dash if you only list one key.
Once you have the debug output (or if any of those quick checks fix the issue) post it back here and we can dig deeper. Good luck hope we will solve it.
You have a semi-colon after ds=nocloud
, which is required, but it means grub will treat the rest of the line as a comment. So you have to either escape it with a \
or put the value in quotes.
Do this…
linux /casper/vmlinuz autoinstall ds=nocloud\;s=/cdrom/nocloud/ ---
or this…
linux /casper/vmlinuz autoinstall "ds=nocloud;s=/cdrom/nocloud/" ---
GRUB syntax the semicolon does act as a command separator, so everything that follows is ignored unless you escape or quote it. Either of the two forms you showed works:
grub
# escape just the semicolon
linux /casper/vmlinuz autoinstall ds=nocloud\;s=/cdrom/nocloud/ ---
# …or quote the whole key=value pair
linux /casper/vmlinuz autoinstall "ds=nocloud;s=/cdrom/nocloud/" ---
Once GRUB passes that intact to the kernel you should see cloud-init pick up the seed at /cdrom/nocloud/
and the installer will come up with the hostname, SSH key, and password you defined in user-data.
If you still don’t get an SSH prompt after boot, run
bash
journalctl -b | grep -Ei 'cloud-init|subiquity'
from the console (or add a cheap USB keyboard temporarily) to confirm the NoCloud datasource was detected. But with the semicolon fixed, it normally just works. Thanks for spotting it!