How to Set Up container machine: Linux on Mac, WSL-Style
Developers and admins coming from Windows know WSL well, the subsystem that provides a real Linux integrated into the host system. If you want Linux on Mac, the closest equivalent arrived with version 1.0 of Apple Container. Its name: container machine.
Rather than packaging an application in a disposable container, this mode provides a persistent Linux environment in which your macOS home directory is mounted. You can install packages, run services, and test your application across multiple distributions. In this article, I’ll show you what container machine is, how it compares to WSL, and then we’ll see how to create and use it!
This article assumes that container is already installed on your Mac. If that is not the case, start with our Apple Container guide, which covers installation and a complete getting-started walkthrough. Ready for a WSL alternative on Mac? Keep reading.
Table of Contents
What Is container machine?
container machine is a mode of Apple’s open source container tool that provides a persistent Linux environment on an Apple Silicon Mac. Unlike a classic container, which is modeled after an application and meant to be started and destroyed, a container machine is modeled after a complete Linux system: it boots the image’s init system and can host services that keep running continuously. It is the closest analogue to WSL on macOS.
Its main benefit for development lies in its integration with the host: your username and your macOS home directory are mounted inside the Linux environment. Your repositories and configuration files are therefore available on both sides. You edit your code with your usual macOS tools, then compile or run it inside Linux, with no copy step.
The distinction between an application container and a Linux environment is important to understand machine mode:
- A container answers the question: “How do I run this application in an isolated and reproducible way?” It is ephemeral by nature.
- A container machine answers: “How do I get a complete and durable Linux environment on my Mac?” You come back to it, install tools, start services, and keep state there.

