{"id":1161,"date":"2026-02-02T14:48:28","date_gmt":"2026-02-02T06:48:28","guid":{"rendered":"https:\/\/vm1.go2see.me\/?p=1161"},"modified":"2026-02-02T17:22:50","modified_gmt":"2026-02-02T09:22:50","slug":"1161","status":"publish","type":"post","link":"https:\/\/vm1.go2see.me\/?p=1161","title":{"rendered":"Ubuntu Server ARM64 on QEMU"},"content":{"rendered":"<h1>Ubuntu Server ARM64 on QEMU<\/h1>\n<blockquote>\n<p><a href=\"https:\/\/github.com\/HathewayWill\/Ubuntu_Server_QEMU_Guide\">https:\/\/github.com\/HathewayWill\/Ubuntu_Server_QEMU_Guide<\/a><\/p>\n<\/blockquote>\n<p>A conversational, start-to-finish build and install guide<\/p>\n<p>Host: clean Ubuntu x86_64 \u2022 Guest: Ubuntu Server 24.04.3 ARM64 \u2022 UEFI + SSH port forwarding<\/p>\n<p>Updated: January 1, 2026<\/p>\n<h1>1. What you are building<\/h1>\n<p>You will build a recent QEMU from source on an x86_64 Ubuntu host, then use it to install and boot an ARM64 Ubuntu Server VM. The VM boots via UEFI firmware, uses virtio devices for disk and networking, and exposes SSH to the host via a simple port forward.<\/p>\n<p>By the end, you will have:<\/p>\n<ul>\n<li>A QEMU binary that supports &#8216;-netdev user&#8217; (user-mode networking via SLiRP).<\/li>\n<li>A VM disk image (qcow2) containing Ubuntu Server.<\/li>\n<li>Two UEFI flash images: one for firmware (read-only) and one for UEFI variables (persistent).<\/li>\n<li>A repeatable QEMU command line for installer boot (VNC) and normal boot (terminal + SSH).<\/li>\n<\/ul>\n<h2>Directory layout we will use<\/h2>\n<p>Everything lives under your home directory. Example paths:<\/p>\n<pre><code>~\/qemu\/                         # QEMU source tree\n~\/qemu\/build\/                   # QEMU build output (created by .\/configure + ninja)\n~\/qemu-ubuntu-host\/             # VM workspace (you create this)\n  efi.img                       # UEFI firmware flash (contains QEMU_EFI.fd)\n  varstore.img                  # UEFI variable store (NVRAM)\n  disk.qcow2                    # VM disk\n  ubuntu-24.04.3-live-server-arm64.iso  # installer ISO<\/code><\/pre>\n<h1>2. Before you start<\/h1>\n<p>You will need:<\/p>\n<ul>\n<li>An x86_64 machine running Ubuntu (fresh install is fine).<\/li>\n<li>At least ~15 GB free disk space (more if you store multiple ISOs\/snapshots).<\/li>\n<li>A working Internet connection (to download packages, QEMU source, and the ISO).<\/li>\n<li>Patience: cross-architecture emulation uses TCG (software CPU emulation) and is slower than running on real ARM hardware.<\/li>\n<\/ul>\n<p>Tip: If you only need a fast ARM64 Ubuntu for development, consider cloud images + cloud-init. This guide focuses on a full installer-based setup because it matches a real system stack more closely.<\/p>\n<h1>3. Prepare a clean Ubuntu host<\/h1>\n<h2>3.1 Update the host<\/h2>\n<p>Open a terminal and run:<\/p>\n<pre><code>sudo apt update\nsudo apt -y upgrade\nsudo reboot<\/code><\/pre>\n<p>After reboot, run:<\/p>\n<pre><code>sudo apt update<\/code><\/pre>\n<h2>3.2 Install packages (build tools + firmware + VNC viewer)<\/h2>\n<p>Install the packages required to build QEMU, enable user-mode networking, and run the installer UI over VNC:<\/p>\n<pre><code>sudo apt install -y build-essential git python3 pkg-config ninja-build meson-1.5 libglib2.0-dev libpixman-1-dev zlib1g-dev libslirp-dev qemu-efi-aarch64 wget ca-certificates tigervnc-viewer<\/code><\/pre>\n<p>What these are for:<\/p>\n<ul>\n<li>build-essential, git, python3: compilers and tooling for building from source.<\/li>\n<li>ninja-build, meson-1.5: QEMU uses Meson\/Ninja as its build system.<\/li>\n<li>libglib2.0-dev, libpixman-1-dev, zlib1g-dev: core dependencies for QEMU system emulation.<\/li>\n<li>libslirp-dev: enables the &#8216;user&#8217; network backend (-netdev user). Without it, QEMU will say: &quot;network backend &#8216;user&#8217; is not compiled into this binary&quot;.<\/li>\n<li>qemu-efi-aarch64: provides ARM64 UEFI firmware (QEMU_EFI.fd).<\/li>\n<li>tigervnc-viewer: lets you interact with the Ubuntu installer (Subiquity) easily.<\/li>\n<\/ul>\n<p>Example output (abridged):<\/p>\n<pre><code>Reading package lists... Done\nBuilding dependency tree... Done\nThe following NEW packages will be installed:\n  meson-1.5 ninja-build libslirp-dev qemu-efi-aarch64 ...\n...\nSetting up qemu-efi-aarch64 ...\nSetting up meson-1.5 ...<\/code><\/pre>\n<p>Confirm Meson is new enough:<\/p>\n<pre><code>meson --version<\/code><\/pre>\n<p>Example output:<\/p>\n<pre><code>1.5.1<\/code><\/pre>\n<h1>4. Build QEMU from source (with user networking enabled)<\/h1>\n<p>We build a recent QEMU because distro packages can be older, and because you already ran into missing network backends in custom builds. This section produces a qemu-system-aarch64 that supports &#8216;-netdev user&#8217; and &#8216;hostfwd=&#8217; for SSH port forwarding.<\/p>\n<h2>4.1 Clone QEMU<\/h2>\n<pre><code>cd ~\ngit clone https:\/\/git.qemu.org\/git\/qemu.git\ncd qemu<\/code><\/pre>\n<p>Example output:<\/p>\n<pre><code>Cloning into &#039;qemu&#039;...\nremote: Enumerating objects: ...\nReceiving objects: 100% (...), done.<\/code><\/pre>\n<h2>4.2 Configure the build<\/h2>\n<p>Important: run QEMU&#8217;s &#8216;.\/configure&#8217;. Do not run &#8216;meson setup&#8217; directly for this project. &#8216;.\/configure&#8217; prepares build configuration files (including config-host.mak) and then drives Meson\/Ninja.<\/p>\n<pre><code>rm -rf build\n.\/configure --target-list=aarch64-softmmu --enable-slirp<\/code><\/pre>\n<p>What the configure flags mean:<\/p>\n<ul>\n<li>&#8211;target-list=aarch64-softmmu: build the ARM64 system emulator (qemu-system-aarch64).<\/li>\n<li>&#8211;enable-slirp: compile in the user-mode networking backend (&#8216;-netdev user&#8217;).<\/li>\n<\/ul>\n<p>Example output (abridged):<\/p>\n<pre><code>Using &#039;.\/build&#039; as the build directory\n...\nTarget list     : aarch64-softmmu\nSLIRP support   : yes\n...<\/code><\/pre>\n<h2>4.3 Build<\/h2>\n<pre><code>ninja -C build<\/code><\/pre>\n<p>Example output:<\/p>\n<pre><code>ninja: Entering directory `build&#039;\n[1\/2487] Compiling C object ...\n...\n[2487\/2487] Linking target aarch64-softmmu\/qemu-system-aarch64<\/code><\/pre>\n<h2>4.4 Verify the &#8216;user&#8217; networking backend is present<\/h2>\n<p>This is the quick check that prevents the earlier &#8216;network backend user is not compiled&#8217; error:<\/p>\n<pre><code>.\/build\/qemu-system-aarch64 -help | grep -n &quot;^-netdev user&quot;<\/code><\/pre>\n<p>Example output:<\/p>\n<pre><code>272:-netdev user,id=str[,ipv4=on|off]...[,...][,hostfwd=rule]...<\/code><\/pre>\n<h2>If the check fails<\/h2>\n<p>If you do not see &#8216;-netdev user&#8217; in the help output, the usual causes are:<\/p>\n<ul>\n<li>libslirp-dev was not installed before configuring.<\/li>\n<li>You configured without &#8216;&#8211;enable-slirp&#8217;.<\/li>\n<\/ul>\n<p>Fix by installing libslirp-dev and re-running configure + build:<\/p>\n<pre><code>sudo apt install -y libslirp-dev\ncd ~\/qemu\nrm -rf build\n.\/configure --target-list=aarch64-softmmu --enable-slirp\nninja -C build<\/code><\/pre>\n<h1>5. Create the VM workspace (disk + UEFI flash)<\/h1>\n<h2>5.1 Create a directory for the VM<\/h2>\n<pre><code>mkdir -p ~\/qemu-ubuntu-host\ncd ~\/qemu-ubuntu-host\npwd<\/code><\/pre>\n<p>Example output:<\/p>\n<pre><code>\/home\/youruser\/qemu-ubuntu-host<\/code><\/pre>\n<h2>5.2 Create a qcow2 disk<\/h2>\n<p>qcow2 grows on demand, so the file starts small and expands as the guest writes data.<\/p>\n<pre><code>~\/qemu\/build\/qemu-img create -f qcow2 disk.qcow2 40G<\/code><\/pre>\n<p>Example output:<\/p>\n<pre><code>Formatting &#039;disk.qcow2&#039;, fmt=qcow2 ... size=42949672960 ...<\/code><\/pre>\n<h2>5.3 Prepare UEFI firmware flash images<\/h2>\n<p>We create two flash images:<\/p>\n<ul>\n<li>efi.img: contains the UEFI firmware code. We mark it read-only when launching QEMU.<\/li>\n<li>varstore.img: the persistent UEFI variable store (NVRAM). This remembers boot entries and other firmware settings.<\/li>\n<\/ul>\n<p>Run these commands exactly:<\/p>\n<pre><code>truncate -s 64m varstore.img\ntruncate -s 64m efi.img\ndd if=\/usr\/share\/qemu-efi-aarch64\/QEMU_EFI.fd of=efi.img conv=notrunc<\/code><\/pre>\n<p>Example output:<\/p>\n<pre><code>0+1 records in\n0+1 records out\n2097152 bytes (2.1 MB, 2.0 MiB) copied, 0.004 s, 485 MB\/s<\/code><\/pre>\n<p>Check the files:<\/p>\n<pre><code>ls -lh efi.img varstore.img disk.qcow2<\/code><\/pre>\n<p>Example output:<\/p>\n<pre><code>-rw-r--r-- 1 youruser youruser  64M Jan  1 12:00 efi.img\n-rw-r--r-- 1 youruser youruser  64M Jan  1 12:00 varstore.img\n-rw-r--r-- 1 youruser youruser 196K Jan  1 12:01 disk.qcow2<\/code><\/pre>\n<p>Do not recreate varstore.img after installation unless you intentionally want to reset firmware state.<\/p>\n<h1>6. Download Ubuntu Server ARM64 24.04.3 install media<\/h1>\n<p>Ubuntu publishes both desktop and server ARM64 ISOs. For this guide we use the server installer ISO:<\/p>\n<pre><code>wget https:\/\/cdimage.ubuntu.com\/releases\/noble\/release\/ubuntu-24.04.3-live-server-arm64.iso<\/code><\/pre>\n<p>Example output (abridged):<\/p>\n<pre><code>--2026-01-01 12:05:10--  https:\/\/cdimage.ubuntu.com\/...\/ubuntu-24.04.3-live-server-arm64.iso\nHTTP request sent, awaiting response... 200 OK\nLength: 3000000000 (2.8G)\nSaving to: &#039;ubuntu-24.04.3-live-server-arm64.iso&#039;\n...\n100%[===================&gt;] 2.80G  25.3MB\/s    in 1m 54s<\/code><\/pre>\n<p>Optional checksum verification:<\/p>\n<pre><code>wget https:\/\/cdimage.ubuntu.com\/releases\/noble\/release\/SHA256SUMS\ngrep ubuntu-24.04.3-live-server-arm64.iso SHA256SUMS\nsha256sum ubuntu-24.04.3-live-server-arm64.iso<\/code><\/pre>\n<h1>7. Boot the installer (VNC)<\/h1>\n<p>Ubuntu Server uses a full-screen installer UI. The easiest way to interact with it under QEMU is to expose a local VNC server and connect with a VNC viewer.<\/p>\n<h2>7.1 Launch QEMU for installation<\/h2>\n<p>Run QEMU from your VM directory (where the images and ISO live):<\/p>\n<pre><code>~\/qemu\/build\/qemu-system-aarch64 \\\n  -machine virt,gic-version=3,virtualization=true \\\n  -accel tcg,thread=multi \\\n  -cpu max,pauth-impdef=on \\\n  -smp 8 \\\n  -m 32768 \\\n  -drive if=pflash,format=raw,file=efi.img,readonly=on \\\n  -drive if=pflash,format=raw,file=varstore.img \\\n  -drive if=virtio,format=qcow2,file=disk.qcow2 \\\n  -device virtio-net-pci,netdev=net0 \\\n  -netdev user,id=net0,hostfwd=tcp::8022-:22 \\\n  -device virtio-scsi-pci,id=scsi0 \\\n  -drive if=none,id=cd,format=raw,file=ubuntu-24.04.3-live-server-arm64.iso \\\n  -device scsi-cd,drive=cd \\\n  -device virtio-gpu-pci \\\n  -device qemu-xhci \\\n  -device usb-kbd \\\n  -device usb-tablet \\\n  -display none \\\n  -vnc 127.0.0.1:1<\/code><\/pre>\n<h2>Adjusting CPU cores and memory (the knobs you\u2019ll change most)<\/h2>\n<p>You control \u201chow big\u201d the VM is with <strong>two flags<\/strong>:<\/p>\n<ul>\n<li><strong>CPU cores:<\/strong> <code>-smp &lt;N&gt;<\/code><\/li>\n<li><strong>RAM:<\/strong> <code>-m &lt;MiB&gt;<\/code><\/li>\n<\/ul>\n<h3>Quick examples<\/h3>\n<p><strong>2 cores, 4 GiB RAM (lightweight testing):<\/strong><\/p>\n<pre><code>-smp 2 -m 4096<\/code><\/pre>\n<p><strong>4 cores, 8 GiB RAM (comfortable for installs + basic dev):<\/strong><\/p>\n<pre><code>-smp 4 -m 8192<\/code><\/pre>\n<p><strong>8 cores, 32 GiB RAM (heavier workloads):<\/strong><\/p>\n<pre><code>-smp 8 -m 32768<\/code><\/pre>\n<h3>Notes that save time<\/h3>\n<ul>\n<li><code>-m<\/code> is in <strong>MiB<\/strong>. So <code>8192<\/code> = ~8 GiB, <code>32768<\/code> = ~32 GiB.<\/li>\n<li>On an x86 host emulating ARM with <strong>TCG<\/strong>, adding more cores can help some workloads but won\u2019t scale like real hardware. If it feels slower with more cores, try fewer.<\/li>\n<li>If you use a <strong>custom DTB<\/strong> (<code>-dtb ...<\/code>) later, keep in mind QEMU still uses <code>-smp<\/code> and <code>-m<\/code> to define the virtual hardware; the DTB won\u2019t override those values.<\/li>\n<\/ul>\n<p>What to expect:<\/p>\n<ul>\n<li>The terminal may print nothing and appear to &#8216;hang&#8217;. That is normal: the UI is on VNC.<\/li>\n<li>VNC is bound to localhost only (127.0.0.1). It is not exposed to the network.<\/li>\n<\/ul>\n<h2>7.2 Connect to the installer over VNC<\/h2>\n<pre><code>vncviewer 127.0.0.1:5901<\/code><\/pre>\n<p>Example output:<\/p>\n<pre><code>TigerVNC Viewer 64-bit v1.13.x\nCConn: connected to host 127.0.0.1 port 5901<\/code><\/pre>\n<h2>7.3 Install Ubuntu Server<\/h2>\n<p>Inside the installer:<\/p>\n<ol>\n<li>Choose language\/keyboard\/timezone as desired.<\/li>\n<li>Partitioning: the default guided install is fine for most cases.<\/li>\n<li>Networking: user-mode networking provides outbound Internet access; keep DHCP defaults.<\/li>\n<li>SSH setup: select &#8216;Install OpenSSH server&#8217; so you can SSH in after first boot.<\/li>\n<li>Finish installation and allow the system to reboot.<\/li>\n<\/ol>\n<p>When the installer finishes and reboots, stop QEMU with Ctrl+C in the terminal running QEMU. Next we boot without the ISO.<\/p>\n<h1>8. Boot the installed system (terminal + SSH)<\/h1>\n<h2>8.1 Launch QEMU (no ISO)<\/h2>\n<pre><code>cd $HOME\/vms\/ubuntu-arm64\n\n~\/qemu\/build\/qemu-system-aarch64 \\\n  -machine virt,gic-version=3,virtualization=true \\\n  -accel tcg,thread=multi \\\n  -cpu max,pauth-impdef=on \\\n  -smp 8 \\\n  -m 32768 \\\n  -drive if=pflash,format=raw,file=efi.img,readonly=on \\\n  -drive if=pflash,format=raw,file=varstore.img \\\n  -drive if=virtio,format=qcow2,file=disk.qcow2 \\\n  -device virtio-net-pci,netdev=net0 \\\n  -netdev user,id=net0,hostfwd=tcp::8022-:22 \\\n  -nographic<\/code><\/pre>\n<p>Example output (boot messages abridged):<\/p>\n<pre><code>[    0.000000] Booting Linux on physical CPU 0x0000000000 ...\n...\nUbuntu 24.04.3 LTS ubuntu ttyAMA0\n\nubuntu login:<\/code><\/pre>\n<h2>8.2 SSH into the guest<\/h2>\n<p>From another host terminal:<\/p>\n<pre><code>ssh -p 8022 &lt;your-username&gt;@localhost<\/code><\/pre>\n<p>Example first connection output:<\/p>\n<pre><code>The authenticity of host &#039;[localhost]:8022 ([127.0.0.1]:8022)&#039; can&#039;t be established.\nED25519 key fingerprint is SHA256:...\nAre you sure you want to continue connecting (yes\/no\/[fingerprint])? yes\nWarning: Permanently added &#039;[localhost]:8022&#039; (ED25519) to the list of known hosts.\n&lt;your-username&gt;@localhost&#039;s password:<\/code><\/pre>\n<h1>9. Networking choices: user vs tap\/bridge vs passt<\/h1>\n<p>This guide uses user-mode networking because it requires no root setup and works anywhere. However, you have options:<\/p>\n<h2>9.1 Option A (recommended): user-mode networking<\/h2>\n<p>Keep these flags:<\/p>\n<pre><code>-device virtio-net-pci,netdev=net0\n-netdev user,id=net0,hostfwd=tcp::8022-:22<\/code><\/pre>\n<p>Pros:<\/p>\n<ul>\n<li>Zero host networking configuration.<\/li>\n<li>Easy SSH from host using hostfwd.<\/li>\n<\/ul>\n<p>Cons:<\/p>\n<ul>\n<li>NAT-like behavior; inbound connections require explicit port forwards.<\/li>\n<li>Some advanced networking features are limited compared to a bridged setup.<\/li>\n<\/ul>\n<h2>9.2 Option B: TAP\/bridge networking (more real networking)<\/h2>\n<p>Use this when you want the guest to be on the same L2 network (or when you want normal inbound access without hostfwd). Requires host setup and often root.<\/p>\n<p>Example host setup (creates tap0 owned by your user):<\/p>\n<pre><code>sudo ip tuntap add dev tap0 mode tap user &quot;$USER&quot;\nsudo ip link set tap0 up<\/code><\/pre>\n<p>Then run QEMU with:<\/p>\n<pre><code>-device virtio-net-pci,netdev=net0 \\\n-netdev tap,id=net0,ifname=tap0,script=no,downscript=no<\/code><\/pre>\n<p>If you want guest Internet via host NAT, you must also enable forwarding and add NAT rules on the host (iptables\/nftables).<\/p>\n<h2>9.3 Option C: passt backend (if present)<\/h2>\n<p>Some QEMU builds support a &#8216;passt&#8217; backend. If your help output shows &#8216;-netdev passt&#8217;, you can use it as another host-friendly approach. Whether it is ideal depends on your environment; user-mode networking is the most universally available and easiest to reason about.<\/p>\n<h1>10. QEMU flags explained line-by-line (what it maps to, and what you can delete)<\/h1>\n<p>This section explains every QEMU flag used in the installer and normal-boot commands. For each flag we cover: what it does, what virtual hardware it represents (if any), and whether you can remove it safely.<\/p>\n<table>\n<thead>\n<tr>\n<th>Flag \/ example<\/th>\n<th>What it does<\/th>\n<th>Maps to virtual hardware?<\/th>\n<th>Can you remove it?<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>-machine virt,gic-version=3,virtualization=true<\/td>\n<td>Selects the ARM &#8216;virt&#8217; machine and sets board properties (interrupt controller version, virtualization exposure).<\/td>\n<td>Yes: board model (virt), GIC interrupt controller, virtualization capability exposure.<\/td>\n<td>Must keep &#8216;-machine virt&#8217;. You can usually drop &#8216;gic-version=3&#8217; and &#8216;virtualization=true&#8217; for a normal server VM.<\/td>\n<\/tr>\n<tr>\n<td>-accel tcg,thread=multi<\/td>\n<td>Uses TCG software CPU emulation. &#8216;thread=multi&#8217; may improve throughput in some cases.<\/td>\n<td>No direct guest hardware; affects how QEMU executes guest code on the host.<\/td>\n<td>Optional. Safe to omit (QEMU will typically fall back to TCG anyway in cross-arch).<\/td>\n<\/tr>\n<tr>\n<td>-cpu max,pauth-impdef=on<\/td>\n<td>Selects a feature-rich CPU model and enables a pointer authentication feature flag.<\/td>\n<td>Yes: guest CPU model and CPU feature set.<\/td>\n<td>Optional. You can omit &#8216;-cpu&#8217; to use defaults, or choose a conservative CPU (e.g., cortex-a72). &#8216;pauth-impdef=on&#8217; is usually safe to drop.<\/td>\n<\/tr>\n<tr>\n<td>-smp 8<\/td>\n<td>Exposes 8 virtual CPUs to the guest.<\/td>\n<td>Yes: vCPU count\/topology.<\/td>\n<td>Optional (default is small). Keep for performance\/testing.<\/td>\n<\/tr>\n<tr>\n<td>-m 32768<\/td>\n<td>Allocates 32 GiB RAM to the guest.<\/td>\n<td>Yes: guest RAM size.<\/td>\n<td>Optional (default is small). Keep for realistic workloads.<\/td>\n<\/tr>\n<tr>\n<td>-drive if=pflash,&#8230; file=efi.img,readonly=on<\/td>\n<td>Attaches firmware flash containing UEFI code and makes it read-only.<\/td>\n<td>Yes: flash device holding UEFI firmware.<\/td>\n<td>Keep if you want UEFI boot. Without it you lose this UEFI firmware path.<\/td>\n<\/tr>\n<tr>\n<td>-drive if=pflash,&#8230; file=varstore.img<\/td>\n<td>Attaches UEFI variable store (NVRAM) for boot entries, settings, etc.<\/td>\n<td>Yes: flash region for UEFI variables.<\/td>\n<td>Strongly recommended to keep. Removing it causes non-persistent firmware state (boot entry problems).<\/td>\n<\/tr>\n<tr>\n<td>-drive if=virtio,format=qcow2,file=disk.qcow2<\/td>\n<td>Attaches the main VM disk using virtio (fast paravirtual disk).<\/td>\n<td>Yes: virtio-blk disk device (often \/dev\/vda).<\/td>\n<td>Keep for installed OS. Required unless you boot from something else.<\/td>\n<\/tr>\n<tr>\n<td>-device virtio-net-pci,netdev=net0<\/td>\n<td>Adds a virtio network card connected to backend &#8216;net0&#8217;.<\/td>\n<td>Yes: virtio network interface.<\/td>\n<td>Optional only if you do not need networking. Must match a &#8216;-netdev &#8230; id=net0&#8217;.<\/td>\n<\/tr>\n<tr>\n<td>-netdev user,id=net0,hostfwd=tcp::8022-:22<\/td>\n<td>Creates a user-mode (SLiRP) NAT network backend and forwards host TCP 8022 to guest TCP 22 (SSH).<\/td>\n<td>Host-side network backend (not a guest device).<\/td>\n<td>Optional if you switch to tap\/bridge\/passt. &#8216;hostfwd&#8217; is optional but required for easy host-&gt;guest SSH.<\/td>\n<\/tr>\n<tr>\n<td>-device virtio-scsi-pci,id=scsi0<\/td>\n<td>Adds a virtio SCSI controller so we can attach a SCSI CD-ROM.<\/td>\n<td>Yes: virtio SCSI HBA.<\/td>\n<td>Installer-only in this guide. If you attach the ISO another way, you can drop it.<\/td>\n<\/tr>\n<tr>\n<td>-drive if=none,id=cd,format=raw,file=&#8230;iso<\/td>\n<td>Defines the ISO as a backend named &#8216;cd&#8217;. &#8216;format=raw&#8217; avoids QEMU&#8217;s probing warning.<\/td>\n<td>Host-side block backend definition.<\/td>\n<td>Installer-only. Remove after installation.<\/td>\n<\/tr>\n<tr>\n<td>-device scsi-cd,drive=cd<\/td>\n<td>Attaches the ISO backend as a SCSI CD-ROM device.<\/td>\n<td>Yes: CD-ROM device.<\/td>\n<td>Installer-only. Remove after installation.<\/td>\n<\/tr>\n<tr>\n<td>-device virtio-gpu-pci<\/td>\n<td>Provides a framebuffer device for graphical output (useful for VNC installer UI).<\/td>\n<td>Yes: virtio GPU device.<\/td>\n<td>Installer convenience. Optional for headless\/serial installs.<\/td>\n<\/tr>\n<tr>\n<td>-device qemu-xhci \/ -device usb-kbd \/ -device usb-tablet<\/td>\n<td>Adds USB controller, keyboard, and absolute pointing device for reliable VNC input.<\/td>\n<td>Yes: USB controller and USB HID devices.<\/td>\n<td>Installer convenience. Usually safe to remove once you use SSH or -nographic.<\/td>\n<\/tr>\n<tr>\n<td>-display none<\/td>\n<td>Prevents QEMU from opening a local GUI window (SDL\/GTK).<\/td>\n<td>Host UI behavior.<\/td>\n<td>Optional. Keep if you only want VNC, drop if you want a local window.<\/td>\n<\/tr>\n<tr>\n<td>-vnc 127.0.0.1:1<\/td>\n<td>Starts a VNC server on localhost display :1 (port 5901).<\/td>\n<td>Host UI behavior.<\/td>\n<td>Installer convenience. Remove if using -nographic or local GUI.<\/td>\n<\/tr>\n<tr>\n<td>-nographic<\/td>\n<td>Disables graphics and routes serial console to your terminal.<\/td>\n<td>Host console wiring (serial over stdio).<\/td>\n<td>Optional. Great for server usage. If you want VNC\/GUI console, omit it.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>10.1 Minimal recommended post-install command (safe defaults)<\/h2>\n<p>Once Ubuntu is installed and you mostly live in SSH, you can simplify to the essentials:<\/p>\n<pre><code>~\/qemu\/build\/qemu-system-aarch64 \\\n  -machine virt \\\n  -accel tcg \\\n  -smp 4 -m 16384 \\\n  -drive if=pflash,format=raw,file=efi.img,readonly=on \\\n  -drive if=pflash,format=raw,file=varstore.img \\\n  -drive if=virtio,format=qcow2,file=disk.qcow2 \\\n  -device virtio-net-pci,netdev=net0 \\\n  -netdev user,id=net0,hostfwd=tcp::8022-:22 \\\n  -nographic<\/code><\/pre>\n<p>This removes installer-only devices (CD-ROM, VNC GPU\/input) and keeps a stable UEFI + disk + network + SSH workflow.<\/p>\n<h1>11. Troubleshooting quick hits<\/h1>\n<h2>Error: network backend &#8216;user&#8217; is not compiled into this binary<\/h2>\n<p>Your QEMU build is missing SLiRP\/user networking. Install libslirp-dev, reconfigure with &#8211;enable-slirp, rebuild.<\/p>\n<pre><code>sudo apt install -y libslirp-dev\ncd ~\/qemu\nrm -rf build\n.\/configure --target-list=aarch64-softmmu --enable-slirp\nninja -C build<\/code><\/pre>\n<h2>Error: Meson version too old (project requires &gt;= 1.5.0)<\/h2>\n<p>Install meson-1.5 (or newer) and make sure &#8216;meson &#8211;version&#8217; shows 1.5+.<\/p>\n<pre><code>sudo apt install -y meson-1.5\nmeson --version<\/code><\/pre>\n<h2>Boot returns to installer<\/h2>\n<p>You are still booting with the ISO attached. Boot without the CD drive lines.<\/p>\n<pre><code>(Remove &#039;-drive ...iso&#039; and &#039;-device scsi-cd,...&#039; from the normal boot command)<\/code><\/pre>\n<h2>SSH does not respond on port 8022<\/h2>\n<p>Make sure OpenSSH server is installed and running inside the guest. If not, install and enable it.<\/p>\n<pre><code>sudo systemctl status ssh\nsudo apt update\nsudo apt install -y openssh-server\nsudo systemctl enable --now ssh<\/code><\/pre>\n<h1>12. Confirm system architecture (host vs guest)<\/h1>\n<p>This is a quick sanity check that answers two questions:<\/p>\n<ul>\n<li>Is my <strong>host<\/strong> really x86_64 (amd64)?<\/li>\n<li>Is my <strong>guest<\/strong> really ARM64 (aarch64\/arm64)?<\/li>\n<\/ul>\n<p>Run these on the <strong>host<\/strong> (your Ubuntu machine):<\/p>\n<pre><code>uname -m\ndpkg --print-architecture<\/code><\/pre>\n<p>Typical expected output on the host:<\/p>\n<ul>\n<li><code>uname -m<\/code> -&gt; <code>x86_64<\/code><\/li>\n<li><code>dpkg --print-architecture<\/code> -&gt; <code>amd64<\/code><\/li>\n<\/ul>\n<p>Now run the same commands <strong>inside the guest<\/strong> (in the VM console or over SSH):<\/p>\n<pre><code>uname -m\ndpkg --print-architecture<\/code><\/pre>\n<p>Typical expected output in the guest:<\/p>\n<ul>\n<li><code>uname -m<\/code> -&gt; <code>aarch64<\/code><\/li>\n<li><code>dpkg --print-architecture<\/code> -&gt; <code>arm64<\/code><\/li>\n<\/ul>\n<h1>References<\/h1>\n<p>Ubuntu ARM64 ISO directory (24.04.3): <a href=\"https:\/\/cdimage.ubuntu.com\/releases\/24.04.3\/release\/\">https:\/\/cdimage.ubuntu.com\/releases\/24.04.3\/release\/<\/a><\/p>\n<p>Ubuntu Server ARM64 ISO used here: <a href=\"https:\/\/cdimage.ubuntu.com\/releases\/noble\/release\/ubuntu-24.04.3-live-server-arm64.iso\">https:\/\/cdimage.ubuntu.com\/releases\/noble\/release\/ubuntu-24.04.3-live-server-arm64.iso<\/a><\/p>\n<p>QEMU user networking documentation (for hostfwd and behavior): <a href=\"https:\/\/www.qemu.org\/docs\/master\/system\/invocation.html#hxtool-4\">https:\/\/www.qemu.org\/docs\/master\/system\/invocation.html#hxtool-4<\/a> and <a href=\"https:\/\/www.qemu.org\/docs\/master\/system\/net.html\">https:\/\/www.qemu.org\/docs\/master\/system\/net.html<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ubuntu Server ARM64 on QEMU https:\/\/github.com\/Hatheway&#8230; &raquo; <a class=\"read-more-link\" href=\"https:\/\/vm1.go2see.me\/?p=1161\">\u95b1\u8b80\u5168\u6587<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1161","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=\/wp\/v2\/posts\/1161","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1161"}],"version-history":[{"count":7,"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=\/wp\/v2\/posts\/1161\/revisions"}],"predecessor-version":[{"id":1163,"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=\/wp\/v2\/posts\/1161\/revisions\/1163"}],"wp:attachment":[{"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1161"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1161"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vm1.go2see.me\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1161"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}