Created
January 29, 2026 18:22
-
-
Save fergalmoran/d45f250b8c0b359854f41c5d7af3daa7 to your computer and use it in GitHub Desktop.
Helper script for running OS-X in docker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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