container machine, a WSL equivalent on macOS?
The analogy with WSL (Windows Subsystem for Linux) is relevant, and it is probably the best reference point for anyone discovering this mode. It is fair to say that the two share several similarities:
- A real Linux kernel runs in a lightweight virtual machine, not simple emulation.
- The host file system is integrated: under WSL, your Windows drives are accessible. Here, your macOS home directory is mounted in the Linux environment.
- You can run real Linux services (with
systemdon a suitable image) and test your application on multiple distributions. - The “edit on the host, build on Linux” workflow is the same.
That said, the analogy has limits, and it is worth being honest about them:
| Criteria | container machine (macOS) | WSL2 (Windows) |
|---|---|---|
| Vendor | Apple | Microsoft |
| Technology | Micro-VM via Virtualization.framework | Lightweight VM via the Virtual Machine Platform (Hyper-V) |
| Model | One VM (and one kernel) per machine | Utility VM with a shared kernel across distros |
| Host file system integration | macOS home directory mounted | Windows drives mounted under /mnt, access via \\wsl$ or \\wsl.localhost\ |
| Multiple distributions | Yes (one machine per image) | Yes (multiple distros) |
| Linux graphical apps | No (no WSLg equivalent yet) | Yes (WSLg) |
| Host ↔ Linux interoperability | Partial (shared files) | Advanced (mutual binary invocation) |
| Maturity | Very recent (2026), evolving | Mature, integrated into Windows |
| Platform | Apple Silicon + macOS 26 | Windows 10/11 |
Requirements for Linux on Mac
The machine mode that gives you Linux on Mac shares the prerequisites of the container tool, namely:
- An Apple Silicon Mac (M1 or newer).
- macOS 26 (Tahoe), the officially supported version.
- The
containertool installed and its service started (container system start).
Create and use a container machine
Create a machine
Creation starts from a Linux image, just like for a container:
container machine create alpine:latest --name devboxTo list running machines, the command is not the same as for containers.
container machine ls
NAME CREATED IP CPUS MEMORY DISK STATE DEFAULT
devbox 2026-06-29 10:43:16 192.168.64.3 5 8G 75M running *Open a shell and run commands
container machine run lets you get a shell or run a single command. If the machine is stopped, it starts automatically. With no command, you get an interactive shell, under a user that matches your macOS account. The values returned by the commands below are especially interesting.
Let’s see how to run a single command.
Which user is used by our devbox machine?
container machine run -n devbox whoamiThis returns: it-connect, which is the user I am logged in as on my Mac.
Now run this command:
container machine run -n devbox pwdThis returns the current directory you are in from the Mac terminal.
Then, to open an interactive shell, run this command:
container machine run -n devboxThis is where the “WSL equivalent” philosophy really makes sense: you are not root in an anonymous environment, but yourself, with your $HOME and your repositories at hand.
Edit on macOS, compile in Linux
Because your repository lives in your macOS home directory and is mounted in the machine, the workflow becomes smooth: you write code in your macOS editor, run it in the Linux environment, and both sides see exactly the same files, with no copy step.
This back-and-forth makes perfect sense when the real target is a Linux server. A common case: you prepare a script intended to run on a Linux server (for example, a scheduled cron job). The trap is that macOS command-line tools are BSD versions, whose behavior can differ from the GNU coreutils found on a Linux server distribution (Debian, Ubuntu, etc.). Testing the script directly on the Mac can therefore be misleading: the container machine gives you a real Linux environment to validate it under the conditions of its target.
Build a suitable machine image
The first step, and this is an important point to know: not all images are suitable for a machine. A container machine boots the image’s init system (PID 1); therefore it needs an image that includes /sbin/init. The alpine:latest image works, but Alpine relies on busybox, which is neither BSD nor GNU: it would not reproduce the behavior of a Debian/Ubuntu server. This is described on this page.
For a genuine GNU environment, we build an Ubuntu image with init, using the Dockerfile provided by the official documentation. Start by creating a folder for this project.
mkdir ~/ubuntu-machine && cd ~/ubuntu-machineThen create a Dockerfile in this directory with the example provided by Apple:
FROM ubuntu:24.04
ENV container container
RUN apt-get update && \
apt-get install -y \
dbus systemd openssh-server net-tools iproute2 \
iputils-ping curl wget vim-tiny man sudo && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
yes | unminimize
RUN >/etc/machine-id
RUN >/var/lib/dbus/machine-id
RUN systemctl set-default multi-user.target
RUN systemctl mask \
dev-hugepages.mount \
sys-fs-fuse-connections.mount \
systemd-update-utmp.service \
systemd-tmpfiles-setup.service \
console-getty.service
RUN systemctl disable networkd-dispatcher.serviceWe then build the image, then create the machine from it (building requires Rosetta 2, just like any container build command):
container build -t local/ubuntu-machine:latest .
container machine create local/ubuntu-machine:latest --name devubuntuNote: this local/ubuntu-machine:latest image serves as the base for a real Ubuntu machine. We will reuse it later in the article.
From there, you now have an Ubuntu machine running through Apple Container. You can open a shell or run a command, as we saw earlier.
The back-and-forth in practice
Let’s put this into practice with a representative example. We are going to write, on the Mac side, a small maintenance script intended for a Linux server: it calculates yesterday’s date, a classic pattern for naming an archive or a daily report. In our case it is incomplete, but it illustrates the mechanism.
We will first run it on the Mac to see it fail (the date command there is the BSD version), then inside the Ubuntu machine where it will run correctly (GNU version), just like on the target server. That is the point: one file, shared, but two behaviors depending on the environment.
On the Mac, create the script in your home directory (you would normally edit it with VS Code):
mkdir ~/maintenance && cd ~/maintenance
cat > rapport-veille.sh << 'EOF'
#!/usr/bin/env bash
# Destine a un serveur Linux : calcule la date de la veille (syntaxe GNU)
hier=$(date -d "yesterday" +%Y-%m-%d)
echo "Generation du rapport pour le $hier"
EOF
chmod +x rapport-veille.shRun directly on the Mac, it fails: macOS’s date command (BSD) does not know the -d option:
./rapport-veille.sh
date: illegal option -- d
usage: date [-jnRu] [-I[date|hours|minutes|seconds|ns]] [-f input_fmt]
[ -z output_zone ] [-r filename|seconds] [-v[+|-]val[y|m|w|d|H|M|S]]
[[[[mm]dd]HH]MM[[cc]yy][.SS] | new_date] [+output_fmt]
Generation du rapport pour le Inside the Linux machine, you find the script without copying it! That is a characteristic of this execution mode, and most importantly, it runs the way it would on the production server. Several steps to reach that goal.
Open a shell in the Ubuntu machine
container machine run -n devubuntuFrom here on, you are in the Linux environment!
The macOS home directory is mounted: the script is already visible to Ubuntu.
cd ~/maintenance
./rapport-veille.shThe execution works! The image below clearly illustrates the behavior difference depending on the execution context.

