← Back · NextBSD Research · companion to Linux ABI mounts

Debian userland: debootstrap and the apt wrapper

How a NextBSD user gets a Linux userland to run Linux programs. Type apt install google-chrome-stable. If no Linux root exists yet, NextBSD bootstraps one with debootstrap: Devuan 6 by default, with Debian or Ubuntu if you ask. It mounts it, then runs Debian’s own apt inside it with your arguments unchanged. This page covers which distro, how “latest” is chosen, what the wrapper does, and how the graphics stack lines up with NextBSD’s 6.12 DRM drivers.

2026-09-21. Research agents read the FreeBSD sysutils/debootstrap port and its patches, upstream debootstrap and Devuan’s fork, the FreeBSD Handbook’s Linux chapter, the Debian, Devuan and Ubuntu archives (Release files and Packages indexes), Google’s Chrome repository, the Linuxulator’s DRM and sysfs code, and NextBSD’s kernel, kext and userland repos. Nothing has been bootstrapped on NextBSD yet. Sizes and timings are estimates. Planning only.

The short answers.

  1. Default distro: Devuan 6 “Excalibur”, --variant=minbase, into /compat/linux. It has the same Mesa 25.0.7 and libdrm 2.4.124 as Debian 13 trixie, built against kernel 6.12, an exact match for NextBSD’s drm-kmod 6.12-lts. It has no systemd at all, and systemd’s postinst is the one thing that has actually failed under the Linuxulator. Debian trixie minbase is an equally good second choice. Ubuntu LTS is opt-in.
  2. debootstrap runs on NextBSD from the FreeBSD port on amd64 and arm64. Stage 2 runs Debian’s dpkg under the Linuxulator, and debootstrap mounts what it needs itself. It goes straight into the already-mounted root (launchctl bootstrap mounts it at every boot, #244); the wrapper then remounts proc, which debootstrap unmounts (mounts plan §3).
  3. One tool, nextbsd-linux, in NextBSD-userland, with /usr/bin/apt as a thin shim. apt runs inside a chroot, as root. Installed programs run directly through the Linuxulator’s alt root, as the linux-chrome and claude-code ports already do. There is no apt in FreeBSD base, ports or Darwin, so the name is free.
  4. GPU: Intel and AMD work in principle, with Mesa talking to the 6.12 drivers through DRM ioctl passthrough. NVIDIA acceleration for Linux programs is impossible on NextBSD as built, because the NVIDIA kext is compiled without its Linux ioctl bridge, whatever the distro. The Pi 5’s GPU is invisible to Linux libdrm, because linsysfs only describes PCI display devices.

Contents

  1. What the user sees
  2. Distro choice
  3. Resolving “latest”
  4. debootstrap on NextBSD
  5. The wrapper
  6. Graphics: Mesa, NVIDIA, linsysfs
  7. Running installed programs
  8. Risks and open questions
  9. Tickets this implies

1. What the user sees

# apt install google-chrome-stable
No Linux userland at /compat/linux.
Bootstrap Devuan 6 (excalibur) minbase for amd64 from http://deb.devuan.org/merged?
About 50 MB to download and 200 MB on disk. [y/N] y
… debootstrap output …
Linux userland ready: Devuan 6 (excalibur), amd64. Mounts up.
Reading package lists…   ← Debian's own apt from here on

Later runs skip straight to apt. apt update, upgrade, install and remove behave exactly as on Debian, because they are Debian’s apt. apt’s own exit code is passed through unchanged.

2. Distro choice

The table below is as of 2026-09-21, from each archive’s dists/*/Release and Packages.

Devuan 6 ExcaliburDebian 13 trixieUbuntu 24.04 nobleUbuntu 26.04 resolute
Statusstable 6.0 (2025-11-02)stable 13.7; LTS 2028–2030LTS to 2029LTS 26.04.1
Archesamd64, arm64amd64, arm64amd64; arm64 via ports.ubuntu.comsame
Mesa / libdrm / built against25.0.7 / 2.4.124 / 6.12 (same binaries as trixie)25.0.7 / 2.4.124 / 6.1224.0.5 (25.2.8 in updates) / 2.4.120 / 6.826.0.3 / 2.4.131 / 7.0
systemd in a minbase rootnone; sysvinit-core, eudev, elogindnone in minbase (init/systemd are important, not required)in the default set; triggers the port’s postinst workaroundsame
debootstrap script in the FreeBSD portno; vendor Devuan’s ceres script (excalibur and stable are symlinks to it)trixie, stablenobleresolute
Archive keyring on FreeBSDfetch devuan-keyring .debfetch debian-archive-keyring .deb (the debian-keyring port is the developer keyring, not the archive one)security/ubuntu-keyringsame
Chrome .deball deps resolvable (libudev1 from eudev); install unverifiedGoogle targets it; amd64 + arm64yesyes

Why Devuan by default.

Debian trixie minbase is the zero-vendoring alternative. It has the same graphics stack, and minbase is systemd-free at bootstrap; systemd only arrives if a later apt install pulls it in, and Chrome’s dependencies don’t. Ubuntu stays opt-in. 26.04’s Mesa was built for kernel 7.0, which is probably fine on 6.12 but untested, and its systemd-heavy default set triggers the known stage-2 failures.

The user picks with --distro devuan|debian|ubuntu and --suite <codename>|stable, and the default lives in /etc/nextbsd-linux.conf.

3. Resolving “latest”

Pin the codename, don’t follow stable. The wrapper writes the codename into sources.list and a state file, not stable. Writing stable would silently jump a working root to the next major release on release day. Moving to a new release should be an explicit nextbsd-linux upgrade-release, never implicit.

4. debootstrap on NextBSD

5. The wrapper

What ships. The nextbsd-linux command, and /usr/bin/apt as a shim to nextbsd-linux apt. Both go in NextBSD-userland, whose package build lists every staged file automatically, so no packaging change is needed. The Linux mounts themselves are not the wrapper’s job: launchctl bootstrap makes them at every boot (mounts plan §8).

SubcommandBehaviour
apt <args>Root only. There is no sudo on a stock image, so print “run as root” rather than exec it. It ensures a root (bootstrapping on first use), refreshes the host files, then runs chroot $root /usr/bin/apt "$@" with apt’s exit code passed through.
bootstrap [--distro --suite --arch --mirror --variant]Explicit bootstrap without running apt.
run <prog> [args]Any user. It ensures the mounts, then execs the program directly, and the Linuxulator resolves its paths through the alt root.
shellchroot $root /bin/bash as root.
statusDistro and codename, arch, mounts, whether emul_path matches, and GPU notes (for example, “NVIDIA: no Linux acceleration”).
destroyUnmount (refuses if busy), then rm -rfx.
(mounts)None: launchctl bootstrap mounts the Linux ABI filesystems at every boot (#244). The wrapper only remounts proc after debootstrap.

What first use does:

  1. Find the root. It is compat.linux.emul_path. It counts as a valid root only if etc/os-release, var/lib/dpkg/status and the wrapper’s own .nextbsd-linux/state all exist. An existing directory that fails this check is refused with exit 65, and the wrapper never deletes anything on the user’s behalf. The empty pre-created mount skeleton is the one exception: bootstrapping into it is allowed.
  2. Get consent. Show the plan and require y on a tty or -y. Without a tty and without -y, exit 64 with the exact command to run. On live media, refuse unless --force: /cow is RAM-backed and unswapped (#326), and a root plus Chrome is well over 600 MB.
  3. Bootstrap. Take lockf, then run debootstrap --arch=… --variant=minbase --keyring=… <codename> $root <mirror> in place. Afterwards, whatever the result, remount $root/proc (mount -t linprocfs linprocfs $root/proc), which debootstrap unmounted. On failure, leave the root for inspection and point to destroy.
  4. Write state. Record distro, codename, arch, variant, date and debootstrap version in .nextbsd-linux/state. Write 00freebsd and host.conf (order hosts, bind).
  5. Refresh on every run: copy /etc/resolv.conf (IPConfiguration rewrites it, so copy rather than symlink) and /etc/hosts.

Users. A direct-exec program sees the root’s /etc/passwd, because it exists. linux_base-rl9 deliberately omits passwd, group and nsswitch.conf so lookups fall through to the host. The recommendation is to add host users to the root’s passwd and group at bootstrap and on run, which is what Handbook users do by hand.

Exit codes (sysexits):

apt’s own codes pass through.

6. Graphics: Mesa, NVIDIA, linsysfs

7. Running installed programs

8. Risks and open questions

  1. Absolute symlinks escape the root on unfixed kernels. FreeBSD fixed alt-root handling of absolute symlinks on main in commit 459ac3044b (PR 289739, 2026-04-26). It is not in releng/15.0 or stable/15. Trixie’s own loader symlinks are relative, so the base root works. But update-alternatives symlinks are absolute by design: /usr/bin/x-www-browser points to /etc/alternatives/…, which points to /usr/bin/google-chrome-stable. On an unfixed kernel, direct exec through them resolves on the host. We need to check NextBSD’s 15.1-based kernel, and backport the commit if it’s missing.
  2. Keyring provenance. The choice is between shipping the Debian and Devuan archive keyrings in NextBSD-userland (a few tens of KB; licences to check) and fetching the .deb over HTTPS, which is chicken-and-egg without a keyring. Shipping them is recommended.
  3. Vendored Devuan script drift, and the Devuan mirror’s TLS certificate mismatch.
  4. Unmeasured: whether /run needs a tmpfs (one bookworm report), Chrome’s actual /dev/shm use, bootstrap time and size.
  5. Coexistence with linux_base-rl9. Ports hardcode /compat/linux. If both Debian and ports’ linux-* packages must coexist, the Debian root moves to /compat/debian with emul_path set. Pick one model; mixing is messy either way.
  6. pkg triggers are irrelevant to this path. A courtesy trigger for admins who install linux_base-* anyway is possible (path_glob "/compat/linux/*", which fires for files installed by other packages).

9. Tickets (filed 2026-09-21)

TicketEpic
userland#190: the Linux ABI mounts, done in launchctl bootstrap (#244)E15
nextbsd-userland#241: nextbsd-linux bootstrap|apt|run|shell|status|destroy plus the /usr/bin/apt shim; vendored Devuan script; shipped keyringsE13
nextbsd-kernel#247: kernel, check for and backport 459ac3044b (alt-root absolute symlinks)E13
nextbsd-kernel#248: kernel, linsysfs DRM nodes for platform-bus devices (Pi 5 vc4/v3d)E13
nextbsd#493: spike, NVIDIA Linux acceleration (LINUX bridge plus a 595.84-matched userland)E12
nextbsd-userland#242: .app wrappers for Linux apps (nextbsd-linux link)E11
nextbsd-userland#243: optional, restore native WatchPaths/PathState in launchdE2

Evidence: FreeBSD ports sysutils/debootstrap (Makefile, pkg-plist, pkg-message, files/patch-*), emulators/linux_base-rl9, www/linux-chrome, misc/claude-code, x11/linux-nvidia-libs; upstream debootstrap (functions, scripts/{debian-common,sid,gutsy}) and debootstrap_1.0.145devuan1; Handbook linuxemu chapter; deb.debian.org, deb.devuan.org/merged and Ubuntu Release files and Packages indexes; dl.google.com/linux/chrome/deb; FreeBSD sys/compat/linux/{linux_util,linux_ioctl}.c, sys/compat/linsysfs/linsysfs.c, sys/kern/vfs_lookup.c (main 459ac3044b); nextbsd-kernel-extensions build.yml and tools/nvidia-portpatch.sh; nextbsd-pkg scripts/build.sh. Related: E13 (#461), #460, #449, #326, E14 (#468).