Running TAIL OS in QEMU
Try TAIL OS on your Linux machine in under two minutes — no hardware, no toolchain. For installing TAIL OS on real Raspberry Pi 3 hardware, see Installing on Raspberry Pi 3.
Prerequisites
| Item | Install command |
|---|---|
| Linux host (Ubuntu 22.04 / 24.04 tested) | — |
qemu-system-aarch64 |
sudo apt-get install -y qemu-system-arm qemu-utils |
curl or wget |
usually preinstalled |
That's it. Everything else is bundled in the prebuilt images.
Run TAIL OS
Download the launcher, then run it:
curl -O https://tail-os.com/downloads/run_tailos_qemu.sh
chmod +x run_tailos_qemu.sh
./run_tailos_qemu.sh
The launcher will:
- Check that QEMU is installed.
- Download
tail_qemu.rfs(kernel) andtail_disk.img(data disk) into~/.cache/tailos/, verifying each against the publishedSHA256SUMS. Later runs reuse the cache until a new image is published. - Boot TAIL OS in QEMU with the correct flags.
When you see /$, the system is ready. Exit QEMU with Ctrl-A, then lowercase x. Booting it
again is ./run_tailos_qemu.sh: it starts from the cached images.
Try the Shell
/$ help
/$ pwd
/$ ls /usr/bin
/$ /usr/bin/ps
/$ cd /usr/bin
/usr/bin$ exit
The prompt shows the current directory (it changes after cd). The shell also
supports arrow-key history, per-process cwd, and background jobs
with &.
exit ends the shell, and no new one starts: nothing runs and no prompt returns, though
what you type still echoes. Quit QEMU with Ctrl-A, then lowercase x.
Manual Launch (alternative)
If you prefer not to run a remote script, do it by hand:
# 1. Install QEMU
sudo apt-get install -y qemu-system-arm qemu-utils
# 2. Download the images, unpack them, and check them
curl -fsSLO https://tail-os.com/downloads/tail_qemu.rfs.gz
curl -fsSLO https://tail-os.com/downloads/tail_disk.img.gz
curl -fsSLO https://tail-os.com/downloads/SHA256SUMS
gunzip tail_qemu.rfs.gz tail_disk.img.gz
sha256sum -c --ignore-missing SHA256SUMS
# 3. Boot
qemu-system-aarch64 \
-M raspi3b \
-kernel tail_qemu.rfs \
-serial mon:stdio \
-display none \
-drive file=tail_disk.img,format=raw,if=sd \
-netdev user,id=tailnet0 \
-device usb-net,netdev=tailnet0
What's Inside the Images
tail_qemu.rfs is a custom ELF container that bundles the entire OS, 16 components:
tail_qemu.rfs
├── aarch64-startup Early boot (EL3 -> EL1, MMU, jump to kernel)
├── kernel Microkernel (process, thread, IPC, scheduler)
├── uart_pl011 UART + TTY server (user-space)
├── gpio_rpi3 GPIO controller driver
├── sd_sdhost_rpi3 SD card block driver (user-space)
├── fat_file_system_server Mounts tail_disk.img as "/"
├── read_only_file_system_server Serves these files at /rfs
├── log_server System log
├── logview Copies logged errors to the console
├── pipe_server Pipes between processes
├── dwc2_rpi3 USB host controller driver
├── network Network stack
├── netdev_lo_module Loopback network device
├── route Sets the default route at boot
├── debug_server GDB remote protocol stub (packed, not started)
└── tsh Shell
ls /rfs lists them, and the shell itself is /rfs/tsh. /rfs does not appear in
ls /, because ls / lists the root directory of the FAT disk, and /rfs is a separate
file system mounted beside it rather than a directory on that disk. Paths under it work:
which tsh prints /rfs/tsh.
tail_disk.img is exposed to the guest as an SD card. It has two FAT32 partitions, laid
out like the Raspberry Pi 3 image: the first, 64 MiB, is the boot partition a real Pi
reads its firmware from, and it is empty here, because QEMU loads tail_qemu.rfs
directly. The second is mounted as / and holds:
tail_disk.img
├── /etc/hosts, /etc/resolv.conf Name lookup
├── /hello.py Example Python script
├── /usr/bin/ 27 programs: ls, ps, top, vi, python, ping, ... (*)
└── /usr/lib/python3.14/,
/usr/lib/python314.zip Python 3.14 standard library
(*) Plus list-root-long, a copy of ls under a long file name that shows the FAT
server's long-name support, so ls /usr/bin lists 28 names.
Boot Sequence
qemu-system-aarch64 -M raspi3b
|
v
QEMU loads tail_qemu.rfs at 0x80000 (raspi3b entry point)
|
v
TAIL OS startup (aarch64-startup)
|-- Switch EL3 -> EL1
|-- Initialize MMU, caches
|-- Jump to kernel
v
TAIL OS kernel
|-- Initialize process/thread/IPC/memory subsystems
|-- Load user-space servers from RFS
|-- Mount tail_disk.img as "/" via SD + FAT
|-- Start tsh shell
v
/$ _
Troubleshooting
qemu-system-aarch64: command not found:
Install QEMU with sudo apt-get install -y qemu-system-arm qemu-utils.
No output at all in the QEMU window:
The launcher passes -serial mon:stdio for you. If you're running QEMU by
hand, make sure that flag is present — otherwise UART output goes nowhere
visible.
Want to force a fresh download:
Clear the cache: rm -rf ~/.cache/tailos and re-run the launcher.
QEMU boots but hangs before /$:
The FAT filesystem takes several seconds to initialize on first boot; give it
up to a minute. If it never appears, re-download the images (the cached copy
may be corrupted) with rm -rf ~/.cache/tailos.
Exiting:
Inside QEMU, press Ctrl-A, then lowercase x to quit. Ctrl-A, then lowercase c
drops into the QEMU monitor (type quit). Uppercase X and C do nothing.
See Also
- Installing on Raspberry Pi 3 — TAIL OS on real hardware