# How to Run Linux Applications on FreeBSD
FreeBSD is not Linux. But it can run most Linux software, often without recompiling a single line of code. The mechanism behind this is the **Linuxulator**, a kernel-level compatibility layer that translates Linux system calls into their FreeBSD equivalents. It is not emulation. There is no virtual machine. Linux binaries execute directly on FreeBSD hardware at near-native speed.
This guide covers the full process: enabling the compatibility layer, installing a Linux userland, running popular applications like Spotify and Steam, and dealing with the edge cases that inevitably come up.
What Is the Linuxulator?
The Linuxulator is FreeBSD's Linux ABI (Application Binary Interface) compatibility layer. It has been part of FreeBSD since the mid-1990s and has matured considerably over the decades.
Here is what it does at a technical level:
- **Syscall translation.** When a Linux binary makes a system call, the FreeBSD kernel intercepts it and maps it to the equivalent FreeBSD syscall. Most Linux syscalls have direct FreeBSD counterparts.
- **ELF branding.** FreeBSD's kernel inspects the ELF header of a binary to determine whether it is a native FreeBSD executable or a Linux one. Linux-branded binaries are routed through the compatibility layer automatically.
- **Filesystem mapping.** Linux binaries expect to find libraries and configuration files under paths like /lib, /usr/lib, and /etc. The Linuxulator maps these to a separate root under /compat/linux/, keeping Linux files isolated from the FreeBSD system.
- **Signal and thread handling.** Linux-specific threading semantics (NPTL) and signal delivery mechanisms are handled within the kernel module.
The key point: this is not Wine, not QEMU, not a container. Linux binaries run as native processes visible in ps and top. They can interact with FreeBSD files, network sockets, and devices. The performance overhead is negligible -- typically under 2-3% for syscall-heavy workloads, and effectively zero for compute-bound tasks.
For a broader comparison of the two operating systems, see our [FreeBSD vs Linux](/blog/freebsd-vs-linux/) comparison.
Enabling Linux Compatibility
Step 1: Load the Kernel Module
The Linuxulator is implemented as a loadable kernel module. On a 64-bit FreeBSD system, load it immediately with:
bash
sudo kldload linux64
Verify it loaded:
bash
kldstat | grep linux
You should see linux64.ko in the output.
Step 2: Enable It at Boot
To load the module automatically on every boot, add this line to /etc/rc.conf:
bash
sudo sysrc linux_enable="YES"
Step 3: Mount Required Filesystems
Linux applications expect certain pseudo-filesystems to be available. Add the following entries to /etc/fstab:
linprocfs /compat/linux/proc linprocfs rw 0 0
linsysfs /compat/linux/sys linsysfs rw 0 0
tmpfs /compat/linux/dev/shm tmpfs rw,mode=1777 0 0
Create the mount points and mount them:
bash
sudo mkdir -p /compat/linux/proc /compat/linux/sys /compat/linux/dev/shm
sudo mount -a
Step 4: Configure DMA Buffer Access (Optional)
Some graphical Linux applications need access to /dev/shm for shared memory. The tmpfs entry above handles this. If you are running a [FreeBSD desktop](/blog/best-desktop-environment-freebsd/), this step is essential for GUI applications.
Installing a Linux Userland
The Linuxulator translates syscalls, but Linux binaries still need Linux shared libraries to link against. You need a Linux userland -- a minimal Linux root filesystem installed under /compat/linux/.
Option A: CentOS Userland via pkg (Recommended)
FreeBSD's package manager provides pre-built CentOS-based userland packages. This is the fastest and most well-tested approach:
bash
sudo pkg install linux_base-c7
This installs a CentOS 7 base system under /compat/linux/. It includes glibc, common shared libraries, and basic utilities.
For newer software that requires a more recent glibc, you can install the Rocky Linux 9 base instead (available on FreeBSD 14+):
bash
sudo pkg install linux_base-rl9
After installation, verify the setup:
bash
/compat/linux/usr/bin/uname -a
This should report a Linux kernel version, confirming the compatibility layer is working.
Option B: Ubuntu/Debian Userland via debootstrap
If you need Debian or Ubuntu packages (common for desktop applications), you can bootstrap an Ubuntu userland:
bash
sudo pkg install debootstrap
sudo debootstrap --arch=amd64 jammy /compat/linux/ubuntu http://archive.ubuntu.com/ubuntu
After bootstrapping, you may need to set up the correct symlinks or adjust /compat/linux to point to this new root, depending on your needs. This approach requires more manual configuration but gives you access to the full Debian/Ubuntu package ecosystem.
Option C: Hybrid Approach
Many users install the CentOS base for core libraries and then layer additional libraries from other distributions as needed. The CentOS base provides a stable foundation, and you can manually add .deb-extracted libraries into /compat/linux/ for specific applications.
Installing Linux Packages Inside the Compat Layer
Once you have a Linux userland, you can install additional Linux packages within it.
Using yum (CentOS Userland)
Chroot into the Linux environment and use the native package manager:
bash
sudo chroot /compat/linux /bin/bash
yum install -y
exit
For the CentOS 7 userland, you may need to configure repositories first:
bash
sudo chroot /compat/linux /bin/bash
yum install -y epel-release
yum update -y
Using apt (Ubuntu/Debian Userland)
If you bootstrapped an Ubuntu root:
bash
sudo chroot /compat/linux/ubuntu /bin/bash
apt update
apt install -y
exit
Manual Library Installation
Sometimes you only need one or two libraries for a specific application. You can extract them from a .deb or .rpm package and place them manually:
bash
# Download a .deb package
wget http://archive.ubuntu.com/ubuntu/pool/main/libx/libxcb/libxcb1_1.14-3ubuntu3_amd64.deb
# Extract it
ar x libxcb1_1.14-3ubuntu3_amd64.deb
tar xf data.tar.xz
# Copy libraries to the compat layer
sudo cp -a usr/lib/x86_64-linux-gnu/* /compat/linux/usr/lib64/
Run ldconfig inside the compat layer after adding libraries:
bash
sudo chroot /compat/linux /sbin/ldconfig
Running Common Linux Applications
Spotify
Spotify does not offer a native FreeBSD client. The Linux version works via the Linuxulator:
bash
# Install required dependencies in the Linux userland
sudo chroot /compat/linux /bin/bash
yum install -y alsa-lib libXScrnSaver gtk3 nss at-spi2-atk libdrm mesa-libgbm
exit
# Download and extract the Spotify .deb
fetch https://repository-origin.spotify.com/pool/non-free/s/spotify-client/spotify-client_1.2.52.442_amd64.deb
ar x spotify-client_*.deb
tar xf data.tar.xz -C /compat/linux/
# Run it
/compat/linux/usr/bin/spotify
Audio output requires PulseAudio or PipeWire to be configured on the FreeBSD side. More on audio troubleshooting below.
Discord
Similar to Spotify, Discord provides a Linux .deb package:
bash
fetch -o discord.deb "https://discord.com/api/download?platform=linux&format=deb"
ar x discord.deb
sudo tar xf data.tar.xz -C /compat/linux/
/compat/linux/usr/share/discord/Discord
Discord may require additional libraries like libappindicator and libnotify. Install them inside the chroot as needed.
Steam
Steam on FreeBSD requires both the Linux compatibility layer and 32-bit library support:
bash
sudo kldload linux
sudo pkg install linux_base-c7 linux-steam-utils
The linux-steam-utils port handles much of the dependency management. Launch Steam with:
bash
steam
Game compatibility varies. Proton-based games (Valve's Wine fork) add another translation layer on top of the Linuxulator, which can introduce additional issues. Native Linux games generally work better.
Google Chrome
bash
sudo chroot /compat/linux /bin/bash
yum install -y wget
wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm
yum localinstall -y google-chrome-stable_current_x86_64.rpm
exit
/compat/linux/usr/bin/google-chrome-stable --no-sandbox
The --no-sandbox flag is often required because Chrome's sandbox makes syscalls that the Linuxulator does not fully support. This is a known workaround, though it reduces browser security isolation.
Flatpak on FreeBSD
Flatpak provides sandboxed application distribution and has experimental FreeBSD support. It runs Linux applications in isolated environments with their own runtime libraries.
bash
sudo pkg install flatpak
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
Install an application:
bash
flatpak install flathub com.spotify.Client
flatpak run com.spotify.Client
Flatpak on FreeBSD relies on the Linuxulator under the hood. Support is still maturing. Some applications work perfectly, others have issues with sandboxing, D-Bus communication, or portal access. Check the FreeBSD wiki and forums for current application-specific compatibility notes.
The advantage of Flatpak is that each application bundles its own runtime libraries, avoiding dependency conflicts with the base Linux userland.
Wine for Windows Applications
Wine is separate from the Linuxulator -- it translates Windows API calls to POSIX calls. On FreeBSD, Wine runs natively (not through the Linux compat layer):
bash
sudo pkg install wine
For 32-bit Windows applications on a 64-bit system:
bash
sudo pkg install i386-wine
Run a Windows executable:
bash
wine /path/to/application.exe
Wine on FreeBSD is well-maintained and generally on par with the Linux version. For gaming, wine-proton or wine-staging may provide better compatibility:
bash
sudo pkg install wine-proton
Wine and the Linuxulator serve different purposes and can coexist on the same system. Wine handles Windows binaries; the Linuxulator handles Linux binaries.
Docker on FreeBSD
Docker does not run natively on FreeBSD. Docker depends on Linux-specific kernel features (cgroups v2, namespaces, overlayfs) that the Linuxulator does not implement.
Your options:
1. **Use FreeBSD jails.** Jails are FreeBSD's native containerization and predate Docker by over a decade. Tools like bastille, pot, and iocage provide management interfaces. See our [FreeBSD jails vs Docker](/blog/freebsd-jails-vs-docker/) comparison for details.
2. **Run Docker inside a Linux VM.** Use bhyve (FreeBSD's hypervisor) to run a minimal Linux VM, then run Docker inside it. This is the most reliable approach if you need full Docker compatibility.
3. **Podman (experimental).** There has been work on running Podman with FreeBSD support using jails as the container backend, but this remains experimental and limited.
The bottom line: if Docker is a hard requirement for your workflow, you will need a Linux VM. If your goal is containerization, FreeBSD jails are the native and more efficient solution.
Performance Considerations
The Linuxulator operates at the kernel level, translating syscalls in-kernel without context switches to userspace. This makes it significantly faster than traditional emulation.
**Benchmarks in practice:**
- **CPU-bound workloads** (compilation, encoding, scientific computing): Effectively zero overhead. The binary code runs directly on the CPU.
- **I/O-bound workloads** (file access, network operations): Minimal overhead from syscall translation, typically 1-3%.
- **Graphics-intensive workloads** (games, GPU computing): Performance depends on GPU driver support. FreeBSD's DRM drivers have improved substantially. Applications using OpenGL or Vulkan through the Linuxulator may see slightly reduced performance compared to native FreeBSD applications.
Compared to running applications in a VM, the Linuxulator has a clear advantage: no memory overhead, no CPU virtualization penalty, no disk image management. Linux applications share the same kernel, filesystem, and network stack as native FreeBSD processes.
Memory usage is comparable to running the same application on Linux. The Linux userland libraries are loaded into memory as shared objects, same as they would be on a Linux system.
Known Limitations and Workarounds
Not everything works. Here are the most common issues:
Kernel Feature Gaps
Some Linux-specific kernel features are not implemented:
- **inotify**: Partially supported. Some applications that rely on filesystem event monitoring may not work correctly. FreeBSD uses kqueue natively, but the Linuxulator provides an inotify shim that covers common use cases.
- **epoll**: Supported and mapped to kqueue internally. Most applications work fine.
- **seccomp**: Not supported. Applications that use seccomp sandboxing (Chrome, Flatpak) may need workarounds like --no-sandbox.
- **cgroups/namespaces**: Not supported. Container runtimes (Docker, Podman) do not work.
- **io_uring**: Not supported. Applications using this newer Linux I/O interface will fall back to older methods or fail.
32-bit Support
Running 32-bit Linux applications requires loading the linux module in addition to linux64:
bash
sudo kldload linux
sudo kldload linux64
And installing 32-bit libraries:
bash
sudo pkg install linux_base-c7
GPU and Graphics
GPU acceleration through the Linuxulator works but requires proper DRM driver support on FreeBSD. Intel and AMD GPUs are best supported. NVIDIA support depends on the proprietary driver version.
For applications needing GPU access:
bash
# Ensure the Linux user has access to the DRI device
sudo chmod 666 /dev/dri/card0 /dev/dri/renderD128
Networking
Linux applications running under the Linuxulator share FreeBSD's network stack. This generally works transparently. Applications that try to access /proc/net/ or make Linux-specific netlink socket calls may encounter issues.
Troubleshooting
Missing Shared Libraries
The most common error you will see:
/compat/linux/usr/bin/app: error while loading shared libraries: libsomething.so.1: cannot open shared object file
Fix it by finding and installing the missing library:
bash
# Search for the library in available packages
sudo chroot /compat/linux /bin/bash
yum provides */libsomething.so.1
yum install -y
exit
Or use ldd to check all dependencies:
bash
/compat/linux/usr/bin/ldd /compat/linux/path/to/application
Wrong Paths and Prefix Issues
Linux applications hardcode paths like /usr/lib or /etc. The Linuxulator redirects these to /compat/linux/usr/lib and /compat/linux/etc. But some applications use unusual paths that are not caught by the redirection.
Check what paths an application is trying to access:
bash
truss -f /compat/linux/usr/bin/application 2>&1 | grep "open\|stat"
Then create the necessary symlinks or copy files to the expected locations under /compat/linux/.
Audio Issues
Audio is the single most common problem with Linux applications on FreeBSD. FreeBSD uses OSS natively, while most Linux applications expect PulseAudio or ALSA.
**Solution 1: PulseAudio bridge**
Install PulseAudio on FreeBSD:
bash
sudo pkg install pulseaudio
Start the PulseAudio daemon:
bash
pulseaudio --start
Linux applications will connect to PulseAudio via the Unix socket at /var/run/pulse/. Make sure this path is accessible from within the compat layer:
bash
sudo mkdir -p /compat/linux/var/run/pulse
sudo mount -t nullfs /var/run/pulse /compat/linux/var/run/pulse
**Solution 2: PipeWire**
PipeWire is increasingly replacing PulseAudio and offers better compatibility:
bash
sudo pkg install pipewire
PipeWire provides PulseAudio and ALSA compatibility layers, making it the best option for running Linux audio applications.
D-Bus Issues
Many Linux desktop applications require D-Bus. Install and enable it:
bash
sudo pkg install dbus
sudo sysrc dbus_enable="YES"
sudo service dbus start
Ensure the D-Bus socket is accessible from the compat layer:
bash
sudo mkdir -p /compat/linux/var/run/dbus
sudo mount -t nullfs /var/run/dbus /compat/linux/var/run/dbus
Font Issues
Linux applications may complain about missing fonts. Install common font packages:
bash
sudo pkg install noto urwfonts webfonts
And symlink the font directory into the compat layer:
bash
sudo mkdir -p /compat/linux/usr/share/fonts
sudo mount -t nullfs /usr/local/share/fonts /compat/linux/usr/share/fonts
Frequently Asked Questions
Is the Linuxulator the same as running Linux in a VM?
No. The Linuxulator runs Linux binaries directly on the FreeBSD kernel. There is no virtual machine, no hypervisor, no separate kernel. Linux processes are native FreeBSD processes with syscall translation. This means near-zero overhead and direct access to hardware, filesystems, and network interfaces. A VM, by contrast, runs a complete separate Linux kernel and requires dedicated memory and CPU resources.
Can I run any Linux application on FreeBSD?
Most Linux applications work. The compatibility is very good for command-line tools, server software, and many desktop applications. Applications that depend on Linux-specific kernel features not yet implemented in the Linuxulator (such as cgroups, namespaces, or io_uring) will not work. The majority of "standard" Linux software, including many commercial applications, runs without issues.
Does the Linuxulator support Linux kernel modules?
No. The Linuxulator translates userspace syscalls only. Linux kernel modules, device drivers, or anything that runs in kernel space cannot be loaded on FreeBSD. If an application requires a custom Linux kernel module, it will not work through the Linuxulator. You would need a full Linux VM for that use case.
How do I update the Linux userland?
For the CentOS base installed via pkg:
bash
sudo pkg upgrade linux_base-c7
For packages installed inside the chroot:
bash
sudo chroot /compat/linux /bin/bash
yum update -y
exit
Keep both the FreeBSD-provided base and the chroot packages updated for security and compatibility.
Can I run Linux and FreeBSD applications side by side?
Yes. Linux applications running under the Linuxulator are regular processes on the FreeBSD system. They can read and write the same files, listen on the same network ports (if not conflicting), and communicate via pipes, sockets, and shared memory with native FreeBSD applications. You can pipe output from a Linux tool into a FreeBSD tool and vice versa. They coexist transparently.
Is Linux compatibility available on FreeBSD ARM64?
Linux compatibility on ARM64 (aarch64) is under active development but is less mature than the x86_64 implementation. Basic functionality works on FreeBSD 14 and later, but many applications have not been tested. If you are running FreeBSD on ARM hardware, expect to encounter more rough edges than on x86_64.
Should I use the Linuxulator or just install the FreeBSD native version of software?
Always prefer the native FreeBSD version when one exists. Native packages are better integrated, better tested on FreeBSD, and avoid the small overhead of syscall translation. Use the Linuxulator for software that is only available as Linux binaries: proprietary applications, commercial software, or niche tools that have not been ported to FreeBSD.
Conclusion
The Linuxulator is one of FreeBSD's most practical features. It bridges the gap between FreeBSD's technical strengths and Linux's larger application ecosystem without requiring a VM or dual-boot setup. The setup takes about ten minutes, and once configured, most Linux applications just work.
Start with the CentOS base userland via pkg, add libraries as needed for specific applications, and keep truss handy for debugging path and library issues. For desktop use, get PulseAudio or PipeWire working early -- audio is the most common friction point.
FreeBSD is not trying to be Linux. But it does not force you to give up Linux software either. That pragmatism is one of the reasons FreeBSD remains a compelling choice for both servers and desktops.