How to Run macOS in a Docker Container on Linux: A Practical Dev & Test Guide

22 views 0 likes 0 comments 17 minutesOriginalTutorial

Learn how to set up a fully interactive macOS virtual machine on a Linux server using Docker and KVM. This step-by-step tutorial covers environment setup, X11 graphical forwarding, SSH access, disk image persistence, and host-to-container file sharing.

#Docker #macOS #Virtual Machine #KVM #Development Environment #Cross-Platform #Tutorial
How to Run macOS in a Docker Container on Linux: A Practical Dev & Test Guide

How to Run macOS in a Docker Container on Linux: A Practical Dev & Test Guide

As a backend developer, my daily tasks usually involve writing Java microservices and managing CI/CD pipelines. But last month, my team needed to package a macOS-exclusive client and perform iOS security testing—and I only had a Linux server at hand. Was I supposed to buy a Mac just for this?

Then I found Docker-OSX on GitHub (52.9k stars, actively maintained). The concept is straightforward: it wraps a macOS virtual machine inside a Docker container using QEMU + KVM, supporting X11 graphical forwarding and SSH. In short, you don't need to buy a Mac. As long as you have a Linux machine with hardware virtualization support, you can get a fully interactive macOS environment.

This guide will walk you through setting it up from scratch. By the end, you'll have:

  • A macOS container with a graphical interface
  • The ability to SSH into the container for development and debugging
  • A persistent, reusable macOS workflow

Let's dive in.


1. Prerequisites: What You Need Before Getting Started

This isn't just a "pull an image and run" setup. It relies on KVM hardware virtualization under the hood. Make sure you meet these requirements:

  1. CPU Virtualization Support: Enable Intel VT-x or AMD-V in your BIOS. Most motherboards leave this disabled by default, so you'll need to turn it on.
  2. x86_64 Linux Machine: ARM architectures won't work, this project runs the Intel version of macOS.
  3. At least 20 GB Disk Space: If you plan to install Xcode, prepare 50 GB+.
  4. At least 4 GB RAM: macOS is memory-hungry. Ensure your host has enough headroom to run the container smoothly.

Once verified, install the QEMU and libvirt dependencies on your host. Commands vary by distro; here are the most common ones:

bash 复制代码
## Ubuntu / Debian
sudo apt install qemu qemu-kvm libvirt-clients libvirt-daemon-system bridge-utils virt-manager libguestfs-tools

## Enable libvirt and load the KVM module
sudo systemctl enable --now libvirtd
sudo systemctl enable --now virtlogd
echo 1 | sudo tee /sys/module/kvm/parameters/ignore_msrs
sudo modprobe kvm

Why do this? The ignore_msrs parameter tells KVM to ignore certain MSR (Model-Specific Register) read/write exceptions, which is mandatory for running a macOS VM. libvirt handles the underlying virtualization resource management.

Verify the setup with kvm-ok. If you see KVM acceleration can be used, you're good to go.


2. Quick Start: Launch macOS with a Single Command

With the environment ready, you can pull the image and start it up. Docker-OSX officially provides images for multiple macOS versions (from High Sierra 10.13 to the latest Tahoe 16). Let's test with Catalina (10.15) first:

bash 复制代码
docker run -it \
    --device /dev/kvm \
    -p 50922:10022 \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -e "DISPLAY=${DISPLAY:-:0.0}" \
    -e SHORTNAME=catalina \
    sickcodes/docker-osx:latest

Here's a breakdown of what each parameter does:

Parameter Purpose
--device /dev/kvm Passes the host's KVM device directly to the container for performance.
-p 50922:10022 Port mapping: container SSH runs on 10022, mapped to host port 50922.
-v /tmp/.X11-unix:/tmp/.X11-unix Mounts the X11 socket so the container's GUI displays on your host.
-e DISPLAY=... Tells the container which display to output graphics to.
-e SHORTNAME=catalina Specifies the macOS version. You can also use big-sur, ventura, sonoma, etc.

Why does X11 work across containers? Linux's X Window System uses the /tmp/.X11-unix socket file for communication. Mounting this socket into the container allows its processes to send window drawing instructions back to the host's X Server, giving you direct GUI access.

On first run, you'll enter the installation wizard:

  1. Open Disk Utility
  2. Erase the largest disk (approx. 200 GB)
  3. Select Reinstall macOS. The system will automatically download and install.
  4. It will reboot several times. Just wait patiently.

