Procedure for installing the Ubuntu base system into FreeBSD’s built-in Linux Binary Compatibility, so Ubuntu and Debian based desktop applications, such as Signal, Spotify and Netflix, can run directly on FreeBSD. Tested with Ubuntu 20.04 on FreeBSD 13.0 for 64-bit amd64 architecture.

What is FreeBSD’s Linux Binary Compatibility?

FreeBSD’s built-in Linux Binary Compatibility makes it possible for FreeBSD users, that are running the 32-bit i386, 64-bit amd64 or 64-bit arm64 architecture, to install and run 32-bit and 64-bit Linux binaries directly from the command line. This is done through a system call table, which means, that Linux applications can run without emulation nor virtualization. FreeBSD’s built-in Linux Binary Compatibility was introduced in the 90’s.

In the following example, Spotify desktop client for Linux is launched from the command line in FreeBSD.

$ /compat/ubuntu/usr/bin/spotify
Screenshot of Spotify desktop client, that is running in GNOME on FreeBSD 13.0.
Screenshot of Spotify desktop client for Linux, that is running in GNOME on FreeBSD 13.0 with Ubuntu 20.04 in FreeBSD’s built-in Linux Binary Compatibility.

Enable FreeBSD’s built-in Linux Binary Compatibility.

FreeBSD has built-in binary compatibility with Linux. This makes it possible to run Ubuntu and Linux binaries. It is enabled by loading the Linux kernel modules.

# kldload linux
# kldload linux64
# kldload fdescfs
# kldload linprocfs
# kldload tmpfs
# kldload linsysfs

To make this permanent, so it also works after reboot, configure the FreeBSD system bootstrap configuration information in loader.conf.

# nano /boot/loader.conf

Prepare command script for Ubuntu base system.

Prepare a command script, that will be used to start and stop the Ubuntu base system.

# touch /usr/local/etc/rc.d/ubuntu
# chmod +x /usr/local/etc/rc.d/ubuntu
# nano /usr/local/etc/rc.d/ubuntu

Insert the following lines of shell script code into the command script.

# PROVIDE: ubuntu
# REQUIRE: archdep mountlate
# KEYWORD: nojail

. /etc/rc.subr

desc="Ubuntu for FreeBSD Linux Binary Compatibility"

  [ `stat -f "%d" "$1"` == `stat -f "%d" "$1/.."` -a `stat -f "%i" "$1"` != `stat -f "%i" "$1/.."` ]

  local _tmpdir
  load_kld -e 'linux(aout|elf)' linux
  case `sysctl -n hw.machine_arch` in
      load_kld -e 'linux64elf' linux64
  if [ -x "/compat/ubuntu/sbin/ldconfigDisabled" ]; then
    _tmpdir=`mktemp -d -t linux-ldconfig`
    /compat/ubuntu/sbin/ldconfig -C ${_tmpdir}/
    if ! cmp -s "${_tmpdir}/" "/compat/ubuntu/etc/"; then
      cat "${_tmpdir}/" > "/compat/ubuntu/etc/"
    rm -rf ${_tmpdir}
  load_kld pty
  if [ `sysctl -ni kern.elf64.fallback_brand` -eq "-1" ]; then
    sysctl kern.elf64.fallback_brand=3 > /dev/null
  if [ `sysctl -ni kern.elf32.fallback_brand` -eq "-1" ]; then
    sysctl kern.elf32.fallback_brand=3 > /dev/null
  sysctl compat.linux.emul_path="/compat/ubuntu"
  unmounted "/compat/ubuntu/dev" && (mount -o nocover -t devfs devfs "/compat/ubuntu/dev" || exit 1)
  unmounted "/compat/ubuntu/dev/fd" && (mount -o nocover,linrdlnk -t fdescfs fdescfs "/compat/ubuntu/dev/fd" || exit 1)
  unmounted "/compat/ubuntu/dev/shm" && (mount -o nocover,mode=1777 -t tmpfs tmpfs "/compat/ubuntu/dev/shm" || exit 1)
  unmounted "/compat/ubuntu/home" && (mount -t nullfs /home "/compat/ubuntu/home" || exit 1)
  unmounted "/compat/ubuntu/proc" && (mount -o nocover -t linprocfs linprocfs "/compat/ubuntu/proc" || exit 1)
  unmounted "/compat/ubuntu/sys" && (mount -o nocover -t linsysfs linsysfs "/compat/ubuntu/sys" || exit 1)
  unmounted "/compat/ubuntu/tmp" && (mount -t nullfs /tmp "/compat/ubuntu/tmp" || exit 1)
  unmounted /dev/fd && (mount -o nocover -t fdescfs fdescfs /dev/fd || exit 1)
  unmounted /proc && (mount -o nocover -t procfs procfs /proc || exit 1)

