Skip to content

Instantly share code, notes, and snippets.

@fergalmoran
Created January 29, 2026 18:22
Show Gist options
  • Select an option

  • Save fergalmoran/d45f250b8c0b359854f41c5d7af3daa7 to your computer and use it in GitHub Desktop.

Select an option

Save fergalmoran/d45f250b8c0b359854f41c5d7af3daa7 to your computer and use it in GitHub Desktop.
Helper script for running OS-X in docker
#!/bin/bash
# Start macOS VM using dockur/macos
# Data disk location: /opt/vms/<container-name>/
# GitHub: https://github.com/dockur/macos
set -e
# Default values
CONTAINER_NAME="macos"
VNC_PORT=5900
SSH_PORT=2022
WEB_VNC_PORT=8007
VERSION="15"
AUTO_PORTS=false
# Check if a port is in use
is_port_in_use() {
local port=$1
if command -v ss &> /dev/null; then
ss -tuln | grep -q ":${port} "
elif command -v netstat &> /dev/null; then
netstat -tuln | grep -q ":${port} "
else
# Fallback: try to bind to the port
(echo >/dev/tcp/localhost/$port) 2>/dev/null && return 0 || return 1
fi
}
# Find next available port starting from given port
find_available_port() {
local port=$1
while is_port_in_use "$port"; do
((port++))
done
echo "$port"
}
# Version name mapping
get_version_name() {
case $1 in
15) echo "Sequoia" ;;
14) echo "Sonoma" ;;
13) echo "Ventura" ;;
12) echo "Monterey" ;;
11) echo "Big Sur" ;;
*) echo "Unknown" ;;
esac
}
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--container-name)
CONTAINER_NAME="$2"
shift 2
;;
--container-name=*)
CONTAINER_NAME="${1#*=}"
shift
;;
--version)
VERSION="$2"
shift 2
;;
--version=*)
VERSION="${1#*=}"
shift
;;
--ssh-port)
SSH_PORT="$2"
shift 2
;;
--ssh-port=*)
SSH_PORT="${1#*=}"
shift
;;
--vnc-port)
VNC_PORT="$2"
shift 2
;;
--vnc-port=*)
VNC_PORT="${1#*=}"
shift
;;
--web-vnc-port)
WEB_VNC_PORT="$2"
shift 2
;;
--web-vnc-port=*)
WEB_VNC_PORT="${1#*=}"
shift
;;
--auto-ports)
AUTO_PORTS=true
shift
;;
-h|--help)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --container-name Name of the container (default: macos)"
echo " Data will be stored at /opt/vms/<container-name>/"
echo " --version macOS version to install (default: 15)"
echo " 15 = macOS 15 Sequoia"
echo " 14 = macOS 14 Sonoma"
echo " 13 = macOS 13 Ventura"
echo " 12 = macOS 12 Monterey"
echo " 11 = macOS 11 Big Sur"
echo " --vnc-port VNC port (default: 5900)"
echo " --web-vnc-port Web VNC port (default: 8007)"
echo " --ssh-port SSH port (default: 2022)"
echo " --auto-ports Auto-select available ports if defaults are in use"
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
done
# Validate version
if [[ ! "$VERSION" =~ ^(11|12|13|14|15)$ ]]; then
echo "Error: Invalid version '$VERSION'. Must be 11, 12, 13, 14, or 15."
exit 1
fi
# Auto-select ports if requested
if [ "$AUTO_PORTS" = true ]; then
VNC_PORT=$(find_available_port "$VNC_PORT")
SSH_PORT=$(find_available_port "$SSH_PORT")
WEB_VNC_PORT=$(find_available_port "$WEB_VNC_PORT")
fi
# Derive DATA_DIR from container name
DATA_DIR="/opt/vms/${CONTAINER_NAME}"
VERSION_NAME=$(get_version_name "$VERSION")
# Create data directory if it doesn't exist
if [ ! -d "$DATA_DIR" ]; then
echo "Creating data directory: $DATA_DIR"
sudo mkdir -p "$DATA_DIR"
sudo chown "$(id -u):$(id -g)" "$DATA_DIR"
fi
# Stop and remove existing container if running
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "Stopping existing container: $CONTAINER_NAME"
docker stop "$CONTAINER_NAME" 2>/dev/null || true
docker rm "$CONTAINER_NAME" 2>/dev/null || true
fi
echo "Starting macOS VM container..."
echo " Container name: $CONTAINER_NAME"
echo " macOS version: $VERSION ($VERSION_NAME)"
echo " Data directory: $DATA_DIR"
echo " VNC port: $VNC_PORT"
echo " Web VNC port: $WEB_VNC_PORT"
echo " SSH port: $SSH_PORT"
docker run -d \
--name "$CONTAINER_NAME" \
--device /dev/kvm \
--cap-add NET_ADMIN \
-p "$VNC_PORT:5900" \
-p "$WEB_VNC_PORT:8006" \
-p "$SSH_PORT:22" \
-v "$DATA_DIR:/storage" \
-e VERSION="$VERSION" \
-e RAM_SIZE="8G" \
-e CPU_CORES="4" \
-e DISK_SIZE="64G" \
--restart unless-stopped \
dockurr/macos
echo ""
echo "macOS VM container started!"
echo ""
echo "Access methods:"
echo " Web VNC: http://localhost:$WEB_VNC_PORT"
echo " VNC client: localhost:$VNC_PORT"
echo " SSH (after setup): ssh user@localhost -p $SSH_PORT"
echo ""
echo "View logs: docker logs -f $CONTAINER_NAME"
echo "Stop VM: docker stop $CONTAINER_NAME"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment