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

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 linux_load="YES" linux64_load="YES" fdescfs_load="YES" linprocfs_load="YES" tmpfs_load="YES" linsysfs_load="YES"
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.
#!/bin/sh # # PROVIDE: ubuntu # REQUIRE: archdep mountlate # KEYWORD: nojail # . /etc/rc.subr name="ubuntu" desc="Ubuntu for FreeBSD Linux Binary Compatibility" rcvar="ubuntu_enable" start_cmd="${name}_start" stop_cmd=":" unmounted() { [ `stat -f "%d" "$1"` == `stat -f "%d" "$1/.."` -a `stat -f "%i" "$1"` != `stat -f "%i" "$1/.."` ] } ubuntu_start() { local _tmpdir load_kld -e 'linux(aout|elf)' linux case `sysctl -n hw.machine_arch` in amd64) load_kld -e 'linux64elf' linux64 ;; esac if [ -x "/compat/ubuntu/sbin/ldconfigDisabled" ]; then _tmpdir=`mktemp -d -t linux-ldconfig` /compat/ubuntu/sbin/ldconfig -C ${_tmpdir}/ld.so.cache if ! cmp -s "${_tmpdir}/ld.so.cache" "/compat/ubuntu/etc/ld.so.cache"; then cat "${_tmpdir}/ld.so.cache" > "/compat/ubuntu/etc/ld.so.cache" fi rm -rf ${_tmpdir} fi load_kld pty if [ `sysctl -ni kern.elf64.fallback_brand` -eq "-1" ]; then sysctl kern.elf64.fallback_brand=3 > /dev/null fi if [ `sysctl -ni kern.elf32.fallback_brand` -eq "-1" ]; then sysctl kern.elf32.fallback_brand=3 > /dev/null fi 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) true } 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 ./ld-linux-x86-64.so.2 # ln -s ../lib/x86_64-linux-gnu/ld-2.31.so ld-linux-x86-64.so.2
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 http://archive.ubuntu.com/ubuntu/ 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.