load_rc_config $name
run_rc_command "$1"

Create ZFS dataset for Linux compatibility directory.

If the benefits of ZFS dataset is of interest, then create a ZFS dataset. This will also make it possible to use snapshots, safely delete files without crossing mountpoints and safely delete the entire volume, if necessary.

# zfs create -o compression=on -o mountpoint=/compat zroot/compat

The snapshot feature of ZFS can be used as a kind of quick backup before changes.

# zfs snapshot -r zroot/compat@2022-04-22

Create directories for the Ubuntu base system.

Prepare directories for Ubuntu.

# mkdir -p /compat/ubuntu/{dev/fd,dev/shm,home,proc,sys,tmp}

Start Ubuntu base system.

Enable Ubuntu chroot jail and make it automatically enabled at boot time.

# sysrc ubuntu_enable=YES

Start Ubuntu base system in its chroot jail.

# service ubuntu start
compat.linux.emul_path: /compat/linux -> /compat/ubuntu

Install Ubuntu base system into the Linux compatibility directory.

Install Debootstrap. This will be used to download and install Ubuntu base systems by specifying the Ubuntu target, such as focal for Focal Fossa, which is version 20.04 LTS of Ubuntu. The different targets and releases of Ubuntu are listed at List of releases at Ubuntu Wiki.

# pkg install debootstrap

Download and install Ubuntu base system into Linux compatibility directory.

# debootstrap --arch=amd64 --no-check-gpg focal /compat/ubuntu
I: Base system installed successfully.

Restart Ubuntu chroot jail.

# service ubuntu restart
compat.linux.emul_path: /compat/ubuntu -> /compat/ubuntu

Fix the dynamic linker (ELF interpreter) with a symbolic link.

# cd /compat/ubuntu/lib64/
# rm ./
# ln -s ../lib/x86_64-linux-gnu/

Configure Ubuntu.

Enter the chroot jail, which will restrict the following processes to the Ubuntu base filesystem. If Ubuntu shows a message about a missing group ID, this can just be ignored. You will see, that the prompt changes.

# chroot /compat/ubuntu /bin/bash

Set timezone.

/# printf "%b\n" "0.0 0 0.0\n0\nUTC" > /etc/adjtime
/# dpkg-reconfigure tzdata

Fix apt package manager.

/# printf "APT::Cache-Start 251658240;" > /etc/apt/apt.conf.d/00aptitude

Add repositories. In this example, the target focal is used. Change as necessary.

/# printf "deb focal main restricted universe multiverse" > /etc/apt/sources.list

Exit the chroot jail.

/# exit

Install and run Ubuntu and Debian based application and binaries.

You have now enabled the Linux Binary Compatibility in FreeBSD and installed the Ubuntu base system into it. You can install Ubuntu and Debian based application and binaries by entering the Ubuntu chroot jail and using Ubuntu’s package manager apt.

If you would like to install the Signal desktop application on FreeBSD, then see my guide in Install and run Signal desktop application on FreeBSD.

Update Ubuntu and Debian based applications.

# chroot /compat/ubuntu /bin/bash
/# apt update
/# apt list --upgradable
/# apt upgrade
/# apt autoremove
/# apt clean

Safely deleting the Ubuntu base system and Linux Binary Compatibility in FreeBSD.

If necessary, the Ubuntu base system in FreeBSDs Linux Binary Compatibility can be safely deleted by first disabling the automatic start of Ubuntu base system, then rebooting FreeBSD and then deleting the Ubuntu base system directory or destroying the ZFS volume. I recommend deleting without crossing mountpoints for extra safety measure. If the Ubuntu base system is running, while attempting to delete it, FreeBSD will crash and FreeBSD disk related services will core dump.

# nano /etc/rc.conf
# reboot
# cd /compat
# rm -rxv ubuntu

More about Linux Binary Compatibility in FreeBSD.

[Linuxulator] How to install Brave (Linux app) on FreeBSD 13.0+ on FreeBSD Forums. Chapter 10. Linux® Binary Compatibility in FreeBSD Documentation. Linux browser installer by mrclksr at GitHub. Install and run Signal desktop application on FreeBSD by me. How to upgrade to new minor and major releases of FreeBSD by me. Package Management by Ubuntu. Running Linux applications on FreeBSD by Tuffi Chuck on TIB AC Portal.

Would you like to treat me a cup of coffee?

If you would like to treat me a cup of coffee, then please consider making a small donation to My Bitcoin (BTC) Address. It would be greatly appreciated.