Open-source project
sickcodes/Docker-OSX avatar
sickcodes/Docker-OSX

How to run macOS in a container with Docker-OSX, and what it hands the guest

Run macOS VM in a Docker! Run near native OSX-KVM in Docker! X11 Forwarding! CI/CD for OS X Security Research! Docker mac Containers.

52,952 stars2,886 forksShellGPL-3.0

At a glance

What is it?
Docker-OSX turns a QEMU macOS virtual machine into a privileged Docker container, which makes macOS security research repeatable from Linux or Windows hosts. It packages someone else's work rather than containing a macOS image of its own, and the compose file grants far more access than a normal container.
Who is it for?
Use Docker-OSX when you need a disposable macOS environment for security research, device work or repeated experiments, and you have a Linux host with `/dev/kvm`. Do not use it as a general purpose sandbox for untrusted code: the compose file runs privileged, adds all capabilities, joins the host network and mounts `/dev`, so a guest escape is a host compromise.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Activity is slowing. The repository last received commits 10 months ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The container is a recipe for someone else's macOS VM, not a macOS image

Nothing here is a macOS disk image. The build fetches installer media with `fetch-macOS.py` and hands the result to the QEMU and KVM recipe that upstream OSX-KVM defines, and the tree carries a `rankmirrors` directory and a submodule pointing at the `osx-serial-generator` project. That division of labour is the honest way to read the repository. Docker-OSX is written mostly in shell, licensed GPL-3.0, and the README credits Dhiru Kholia for OSX-KVM, thenickdude for the KVM-Opencore fork that Leoyzen started, and the OpenCore team for the bootloader. MacOS security research from Linux and Windows hosts, iMessage research and iPhone USB work are the stated use cases, and the author asks readers to contribute upstream as well. The practical consequence: when a new macOS release breaks the boot process, the fix usually lands in OSX-KVM, KVM-Opencore or OpenCorePkg, not here, and you are tracking three upstreams through this one container recipe.

SHORTNAME is the only version knob, and every example pulls the same latest tag

The release choice is an environment variable, and the list of accepted values is the list of macOS versions the recipe knows about: `catalina` for 10.15, `big-sur` for 11, `monterey` for 12, `ventura` for 13, `sonoma` for 14, `sequoia` for 15 and `tahoe` for 16. There is no `VERSION` flag on the run command in the quick start, and no version number in the image reference, because every one of those seven blocks ends with the same `sickcodes/docker-osx:latest`. So the tag tells you nothing about which macOS booted; only `SHORTNAME` does. The README's version headings each link to the Docker Hub tags page rather than to a digest, and the repository publishes no GitHub releases at all, which leaves a commit date as the only fixed point you can verify. If you run this in a pipeline, pull by digest and record it, or your next rebuild silently becomes a different VM.

GENERATE_UNIQUE and MASTER_PLIST_URL decide what identity the guest presents

The newest guest versions are told to generate their own machine identity, and to read the configuration for that from a file hosted outside this repository. Monterey and Ventura set `GENERATE_UNIQUE=true` with `MASTER_PLIST_URL` pointing at `config-custom.plist` in the osx-serial-generator repository; Sonoma, Sequoia and Tahoe set the same flag but point at `config-custom-sonoma.plist`. Catalina and Big Sur set neither variable in the quick start, which is the clearest signal in the README that identity handling differs by guest version. Two consequences follow. The identity values a guest ends up with come from a plist fetched over the network, so a build that cannot reach `raw.githubusercontent.com` has no identity source, and a value change upstream changes the guest on your machine. Committed containers are the other problem: the values are not regenerated per boot, so two containers started from the same base share them, which is the kind of duplication that makes iMessage and device research behave strangely rather than fail loudly.

Sonoma, Sequoia and Tahoe hand the guest a Haswell processor that is not yours

