├── .github └── FUNDING.yml ├── LICENSE ├── README.md └── prepare-iso.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | --- 3 | github: geerlingguy 4 | patreon: geerlingguy 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jeff Geerling 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # macOS VirtualBox VM Instructions 2 | 3 | Current macOS version: *High Sierra (10.13)*, tested with VirtualBox *5.2.16 r123759* 4 | 5 | To build a VM running macOS, follow the directions below: 6 | 7 | 1. Download the installer from Mac App Store (it should be available in the 'Purchases' section if you've acquired it previously). The installer will be placed in your Applications folder. (Should work for Yosemite, El Capitan, Sierra and High Sierra, Mojave - 10.10-10.14.) 8 | - **Note**: On newer hardware, you might not be able to download older OS releases that Apple doesn't support on the newer hardware (e.g. the 2016 MacBook Pro can only download 10.12 Sierra or later). In this case, you need to use an older Mac to download the older OS. 9 | 2. Make the script executable and run it: `chmod +x prepare-iso.sh && ./prepare-iso.sh`. 10 | 11 | If the script fails to find the installer you can specify its path as the first parameter. By default, the output is saved as .iso on the Desktop. You can change this using the second parameter. 12 | Example: 13 | 14 | ./prepare-iso.sh /Applications/Install\ macOS Sierra\ 2.1\ Beta\ 2.app sierra-2.1-b2 15 | 16 | 3. Open VirtualBox and create a new VM. 17 | 4. Set: 18 | - name: Choose a name 19 | - type: `Mac OS X` 20 | - version: `Mac OS X (64-bit)`. 21 | 5. Follow the rest of the VM creation wizard and either leave the defaults or adjust to your liking. 22 | - For Big Sur, the installer requires the disk to have at least 35.3 GB. 23 | 6. Go into the Settings for the new VM you created and: 24 | 1. Under 'Display', increase the Video Memory to at least 128MB, otherwise macOS might not boot correctly, and display performance will be abysmal. 25 | 2. Under 'Audio', uncheck 'Enable Audio', otherwise the VM may display 'choppy' performance. 26 | 7. In Terminal, run the command `VBoxManage modifyvm VM_NAME --cpuidset 00000001 000306a9 00020800 80000201 178bfbff` (where `VM_NAME` is the exact name of the VM set in step 4) so the VM has the right CPU settings for macOS. 27 | 8. Click 'Start' to boot the new VM. 28 | 9. Select the iso created in step 2 when VirtualBox asks for it. 29 | 10. In the installer, select your preferred language. 30 | 11. Open Disk Utility and format the volume: 31 | 1. Go to `Utilities > Disk Utility`, select the VirtualBox disk, and choose `Erase` to format it as: 32 | - For macOS < 10.13, choose `Mac OS Extended (Journaled)` 33 | - For macOS 10.13 and later, choose `APFS`. 34 | 12. Quit Disk Utility, and then continue with installation as normal. 35 | 36 | 37 | ## Troubleshooting & Improvements 38 | 39 | - I've noticed that sometimes I need to go in and explicitly mark the iso as a Live CD in the VM settings in order to get the VM to boot from the image. 40 | - If you try to start your VM and it does not boot up at all, check to make sure you have enough RAM to run your VM. 41 | - Conversely, VirtualBox sometimes does not eject the virtual installer DVD after installation. If your VM boots into the installer again, remove the ISO in `Settings -> Storage`. 42 | - VirtualBox uses the left command key as the "host key" by default. If you want to use it for shortcuts like `command+c` or `command-v` (copy&paste), you need to remap or unset the "Host Key Combination" in `Preferences -> Input -> Virtual Machine`. 43 | - The default Video Memory of 16MB is far below Apple's official requirement of 128MB. Increasing this value may help if you run into problems and is also the most effective performance tuning. 44 | - Depending on your hardware, you may also want to increase RAM and the share of CPU power the VM is allowed to use. 45 | - When the installation is complete, and you have a fresh new macOS VM, you can shut it down and create a snapshot. This way, you can go back to the initial state in the future. I use this technique to test the [`mac-dev-playbook`](https://github.com/geerlingguy/mac-dev-playbook), which I use to set up and configure my own Mac workstation for web and app development. 46 | - If for High Sierra you can not find the VirtualBox disk created inside the Disk Utility select `View -> Show All Devices` and format the newly visible device ([Source: tinyapps.org](https://tinyapps.org/blog/mac/201710010700_high_sierra_disk_utility.html)). 47 | - If for High Sierra you encounter boot / EFI problems, restart the VM and hit `F12` to get to the VirtualBox boot manager. Select **EFI In-Terminal Shell** and run: 48 | 49 | Shell> fs1: 50 | FS1:\> cd "macOS Install Data" 51 | FS1:\macOS Install Data\> cd "Locked Files" 52 | FS1:\macOS Install Data\Locked Files\> cd "Boot Files" 53 | FS1:\macOS Install Data\Locked Files\Boot Files\> boot.efi 54 | 55 | - If keyboard and mouse do not work inside the VM: 56 | 1. Ensure the VirtualBox Extension Pack is installed. 57 | 2. In the VM settings, under `Ports > USB`, select `USB 3.0 (xHCI) Control`. 58 | - If for Big Sur the installer says `The selected volume is not large enough to install on. A minimum of 35.3 GB is required.`, shutdown the VM, go to File > Virtual Media Manager, and increase the disk size. Now, restart the VM, go to Disk Utility, delete the too-small partition and re-create it to use all of the available space. 59 | ## Larger VM Screen Resolution 60 | 61 | To control the screen size of your macOS VM: 62 | 63 | 1. Shutdown your VM 64 | 2. Run the following VBoxManage command: 65 | 66 | VBoxManage setextradata VM_NAME VBoxInternal2/EfiGopMode N 67 | 68 | Replace `VM_NAME` with the name of your Virtual Machine. Replace `N` with one of 0,1,2,3,4,5. These numbers correspond to the screen resolutions 640x480, 800x600, 1024x768, 1280x1024, 1440x900, 1920x1200 screen resolution, respectively. 69 | 70 | The video mode can only be changed when the VM is powered off and remains persistent until changed. See more details in [this forum discussion](https://forums.virtualbox.org/viewtopic.php?f=22&t=54030). 71 | 72 | ## Notes 73 | 74 | - The code for this example originally came from VirtualBox forums and especially [this article](http://sqar.blogspot.de/2014/10/installing-yosemite-in-virtualbox.html). 75 | - Subsequently updated to support Yosemite - Sierra based on [this thread](https://forums.virtualbox.org/viewtopic.php?f=22&t=77068&p=358865&hilit=elCapitan+iso#p358865), and High Sierra and beyond based on the work of a number of contributors (thanks!). 76 | - To install command line tools after macOS is booted, open a terminal window and enter `xcode-select --install` (or just try using `git`, `gcc`, or other tools that would be installed with CLI tools). 77 | 78 | ## Author 79 | 80 | This project was created in 2015 by [Jeff Geerling](https://www.jeffgeerling.com/). 81 | -------------------------------------------------------------------------------- /prepare-iso.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script will create a bootable ISO image from the installer app for: 4 | # 5 | # - Yosemite (10.10) 6 | # - El Capitan (10.11) 7 | # - Sierra (10.12) 8 | # - High Sierra (10.13) 9 | # - Mojave (10.14) 10 | # - Catalina (10.15) 11 | # - Big Sur (11.0) 12 | # - Monterey (12.2) 13 | 14 | set -e 15 | 16 | # 17 | # createISO 18 | # 19 | # This function creates the ISO image for the user. 20 | # Inputs: $1 = The name of the installer - located in your Applications folder or in your local folder/PATH. 21 | # $2 = The Name of the ISO you want created. 22 | function createISO() 23 | { 24 | if [ $# -eq 2 ] ; then 25 | local installerAppName=${1} 26 | local isoName=${2} 27 | local error=0 28 | 29 | # echo Debug: installerAppName = ${installerAppName} , isoName = ${isoName} 30 | 31 | echo 32 | echo Create ${isoName} blank ISO image with a Single Partition - Apple Partition Map 33 | echo -------------------------------------------------------------------------- 34 | # Just in case - delete any previous sparseimage 35 | [ -e /tmp/${isoName}.sparseimage ] && rm -f /tmp/${isoName}.sparseimage 36 | # increased size to 16G - 8G is too small for Catalina 37 | echo $ hdiutil create -o /tmp/${isoName} -size 16g -layout SPUD -fs HFS+J -type SPARSE 38 | hdiutil create -o /tmp/${isoName} -size 16g -layout SPUD -fs HFS+J -type SPARSE 39 | 40 | echo 41 | echo Mount the installer image 42 | echo ----------------------------------------------------------- 43 | 44 | if [[ "${isoName}" == "BigSur" || "${isoName}" == "Monterey" ]] ; then 45 | echo $ hdiutil attach /tmp/${isoName}.sparseimage -noverify -nobrowse -mountpoint /Volumes/install_app 46 | hdiutil attach /tmp/${isoName}.sparseimage -noverify -nobrowse -mountpoint /Volumes/install_app 47 | elif [ -e "${installerAppName}" ] ; then 48 | echo $ hdiutil attach "${installerAppName}"/Contents/SharedSupport/InstallESD.dmg -noverify -nobrowse -mountpoint /Volumes/install_app 49 | hdiutil attach "${installerAppName}"/Contents/SharedSupport/InstallESD.dmg -noverify -nobrowse -mountpoint /Volumes/install_app 50 | error=$? 51 | elif [ -e /Applications/"${installerAppName}" ] ; then 52 | echo $ hdiutil attach /Applications/"${installerAppName}"/Contents/SharedSupport/InstallESD.dmg -noverify -nobrowse -mountpoint /Volumes/install_app 53 | hdiutil attach /Applications/"${installerAppName}"/Contents/SharedSupport/InstallESD.dmg -noverify -nobrowse -mountpoint /Volumes/install_app 54 | error=$? 55 | installerAppName="/Applications/${installerAppName}" 56 | else 57 | echo Installer Not found! 58 | error=1 59 | fi 60 | 61 | if [ ${error} -ne 0 ] ; then 62 | echo "Failed to mount the InstallESD.dmg from the installer at ${installerAppName}. Exiting. (${error})" 63 | return ${error} 64 | fi 65 | 66 | if [[ "${isoName}" != "BigSur" && "${isoName}" != "Monterey" ]] ; then 67 | echo 68 | echo Mount the sparse bundle for package addition 69 | echo -------------------------------------------------------------------------- 70 | echo $ hdiutil attach /tmp/${isoName}.sparseimage -noverify -nobrowse -mountpoint /Volumes/install_build 71 | hdiutil attach /tmp/${isoName}.sparseimage -noverify -nobrowse -mountpoint /Volumes/install_build 72 | fi 73 | 74 | echo 75 | echo Restore the Base System into the ${isoName} ISO image 76 | echo -------------------------------------------------------------------------- 77 | if [[ "${isoName}" == "BigSur" || "${isoName}" == "Monterey" ]] ; then 78 | echo "N/A skipping..." 79 | elif [ "${isoName}" == "HighSierra" ] || [ "${isoName}" == "Mojave" ] || [ "${isoName}" == "Catalina" ] ; then 80 | echo $ asr restore -source "${installerAppName}"/Contents/SharedSupport/BaseSystem.dmg -target /Volumes/install_build -noprompt -noverify -erase 81 | #following asr command returns an error and prints: 82 | #"Personalization succeeded" 83 | #"asr: Couldn't personalize volume /Volumes/macOS Base System - Operation not permitted" 84 | #I disabled SIP and the error still occurs. 85 | #This was reported in Issue #73 for Mojave 86 | #I added ||true for now to prevent the script from exiting as the steps that follow still seem to work fine for Catalina 87 | asr restore -source "${installerAppName}"/Contents/SharedSupport/BaseSystem.dmg -target /Volumes/install_build -noprompt -noverify -erase ||true 88 | else 89 | echo $ asr restore -source /Volumes/install_app/BaseSystem.dmg -target /Volumes/install_build -noprompt -noverify -erase 90 | asr restore -source /Volumes/install_app/BaseSystem.dmg -target /Volumes/install_build -noprompt -noverify -erase 91 | fi 92 | 93 | echo 94 | echo Remove Package link and replace with actual files 95 | echo -------------------------------------------------------------------------- 96 | if [[ "${isoName}" == "BigSur" || "${isoName}" == "Monterey" ]] ; then 97 | echo "N/A skipping..." 98 | elif [ "${isoName}" == "Mojave" ] || [ "${isoName}" == "Catalina" ] ; then 99 | echo $ ditto -V /Volumes/install_app/Packages /Volumes/macOS\ Base\ System/System/Installation/ 100 | ditto -V /Volumes/install_app/Packages /Volumes/macOS\ Base\ System/System/Installation/ 101 | elif [ "${isoName}" == "HighSierra" ] ; then 102 | echo $ ditto -V /Volumes/install_app/Packages /Volumes/OS\ X\ Base\ System/System/Installation/ 103 | ditto -V /Volumes/install_app/Packages /Volumes/OS\ X\ Base\ System/System/Installation/ 104 | else 105 | echo $ rm /Volumes/OS\ X\ Base\ System/System/Installation/Packages 106 | rm /Volumes/OS\ X\ Base\ System/System/Installation/Packages 107 | echo $ cp -rp /Volumes/install_app/Packages /Volumes/OS\ X\ Base\ System/System/Installation/ 108 | cp -rp /Volumes/install_app/Packages /Volumes/OS\ X\ Base\ System/System/Installation/ 109 | fi 110 | 111 | echo 112 | echo Copy macOS ${isoName} installer dependencies 113 | echo -------------------------------------------------------------------------- 114 | if [[ "${isoName}" == "BigSur" || "${isoName}" == "Monterey" ]] ; then 115 | echo $ sudo /Applications/"${installerAppName}"/Contents/Resources/createinstallmedia --volume /Volumes/install_app --nointeraction 116 | sudo /Applications/"${installerAppName}"/Contents/Resources/createinstallmedia --volume /Volumes/install_app --nointeraction 117 | elif [ "${isoName}" == "Mojave" ] || [ "${isoName}" == "Catalina" ] ; then 118 | echo $ ditto -V "${installerAppName}"/Contents/SharedSupport/BaseSystem.chunklist /Volumes/macOS\ Base\ System/BaseSystem.chunklist 119 | ditto -V "${installerAppName}"/Contents/SharedSupport/BaseSystem.chunklist /Volumes/macOS\ Base\ System/BaseSystem.chunklist 120 | echo $ ditto -V "${installerAppName}"/Contents/SharedSupport/BaseSystem.dmg /Volumes/macOS\ Base\ System/BaseSystem.dmg 121 | ditto -V "${installerAppName}"/Contents/SharedSupport/BaseSystem.dmg /Volumes/macOS\ Base\ System/BaseSystem.dmg 122 | elif [ "${isoName}" == "HighSierra" ] ; then 123 | echo $ ditto -V "${installerAppName}"/Contents/SharedSupport/BaseSystem.chunklist /Volumes/OS\ X\ Base\ System/BaseSystem.chunklist 124 | ditto -V "${installerAppName}"/Contents/SharedSupport/BaseSystem.chunklist /Volumes/OS\ X\ Base\ System/BaseSystem.chunklist 125 | echo $ ditto -V "${installerAppName}"/Contents/SharedSupport/BaseSystem.dmg /Volumes/OS\ X\ Base\ System/BaseSystem.dmg 126 | ditto -V "${installerAppName}"/Contents/SharedSupport/BaseSystem.dmg /Volumes/OS\ X\ Base\ System/BaseSystem.dmg 127 | else 128 | echo $ cp -rp /Volumes/install_app/BaseSystem.chunklist /Volumes/OS\ X\ Base\ System/BaseSystem.chunklist 129 | cp -rp /Volumes/install_app/BaseSystem.chunklist /Volumes/OS\ X\ Base\ System/BaseSystem.chunklist 130 | echo $ cp -rp /Volumes/install_app/BaseSystem.dmg /Volumes/OS\ X\ Base\ System/BaseSystem.dmg 131 | cp -rp /Volumes/install_app/BaseSystem.dmg /Volumes/OS\ X\ Base\ System/BaseSystem.dmg 132 | fi 133 | 134 | echo 135 | echo Unmount the installer image 136 | echo -------------------------------------------------------------------------- 137 | if [ "${isoName}" == "BigSur" ] ; then 138 | echo $ hdiutil detach /Volumes/"Install macOS Big Sur" 139 | hdiutil detach /Volumes/"Install macOS Big Sur" -force # NOTE: force because "Resource busy" 140 | elif [ "${isoName}" == "Monterey" ] ; then 141 | echo $ hdiutil detach /Volumes/"Install macOS Monterey" 142 | hdiutil detach /Volumes/"Install macOS Monterey" -force # NOTE: force because "Resource busy" 143 | else 144 | echo $ hdiutil detach /Volumes/install_app 145 | hdiutil detach /Volumes/install_app 146 | fi 147 | 148 | echo 149 | echo Unmount the sparse bundle 150 | echo -------------------------------------------------------------------------- 151 | if [[ "${isoName}" == "BigSur" || "${isoName}" == "Monterey" ]] ; then 152 | echo "N/A skipping..." 153 | elif [ "${isoName}" == "Mojave" ] || [ "${isoName}" == "Catalina" ] ; then 154 | echo $ hdiutil detach /Volumes/macOS\ Base\ System/ 155 | hdiutil detach /Volumes/macOS\ Base\ System/ 156 | else 157 | echo $ hdiutil detach /Volumes/OS\ X\ Base\ System/ 158 | hdiutil detach /Volumes/OS\ X\ Base\ System/ 159 | fi 160 | echo 161 | echo Resize the partition in the sparse bundle to remove any free space 162 | echo -------------------------------------------------------------------------- 163 | echo $ hdiutil resize -size `hdiutil resize -limits /tmp/${isoName}.sparseimage | tail -n 1 | awk '{ print $1 }'`b /tmp/${isoName}.sparseimage 164 | hdiutil resize -size `hdiutil resize -limits /tmp/${isoName}.sparseimage | tail -n 1 | awk '{ print $1 }'`b /tmp/${isoName}.sparseimage 165 | 166 | echo 167 | echo Convert the ${isoName} sparse bundle to ISO/CD master 168 | echo -------------------------------------------------------------------------- 169 | echo $ hdiutil convert /tmp/${isoName}.sparseimage -format UDTO -o /tmp/${isoName} 170 | hdiutil convert /tmp/${isoName}.sparseimage -format UDTO -o /tmp/${isoName} 171 | 172 | echo 173 | echo Remove the sparse bundle 174 | echo -------------------------------------------------------------------------- 175 | echo $ rm /tmp/${isoName}.sparseimage 176 | rm /tmp/${isoName}.sparseimage 177 | 178 | echo 179 | echo Rename the ISO and move it to the desktop 180 | echo -------------------------------------------------------------------------- 181 | echo $ mv /tmp/${isoName}.cdr ~/Desktop/${isoName}.iso 182 | mv /tmp/${isoName}.cdr ~/Desktop/${isoName}.iso 183 | fi 184 | } 185 | 186 | # 187 | # installerExists 188 | # 189 | # Returns 0 if the installer was found either locally or in the /Applications directory. 1 if not. 190 | # 191 | function installerExists() 192 | { 193 | local installerAppName=$1 194 | local result=1 195 | if [ -e "${installerAppName}" ] ; then 196 | result=0 197 | elif [ -e /Applications/"${installerAppName}" ] ; then 198 | result=0 199 | fi 200 | return ${result} 201 | } 202 | 203 | # 204 | # Main script code 205 | # 206 | # Eject installer disk in case it was opened after download from App Store 207 | # grep "partition_scheme" because "partition" finds too many lines 208 | for disk in $(hdiutil info | grep /dev/disk | grep partition_scheme | cut -f 1); do 209 | hdiutil detach -force ${disk} 210 | done 211 | 212 | # See if we can find an eligible installer. 213 | # If successful, then create the iso file from the installer. 214 | 215 | if installerExists "Install macOS Monterey.app" ; then 216 | createISO "Install macOS Monterey.app" "Monterey" 217 | elif installerExists "Install macOS Big Sur.app" ; then 218 | createISO "Install macOS Big Sur.app" "BigSur" 219 | elif installerExists "Install macOS Catalina.app" ; then 220 | createISO "Install macOS Catalina.app" "Catalina" 221 | elif installerExists "Install macOS Mojave.app" ; then 222 | createISO "Install macOS Mojave.app" "Mojave" 223 | elif installerExists "Install macOS High Sierra.app" ; then 224 | createISO "Install macOS High Sierra.app" "HighSierra" 225 | elif installerExists "Install macOS Sierra.app" ; then 226 | createISO "Install macOS Sierra.app" "Sierra" 227 | elif installerExists "Install OS X El Capitan.app" ; then 228 | createISO "Install OS X El Capitan.app" "ElCapitan" 229 | elif installerExists "Install OS X Yosemite.app" ; then 230 | createISO "Install OS X Yosemite.app" "Yosemite" 231 | else 232 | echo "Could not find installer for Yosemite (10.10), El Capitan (10.11), Sierra (10.12), High Sierra (10.13), Mojave (10.14), Catalina (10.15), Big Sur (11.0), or Monterey (12.0)." 233 | fi 234 | --------------------------------------------------------------------------------