You can now: edit the script on the Mac, save it, and run it again in the Ubuntu machine. The advantage: no transfer, the file is shared. You develop with the comfort of your macOS machine, while validating real behavior on Linux.
Note: the date case is just one example. The same caution applies to sed -i (which requires an additional argument in BSD: sed -i '' on macOS versus sed -i on Linux). This is exactly why you validate a Linux script in a Linux environment.
Run persistent services
This is one of the main advantages of a container machine compared to an application container: because it boots the image’s init system, it can host real services managed with systemctl. To illustrate this, let’s install a small classic web stack: the Apache server and the MariaDB database, all inside a machine based on our local/ubuntu-machine:latest image.
Open a shell in the machine, then install the two packages:
sudo apt-get update
sudo apt-get install -y apache2 mariadb-serverNext, start both services and enable them at machine boot, exactly like on a Linux server:
sudo systemctl start apache2 mariadb
sudo systemctl enable apache2 mariadb
sudo systemctl status apache2
sudo systemctl status mariadbMariaDB provides an initialization script to harden the installation (root password, removal of anonymous accounts and the test database). A good security hygiene habit to keep:
sudo mariadb-secure-installationAll that remains is to verify that Apache responds. The machine has its own IP address on the host network: retrieve it with the container machine ls command, then open the default page from the Mac (via the terminal or your browser).
open http://192.168.64.4The home page appears: your server is running inside the machine, reachable from macOS. And above all, all of this state persists: the next time you run container machine run, Apache and MariaDB are still installed and configured, with nothing to reinstall. That is the big difference from an application container, whose state disappears with the process (unless you declare persistent volumes).

Multiple distributions in parallel
Nothing prevents you from creating as many machines as target distributions. Each one shares the same $HOME and the same personal configuration files (dotfiles: .bashrc, .gitconfig...) from your Mac, which is convenient for validating an application across multiple environments:
container machine create alpine:latest --name alpine-dev
container machine create ubuntu:24.04 --name ubuntu-dev
container machine create debian:13 --name debian-devNested virtualization (KVM) in a container machine
The development branch documentation mentions support for nested virtualization: exposing /dev/kvm inside a machine (via a --virtualization option and a Linux kernel compiled with CONFIG_KVM=y), for M3 and newer chips.
However, according to the tests performed, this capability is not yet exposed in the stable 1.0.0 CLI. If you try to call this option, the command rejects it because it is unknown. Keep an eye on future versions!
container machine versus other “Linux on Mac” options
I want to note that the machine mode presented in this article is not arriving on an empty field. Several projects already make it possible to run Linux on a Mac: Lima (and Colima for container runtimes), Canonical’s multipass for Ubuntu VMs, UTM for virtual machines via QEMU, or the OrbStack option (which has an excellent reputation).
What sets container machine apart is its reliance on Apple’s native frameworks, its direct integration with the macOS home directory, and the fact that it shares the same tooling as container (you stay in the same ecosystem for your containers and your Linux environments). On the other hand, these alternatives are certainly more mature in some areas.
Conclusion
With container machine, the Mac gains a real “Linux on demand,” persistent and well integrated, which will remind many developers of WSL. It is still missing WSLg for graphical environments, which you already have with Windows Subsystem for Linux (WSL). Still, this is a recent feature and it is only just getting started.
Read more:
- Our guide Containers on macOS: using container, Apple’s native tool.
- The official machine mode documentation in the
apple/containerrepository. - The reference documentation for WSL for the comparison point on the Windows side.
FAQ
How do you run Linux on a Mac with container machine?
container machine is a mode of Apple’s container tool that provides a persistent Linux environment on an Apple Silicon Mac. You create a machine from an image that includes an init system (for example Alpine, or an Ubuntu image built with systemd), then open a shell with container machine run. Your macOS session home directory is mounted automatically.
Is container machine the Mac equivalent of WSL?
It is the closest thing to it: a real Linux kernel in a lightweight VM, host file system integration, and the ability to run services. It still lacks WSL’s maturity, especially an equivalent to WSLg for graphical apps and equally advanced host/Linux interoperability.
What is the difference between a container and a container machine?
A container is modeled after an application and remains ephemeral. A container machine is modeled after a complete, persistent Linux system: it boots the image’s init system, keeps its state across sessions, and targets a durable environment rather than a disposable service.
What are the prerequisites for using container machine?
An Apple Silicon Mac, macOS 26 (Tahoe), and the container tool installed with its service started. Most importantly, the image used must include an init system (/sbin/init). So it does not necessarily need systemd, even though it can be used. Alpine, for example, works directly (busybox/OpenRC init), but without systemctl. A plain Ubuntu image, however, is not suitable as-is: you need to build a machine image with an init beforehand, which is what Apple’s official Dockerfile does by adding systemd (as shown earlier).