Default credentials: Username user, Password alpine.


3. Hands-On: Building a Persistent macOS Dev Environment

Just getting it to run isn't enough. We need an environment that saves state and can be reused. This is where naked mode comes in—mounting your own .img disk image.

Step 1: Run the standard installation first

Follow the Quick Start steps above until macOS finishes installing and you reach the desktop.

Step 2: Extract the disk image from the container

bash 复制代码
## Locate the disk image inside Docker's storage
sudo find /var/lib/docker -name "mac_hdd_ng*.img" -size +10G

## Assuming you found it at /var/lib/docker/.../mac_hdd_ng.img, copy it to your current directory
sudo cp /var/lib/docker/overlay2/.../mac_hdd_ng.img ./mac_hdd_ng_auto.img

Step 3: Run in "naked" mode with your custom image

bash 复制代码
docker run -it \
    --device /dev/kvm \
    -p 50922:10022 \
    -v "${PWD}/mac_hdd_ng_auto.img:/image" \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -e "DISPLAY=${DISPLAY:-:0.0}" \
    -e NOPICKER=true \
    sickcodes/docker-osx:naked

-e NOPICKER=true skips the startup disk selection menu and boots directly into the system. Add this if you don't want to manually select the disk every time.

Step 4: Connect via SSH

Open a new terminal on your host:

bash 复制代码
ssh user@localhost -p 50922
## Password: alpine

Once connected, you can do anything you'd do on a real Mac: install Homebrew, run Xcode, execute shell scripts, etc. I personally prefer SSH for command-line work and keep the GUI open just for visual references.

Step 5: Directory Sharing (Host ↔ macOS)

In development, you often need to transfer files between the host and macOS. The safest and most convenient way is sshfs:

bash 复制代码
## On the Linux host
mkdir ~/mnt/osx
sshfs user@localhost: -p 50922 ~/mnt/osx

After running this, ~/mnt/osx will automatically mount the macOS root filesystem, allowing you to read/write files as if they were local. To automate password input if SSH requires it, install sshpass and run:

bash 复制代码
sshpass -p alpine sshfs user@localhost:/ -p 50922 ~/mnt/osx

4. Common Issues & Troubleshooting Tips

1. LibGTK Errors / GUI Window Won't Pop Up

bash 复制代码
## Check the DISPLAY variable
echo $DISPLAY

## If you get errors, install xhost and allow connections
sudo apt install x11-xserver-utils
xhost +

2. Out of Memory Warnings

By default, the container is allocated 3 GB RAM (-e RAM=3). If you see Cannot allocate memory, your host's buff/cache might be too high. Clear the cache:

bash 复制代码
sudo tee /proc/sys/vm/drop_caches <<< 3

3. Docker Daemon Not Running

bash 复制代码
## Check if docker is running
pgrep dockerd

## If not, start it
sudo systemctl enable --now docker

4. CPU Core Allocation

The default core count might be insufficient. You can allocate more cores using -e EXTRA='-smp 8,sockets=4,cores=2'. Note: CPU cores are shared. You can allocate all available host cores to the container without impacting the physical host's stability.

5. Windows Users?

It's possible, but requires Windows 11 + WSL2, with nestedVirtualization=true enabled in .wslconfig. For X11 output, using WSLg is the easiest approach.


5. Summary

After following this guide, you should have:

  1. ✅ Installed KVM + QEMU dependencies
  2. ✅ Successfully launched a Catalina macOS container
  3. ✅ Persisted the disk image locally for future reuse
  4. ✅ Mastered SSH access and directory sharing

This is just the starting point for a macOS sandbox. Next steps you can explore:

  • Generate unique serial numbers for iMessage/iCloud security research (use the project's built-in GENERATE_UNIQUE=true flag)
  • Configure headless mode for CI/CD pipelines
  • Set up VNC for remote access
  • Adjust screen resolution (-e WIDTH=1920 -e HEIGHT=1080)

With over 50k stars on GitHub, the demand for this is clearly real. Instead of spending $800 on a second-hand Mac mini, spend 15 minutes setting up a Docker container on your server. If you run into issues, the project's Discord or Telegram channels are highly active and ready to help.

Happy coding, and enjoy your new macOS sandbox!

Last Updated:2026-10-04 10:04:29

Comments (0)

Post Comment

Loading...
0/500

No comments yet, be the first to comment!