A working recipe to build and run Ubuntu 26.04 LTS (Resolute Raccoon) on the Orange Pi 5 Pro (Rockchip RK3588S), using Armbian's build framework with the mainline (current) Linux kernel for working GPU acceleration.
As of May 2026 there is no off-the-shelf 26.04 image for this board. Joshua Riek's ubuntu-rockchip was archived on 29 April 2026, Armbian's downloads page for the 5 Pro only ships Debian Trixie, and Orange Pi's official downloads top out at 24.04. So we build it ourselves.
Skip everything below and grab a prebuilt 26.04 image from the latest release page:
*_desktop.img.xz(~770 MB) — KDE Plasma + SDDM + HW video decode +orangepi-setupauto-prompt baked in. The "just works" option.*_minimal.img.xz(~300 MB) — CLI only, headless / server use. Runorangepi-setuppost-boot for Plasma + setup.
Flash with balenaEtcher on any OS, or xz -dc *.img.xz | sudo dd of=/dev/sdX bs=4M status=progress on Linux/macOS — see Step 2 below for full per-OS commands and the SHA-256 verify step. Continue reading only if you want to rebuild it yourself or understand why it's needed.
| File | Purpose |
|---|---|
01-build-noble.sh |
Builds the 24.04 stepping-stone image. Run on the stock OPi vendor 22.04 system. |
02-build-resolute.sh |
Builds the 26.04 image. Run on the booted noble system. --desktop flag bakes Plasma + HW video decode + Orange Pi 5 Pro branding. |
apply-uutils-shim.sh |
Patches Armbian's framework with: (1) deploy uutils→qemu-shim, (2) restore before image creation, (3) rk3588 boot-delay (rootwait rootdelay=10), (4) rewrite hardcoded qemu-user-static package name to qemu-user-binfmt for Ubuntu 26.04 hosts. Idempotent. Called automatically by 02-build-resolute.sh. |
customize-image.sh |
Runs inside the chroot during a --desktop build. Installs kubuntu-desktop, builds librockchip-mpp + woodyst/rockchip-vaapi + libva-utils from source, replaces the Armbian motd header with Orange Pi 5 Pro branding, drops a setup-reminder motd, and installs the kdialog wizard autostart entry. Copied into framework/userpatches/ by 02-build-resolute.sh --desktop. |
03-setup.sh |
TTY post-boot helper. Six prompts: install Plasma / auto-start UI / migrate to NVMe / SPI bootloader / install HW video / fix HDMI overscan. Run as orangepi-setup from either image, or ./03-setup.sh from a clone. Re-runnable. |
03-setup-gui.sh |
KDE/kdialog wrapper around the same flow for the desktop image. Auto-launches once on first Plasma login (Plasma + HW video are baked in, so it's a 3-question wizard: autostart toggle, NVMe migration, HDMI overscan). Run as orangepi-setup-gui from the application launcher or terminal. |
orangepi-setup-gui.desktop |
Plasma autostart entry. Shipped to /etc/xdg/autostart/ on the desktop image; runs orangepi-setup-gui once on first KDE login if ~/.opi5pro-setup-done is missing. |
orangepi-setup-gui-launcher.desktop |
Application launcher entry. Shipped to /usr/share/applications/ on the desktop image so the wizard is re-launchable from the menu without the flag check. |
README.md |
This file. |
Ubuntu 26.04 ships rust-coreutils (uutils) as the default coreutils. The uutils binaries use rustix, which crashes during startup with:
thread 'main' panicked at rustix/.../auxv.rs:269:
called `Result::unwrap()` on an `Err` value: ()
…whenever launched through chroot on certain Rockchip vendor kernels. Tested on both 6.1.43-rockchip-rk3588 (stock OPi vendor) and 6.1.115-vendor-rk35xx (Armbian vendor); both panic. The very first chroot operation in Armbian's build (linking armbian-archive-keyring.gpg into /usr/share/keyrings/) hits this and the build dies.
Two layers of problem stack on top of that:
- Stock OPi 22.04 kernel doesn't have
CONFIG_BINFMT_MISCat all — not built-in, no module on disk:So you can't even register$ grep BINFMT_MISC /boot/config-$(uname -r) # CONFIG_BINFMT_MISC is not setqemu-aarch64for binfmt-misc routing. Armbian's build can't shim around the uutils panic. - Even on Armbian's 6.1.115 vendor kernel (which has
CONFIG_BINFMT_MISC=m), Armbian's build framework explicitly skips qemu setup on native-arch builds (if dpkg-architecture -e "${ARCH}"; then return 0), soqemu-aarch64-staticis never deployed into the chroot, and uutils panics anyway.
The recipe therefore needs two components:
- A 24.04 (noble) stepping-stone image so we can boot a kernel with
CONFIG_BINFMT_MISCavailable. Noble itself uses GNU coreutils, so Step 1 of the build doesn't hit the uutils panic. - A small patch (
apply-uutils-shim.sh) for the resolute build that swaps the/usr/bin/*uutils symlinks for a tiny shell shim routing throughqemu-aarch64-static, then restores the original symlinks after all chroot operations are done. The final 26.04 image ships clean uutils — no qemu emulation at runtime.
So the recipe is:
- Build Armbian Ubuntu 24.04 (noble) on the stock Orange Pi vendor system. (~3-5 h cold; ~3 min with caches)
- Flash 24.04 to microSD, boot from it.
- Build Armbian Ubuntu 26.04 (resolute) from the booted 24.04 system.
02-build-resolute.shapplies the patch automatically and defaults toBRANCH=current(~8-15 min total — Armbian's CI publishes a prebuilt mainline kernel deb). - Flash 26.04 wherever you want it (microSD, USB SSD, eMMC).
- Orange Pi 5 Pro (16 GB RAM strongly recommended; 4/8 GB will work, slower)
- A microSD card or USB SSD ≥ 4 GB (≥ 16 GB recommended)
- ~50 GB free disk on the build host
- Stock Orange Pi vendor Ubuntu 22.04 image as starting point (other hosts work but the recipe assumes this)
SSH to your Orange Pi 5 Pro running the stock OPi vendor Ubuntu 22.04, then:
sudo apt-get update
sudo apt-get install -y git docker.io
sudo usermod -aG docker "$USER" # log out / back in OR run: newgrp docker
git clone https://github.com/mack42/OrangePi5Pro.git
cd OrangePi5Pro
./01-build-noble.shOutput lands at:
~/armbian-build/framework/output/images/Armbian-*_Orangepi5pro_noble_vendor_*.img.xz
Plus a matching .txt build manifest and .sha checksum.
Copy the .img.xz to your workstation and flash to a microSD using the instructions for your OS below. balenaEtcher is the cross-platform safe choice; it accepts .img.xz directly and uses raw DD writes — the only tool I've gotten to produce a bootable card reliably across this whole project.
# Identify the SD card device first — DO NOT skip this step or you can wipe a real disk.
lsblk
# Look for the card (usually /dev/sda, /dev/sdb, or /dev/mmcblk0). Confirm by size.
# Decompress and write in one pipe (safe for .img.xz):
xz -dc Armbian-unofficial_*_resolute_current_*.img.xz | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync
syncReplace sdX with your card's device. Triple-check the device — dd will overwrite without warning.
Easiest: install balenaEtcher (drag in the .img.xz, pick the SD, write).
CLI alternative if you prefer Terminal:
# Identify the SD card device:
diskutil list
# Look for /dev/diskN where N is the SD card. Confirm by size.
# Unmount (do NOT eject):
diskutil unmountDisk /dev/diskN
# Write — note the 'r' prefix on rdiskN for raw / faster write:
xz -dc Armbian-unofficial_*_resolute_current_*.img.xz | sudo dd of=/dev/rdiskN bs=4m status=progress
# Eject when done:
diskutil eject /dev/diskNReplace diskN/rdiskN with your card's identifier.
Use balenaEtcher. Download, install, point at the .img.xz, pick the SD, click Flash. Etcher decompresses on the fly and writes raw — works reliably.
Avoid Rufus and Raspberry Pi Imager on Windows for these images. During development, Rufus's ISO/DD detection silently mangled the GPT (the card boots but the kernel sees only the whole-disk device, no partitions). Raspberry Pi Imager wrote a card that wouldn't enumerate the rootfs at the initramfs stage. Both wasted real time. balenaEtcher worked first try, every time.
(If you absolutely must use the command line, install Win32DiskImager and decompress the .img.xz first with 7-Zip, then point Win32DiskImager at the resulting raw .img.)
The release page ships a matching .sha file. Verify before flashing:
# Linux / macOS:
sha256sum -c Armbian-unofficial_*.img.xz.sha # Linux
shasum -a 256 -c Armbian-unofficial_*.img.xz.sha # macOSWindows PowerShell: Get-FileHash Armbian-...img.xz -Algorithm SHA256. Compare to the value in the .sha file.
Insert the microSD into the OPi and power-cycle. Don't touch eMMC — your stock 22.04 stays untouched as a fallback. The 5 Pro's u-boot prefers microSD over eMMC.
First boot prompts for a root password and then to create a regular user. If the very first boot stalls at (initramfs) saying it can't find the rootfs, power-cycle once — first-boot scripts can lose a race with SD enumeration on the very first attempt; the second boot is reliable.
SSH into the booted 24.04 system, then:
sudo apt-get update
sudo apt-get install -y git docker.io qemu-user qemu-user-binfmt binfmt-support
sudo usermod -aG docker "$USER" && newgrp docker
git clone https://github.com/mack42/OrangePi5Pro.git
cd OrangePi5Pro
# Minimal CLI image (~8-15 min, ~300 MB):
./02-build-resolute.sh
# OR — KDE Plasma desktop image with HW video decode + auto-prompt baked in
# (~30-45 min, ~770 MB, all dependencies handled by customize-image.sh):
./02-build-resolute.sh --desktop02-build-resolute.sh clones Armbian's build framework, applies apply-uutils-shim.sh (idempotent — the deploy/restore patch described above), and invokes compile.sh with BRANCH=current by default. Armbian's CI publishes prebuilt current kernel debs (~6.18.x mainline-rockchip64), so the first run downloads the kernel from ghcr.io instead of compiling — keeping the minimal build under ~15 min. (Override with BRANCH=vendor only if you specifically need the BSP — see the GPU caveat below.)
Output:
~/armbian-build/framework/output/images/Armbian-*_Orangepi5pro_resolute_current_*.img.xz
Verify it's actually 26.04:
xz -dkc <image>.img.xz | sudo dd of=/tmp/work.img bs=4M status=none
LOOP=$(sudo losetup -fP --show /tmp/work.img)
sudo mount -o ro "${LOOP}p1" /mnt
grep VERSION /mnt/etc/os-release
sudo umount /mnt && sudo losetup -d "$LOOP"Same flashing procedure as Step 2 (Linux / macOS / Windows commands above), just point at the resolute .img.xz. balenaEtcher on Windows; xz -dc | sudo dd ... on Linux / macOS Terminal.
Both images land you at a TTY login for armbian-firstrun (set root password, create your user, set timezone/locale).
After firstrun, armbian-firstlogin starts SDDM and the desktop image lands you in Plasma. A boot-time service (orangepi-graphical-default.service) flips default.target to graphical.target automatically once firstlogin is complete, so every reboot lands in Plasma from then on. (You can opt out via the wizard or with sudo systemctl set-default multi-user.target for headless / server use.)
A kdialog setup wizard auto-launches once on first Plasma login (or run it manually from the application launcher / orangepi-setup-gui):
- Auto-start Plasma on every boot — the new default; choose No to disable
- Migrate root filesystem to NVMe — opens a terminal running
armbian-install - Put u-boot in SPI flash (asked only if NVMe migration is yes)
- HDMI overscan workaround (skip if your monitor maps pixels 1:1)
The autostart shim touches ~/.opi5pro-setup-done immediately on first launch so the wizard auto-fires exactly once — closing it without finishing won't trigger it on the next login. Re-run manually any time from the application launcher ("Orange Pi 5 Pro Setup") or by running orangepi-setup-gui in a terminal — neither path checks the flag. Plasma + HW video decode are baked into the image, so those prompts are skipped.
You can also run the TTY version (orangepi-setup) over SSH or from the text console — both front-ends share the same flag.
If you ever land at TTY (e.g., you opted out of auto-start), the motd tip shows you how to bring Plasma back up:
Plasma desktop is not running.
Start it now: sudo systemctl start sddm
Boot into Plasma every time: sudo systemctl set-default graphical.target
After firstrun, log in at the text console. The motd shows an Orange Pi 5 Pro reminder:
+--------------------------------------------------------------------+
| First-time setup not yet completed. |
| |
| Run: orangepi-setup |
| |
| Six prompts: Install/auto-start Plasma, migrate root to NVMe, |
| put u-boot in SPI flash, install hardware video decode, and |
| optionally compensate for HDMI overscan. |
+--------------------------------------------------------------------+
Type orangepi-setup and answer the prompts. The minimal image has the script pre-installed at /usr/local/share/OrangePi5Pro/.
If for any reason the script isn't on the image, you can clone and run it manually:
git clone https://github.com/mack42/OrangePi5Pro.git
cd OrangePi5Pro
./03-setup.sh03-setup.sh (a.k.a. orangepi-setup on the desktop image) walks through six prompts and applies your answers:
- Install KDE Plasma desktop? — skipped if already there. Adds ~2 GB.
- Auto-start the UI on boot? — toggles between
graphical.target(boots into SDDM/Plasma) andmulti-user.target(boots to text console). - Migrate root filesystem to NVMe? — calls Armbian's
armbian-installto copy the running rootfs onto an NVMe SSD if one's plugged in. - Put u-boot in SPI flash? — only asked if (3) is yes. Choose YES for pure-NVMe operation, no SD card needed after. Choose NO to keep u-boot on the SD card and treat NVMe as just the rootfs.
- Install hardware video decode? — builds
librockchip-mpp+woodyst/rockchip-vaapifrom source, drops a VA-API driver into/usr/lib/aarch64-linux-gnu/dri/rockchip_drv_video.soso Firefox / Brave / mpv can hardware-decode H.264 / HEVC / VP9 / AV1 via the RK3588 VPU. Takes 15-25 min on this hardware. Skipped automatically if installed already — desktop image variant has it baked in. - Compensate for HDMI overscan? — only relevant if your TV crops the edges of the text console. The proper fix is on the TV (look for "Just Scan" / "PC mode" / "Pixel Perfect"). The workaround here adds
video=HDMI-A-1:1880x1040@60to the kernel cmdline inarmbianEnv.txt, costing ~80 px of effective resolution. Skip if your monitor maps pixels 1:1.
Each step is independent — answer "no" to skip. The script is re-runnable: change your mind later, run it again.
The OPi 5 Pro's RK3588S boot ROM doesn't read u-boot directly from NVMe; u-boot has to come from SPI flash, eMMC, microSD, or USB. So you have three working setups:
| Setup | u-boot location | Rootfs location | Tradeoffs |
|---|---|---|---|
| Pure NVMe (answer YES to step 4) | SPI flash | NVMe | Cleanest. SD card can be removed. SPI write is one-way without rkdeveloptool maskrom recovery. |
| SD bootloader + NVMe rootfs (answer NO to step 4) | microSD (small) | NVMe | Easy to recover (just edit/replace SD). SD slot stays occupied. |
| eMMC bootloader + NVMe rootfs (advanced — choose in armbian-install) | eMMC | NVMe | No SD slot used. Replaces stock OPi 22.04 on eMMC — irreversible without reflash. |
This is the most important practical decision and it's why the recipe defaults to BRANCH=current. Tracked in detail in issue #1.
| Branch | Kernel | GPU | When to use |
|---|---|---|---|
current (default) |
mainline-rockchip64 ~6.18 | ✅ panthor + Mesa panvk: Mali-G610 MC4 accelerated EGL/GLX, real Vulkan via panvk |
Desktop, browsers, anything that benefits from HW accel |
vendor |
Rockchip BSP 6.1.115 | ❌ software (llvmpipe) only — kernel's built-in mali_kbase claims the GPU and prevents panfrost/panthor from binding |
Only if you need NPU access or vendor MPP video decode |
Limitations on current:
- OpenGL Core profile capped at 3.1 (Mesa 26.0.3 panthor still maturing). OpenGL ES 3.1 works, Vulkan 1.4 works.
- Mainline
rkvdec2for HW video decode is improving but not all codecs work yet. - The 5 Pro is community-tier (CSC) in Armbian — no active board maintainer; some peripherals not validated upstream.
02-build-resolute.shdefaults to a minimal CLI image. Pass--desktopfor an image with KDE Plasma + SDDM + HW video decode baked in, or runorangepi-setup(a.k.a.03-setup.sh) post-boot from a minimal image — both reach the same end state.- Each system's Armbian build cache is independent. The first build on a fresh host pulls a ~2 GB Docker base image and clones a kernel tree (~1-2 GB). Subsequent builds reuse those.
- HW video decode on mainline 6.18 isn't packaged in resolute apt; the desktop image build (
customize-image.sh) compileslibrockchip-mpp+woodyst/rockchip-vaapi+libva-utilsfrom source and lands a working VA-API driver. Verified withvainfo: the rockchip driver loads, all four codec families (H.264 / HEVC / VP9 / AV1) decode-capable. Firefox / Brave / mpv pick this up automatically once VA-API flags are enabled. See issue #1 for the full investigation, including ffmpeg-vaapi limitations. - After flashing the desktop image, log in at the TTY (
armbian-firstrunruns there to set root password / create your user). After firstrun, the next interactive TTY login auto-launchesorangepi-setupexactly once; from there you opt into Plasma autostart, NVMe migration, etc. Re-invoke any time withorangepi-setup.
Means the patch wasn't applied. Either you're on a host without CONFIG_BINFMT_MISC (do Step 1 first; 02-build-resolute.sh will refuse to run on such a kernel) or you ran compile.sh directly without apply-uutils-shim.sh. Re-run ./02-build-resolute.sh, which applies the patch idempotently before invoking compile.sh.
Confirm the kernel:
grep BINFMT_MISC "/boot/config-$(uname -r)"# CONFIG_BINFMT_MISC is not set → boot the noble image first.
Power-cycle once. First-boot resize sometimes loses a race with SD enumeration. If it persists across multiple boots:
- Pull the microSD, mount on another machine, edit
/boot/armbianEnv.txtand appendrootwaitandrootdelay=10to theextraargs=line. - Or re-flash with balenaEtcher (Windows) or
dd(Linux). See Step 2 — Rufus and Pi Imager have both produced unbootable cards from this image during development.
The build died. The last ~100 lines of ~/armbian-build/build.log say why. Common causes:
- Out-of-disk: the kernel build alone needs ~10 GB, image creation another ~10 GB.
- Docker daemon not reachable (re-check
systemctl status docker). - Network blip during apt fetch (just rerun the script — caches mostly survive).
Should only happen if you set BRANCH=vendor (or Armbian doesn't have a prebuilt deb for your BRANCH=current config in their ghcr.io cache). Cortex-A76 at 2.35 GHz × 4 + A55 × 4 is roughly half a low-end x86 desktop. Allow 1.5-3 hours for a kernel compile from source. Re-builds reuse the kernel deb from output/debs/ and finish in ~7-10 minutes regardless.
If you have an x86 host, build there instead — same compile.sh, same flags; binfmt-misc + qemu-aarch64 are auto-routed cross-arch on x86 and the resolute build works in one shot (no stepping stone, no patch). The patch in this repo is only needed when host and target are both aarch64.
You built (or downloaded) the BRANCH=vendor image. The Rockchip BSP kernel claims the Mali-G610 via its in-tree mali_kbase driver, blocking panfrost/panthor from binding. Rebuild with BRANCH=current (now the default in 02-build-resolute.sh), or download the current image from the latest release. See issue #1 for the full diagnosis.
- A maintained distro. It's a build recipe; the binaries inherit Armbian's CSC support tier (none).
- A guarantee that every peripheral works.
- An in-place upgrade tool. Don't
do-release-upgradeyour stock Orange Pi system — it ends badly with vendor BSPs.