From Sonoma onwards the run command adds two variables that change what the operating system believes about the hardware. `CPU='Haswell-noTSX'` selects the processor model the guest is shown, and `CPUID_FLAGS='kvm=on,vendor=GenuineIntel,+invtsc,vmware-cpuid-freq=on'` sets the feature flags, including the KVM paravirtualisation hint and a `GenuineIntel` vendor string. This is deliberate: a modern macOS refuses to start on hardware it does not recognise, so the guest is told it is an older supported model instead. The cost is that the guest never sees your actual CPU. Anything that reads the processor model, or that expects instruction sets a Haswell class part does not advertise, is being told a fixed story, and the flags list is a closed set the project chose rather than a profile of the host. Researchers comparing hardware behaviour have to keep that in mind, because the guest is not a measurement of the machine underneath it.

The compose file gives the guest the host's /dev, host networking and every capability

This is the part to read before anything else.

yaml
    privileged: true
    network_mode: "host"
    cap_add:
      - ALL
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix
      - /dev:/dev
      - /lib/modules:/lib/modules
      - docker-osx_data:/home

A privileged container with all capabilities added, host networking, and the host's device tree and kernel modules mounted in is not an isolation boundary. The build arguments default to `SIZE=200G` and `VERSION=10.15.5`, and the named volume at `/home` is what survives a container restart, so a guest filesystem persists between runs. The honest framing is that this is a research workstation in a container shape: convenient for iMessage and iPhone experiments, where real device services matter, and wrong for running code you do not trust, where the guest has more reach than the process that started it.

X11 forwarding needs a real socket, and SSH arrives on 50922

Every run command mounts `/tmp/.X11-unix` into the container and passes the host's `DISPLAY`, defaulting to `:0.0` when the variable is unset. That default is the failure case: on a headless CI runner there is no X server, so the socket the guest is pointed at does not exist, and anything that opens a window inside macOS fails rather than falling back to a console session. The port mapping `-p 50922:10022` puts SSH on 50922 on the host, and the Dockerfile comments record the client side as `ssh fullname@localhost -p 50922`. A separate pre-installed image path with fixed credentials, where the username is `user` and the password is `alpine`, is present in the README but commented out, so do not plan around it. Other entry points sit beside the main path: a `vnc-version/` directory for a VNC build, a `helm/` chart for Kubernetes, and four Dockerfiles including the `.naked` and `.auto` variants.

No releases, and the last push was on 2025-11-11

Maintenance is the one place this repository gives you almost nothing to check. It is not archived, the default branch is `master`, and the last push was on 2025-11-11. It publishes no GitHub releases, so there is no version history to diff and no upgrade notes to read, and the documented guest list reaches `tahoe` for macOS 16, which means the documentation can describe a configuration that no commit in this repository is responsible for. Support runs through a Discord server with a `#docker-osx` channel, a Telegram group, LinkedIn and a contact page rather than through tracked issues, which is a poor fit if you want an auditable trail for a build. The licence is GPL-3.0, with additional credits collected in `CREDITS.md`. If you adopt this for macOS research, plan to carry the recipe yourself and to follow the three upstreams for the parts that actually change.

Editorial conclusion

Use Docker-OSX when you need a disposable macOS environment for security research, device work or repeated experiments, and you have a Linux host with `/dev/kvm`. Do not use it as a general purpose sandbox for untrusted code: the compose file runs privileged, adds all capabilities, joins the host network and mounts `/dev`, so a guest escape is a host compromise. Before you commit, pin the image by digest rather than tracking `latest`, confirm the identity configuration for your chosen `SHORTNAME`, and check the last commit date yourself, because the repository has no GitHub releases and its last push was on 2025-11-11.

Frequently asked questions

how to install docker osx

Pull the published image and run it with hardware virtualisation exposed, as in `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`. A `docker-compose.yml` is included, and the image is published at hub.docker.com/r/sickcodes/docker-osx.

what is docker osx

Docker-OSX runs a macOS virtual machine inside a Docker container, built on top of the OSX-KVM project and packaged by Sick.Codes. Its stated purpose is macOS security research, including iMessage and iPhone USB work, from Linux and Windows hosts.

docker osx alternative

The README credits the projects it is built on: OSX-KVM, the KVM-Opencore fork and OpenCorePkg. Running OSX-KVM or KVM-Opencore directly with QEMU is the same macOS virtual machine without the container wrapper, and without the privileged device access the compose file grants.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sickcodes-docker-osx.svg)](https://hysenlabs.com/projects/sickcodes-docker-osx)