The NetBoot service allows administrators of OS X computers to leverage images hosted on a server to boot computers to a central location and put a new image on them, upgrade them and perform automations based on upgrades and images. Since the very first versions of OS X, the service has been called NetBoot. In the Server app, Apple provides a number of options surrounding the NetInstall service, based on Automator-style actions, now calling the service NetInstall.
The first step to configuring the NetInstall service is to decide what you want the service to do. There are three options available in System Image Utility (available under the Tools menu of the Server app in OS X Server):
- Create a NetBoot Image: Allows Macs to boot over the network to a disk image hosted on a server.
- Create a NetInstall Image: Leverage NetBoot as a boot disk so that an image hosted on a server can be used to run an OS X installer.
- Create a NetRestore Image: Leverage NetBoot as a boot disk so that you can restore a computer that has been configured over a network. Use this option to restore an image that has been prepared.
For the purposes of this example, we’re going to use an OS X Mavericks (10.9) installer running Server 3 to boot an OS X computer over the network. The first step in doing so is to create a Network Disk Image of 10.9, or the 10.9 installation media (which is the Install OS X Mavericks bundle for this example). Before setting it up, download the Install OS X Mavericks installer app into the /Applications directory from the App Store.
To then set up the NetBoot disk image (you can’t start the NetInstall service until you give it an image to serve), often referred to as the NetBoot set, open the Server app and then click on System Image Utility from the Tools menu of OS X.
When System Image Utility opens, click on the Install OS X Mountain Lion entry in the list of available sources. Then, in the list of options, click on NetBoot Image and then click on the Continue button.
At the Image Settings screen, enter the name the NetBoot set will have in the Network Disk field. Then, enter a description of what is on the NetBoot set in the Description field. If the image will be served from multiple servers, check the box for “Image will be served from more than one server.”
Then provide an account name, short name and password in the Image Settings screen. Once provided, click Create to generate the Network Disk Image.
When prompted, click on the Agree button to accept the licensing agreement.
Then, when prompted, select a location to store the Disk Image, provide any tags to be applied to the files that comprise the image and click on Save.The computer will then start creating the NetBoot set. Once finished, it’s time to set up the NetInstall service in OS X Mountain Lion Server. To get started, go back to the Server app.First, define which disk will host NetBoot Images. To do so, click on the Edit Storage Settings button. At the Storage Settings overlay, select the volume that Images will be hosted as well as the volume that Client Data will be hosted. The Image is what you are creating and the Client Data is dynamic data stored in images.
If you only have one disk, as in this example, click on “Images & Client Data” for that disk. Then click on the OK button. Once you’ve selected a disk to store your image, we need to copy the disk image into the Library/NetBoot/NetBootSP0 folder of the disk used for images. Once in the appropriate folder, click on the Edit button for the Enable NetInstall on: field
Check the box for the interface you want to serve images over (if you only have one then it’s pretty obvious which interface this will be. Click on the OK button to save your settings. Then, click on the Images tab.
Each server can host multiple images. The Images tab displays a list of NetBoot images stored in the Library/NetBoot/NetBootSP0 directory. By default, images have a red indicator light. This means they’re not being served over any specific protocol yet. Double-click on an image.
At the image settings screen, check the box for “Make available over” and for many environments, select NFS as the protocol. Note, you can also restrict access to the image to certain models of Apple computers and/or certain MAC addresses by using the “Image is visible to” and “Restrict access to this images” options respectively. Additionally, use the Make this image available for diskless booting option to allow computers without hard drives to boot to the image.
Click on the Done button and the image will appear as green in the list of images. Click on the image and then click on the cog-wheel icon. Click on “Use as Default Boot Image” to set an image to be the default images computers boot to when booting to NetBoot. Now, it’s as easy as clicking on the ON button. Do so to start the service.
Once started, open a Terminal window. Here, let’s get a status of the service using the serveradmin fullstatus option (along with the service name, which is still netboot from the command line):
sudo serveradmin fullstatus netboot
The output of which shows the various components, logs and states of components:
netboot:state = "RUNNING"
netboot:stateTFTP = "RUNNING"
netboot:readWriteSettingsVersion = 1
netboot:netBootConnectionsArray = _empty_array
netboot:logPaths:netBootLog = "/var/log/system.log"
netboot:dhcpLeasesArray = _empty_array
netboot:stateDHCP = "STOPPED"
netboot:stateHTTP = "RUNNING"
netboot:serviceCanStart = 0
netboot:timeOfSnapshot = "2013-10-07 18:39:33 +0000"
netboot:stateNFS = "RUNNING"
netboot:stateImageArray:_array_index:0:_array_index:0 = 0
netboot:stateImageArray:_array_index:0:_array_index:1 = 0
netboot:stateImageArray:_array_index:0:_array_index:2 = 0
netboot:stateImageArray:_array_index:0:_array_index:3 = 0
netboot:stateImageArray:_array_index:0:_array_index:4 = 2
netboot:stateImageArray:_array_index:1:_array_index:0 = 0
netboot:stateImageArray:_array_index:1:_array_index:1 = 0
netboot:stateImageArray:_array_index:1:_array_index:2 = 0
netboot:stateImageArray:_array_index:1:_array_index:3 = 0
netboot:stateImageArray:_array_index:1:_array_index:4 = 2
netboot:stateImageArray:_array_index:2:_array_index:0 = 0
netboot:stateImageArray:_array_index:2:_array_index:1 = 0
netboot:stateImageArray:_array_index:2:_array_index:2 = 0
netboot:stateImageArray:_array_index:2:_array_index:3 = 0
netboot:stateImageArray:_array_index:2:_array_index:4 = 2
netboot:stateImageArray:_array_index:3:_array_index:0 = 0
netboot:stateImageArray:_array_index:3:_array_index:1 = 0
netboot:stateImageArray:_array_index:3:_array_index:2 = 0
netboot:stateImageArray:_array_index:3:_array_index:3 = 0
netboot:stateImageArray:_array_index:3:_array_index:4 = 2
netboot:servicePortsRestrictionInfo = _empty_array
netboot:netBootClientsArray = _empty_array
netboot:servicePortsAreRestricted = "NO"
netboot:setStateVersion = 1
netboot:startedTime = ""
netboot:stateAFP = "RUNNING"
And to start the service when not running:
sudo serveradmin start netboot
There are also a number of settings available at the command line that are not in the graphical interface. For example, to allow writing to the NetBoot share:
sudo serveradmin settings netboot:netBootStorageRecordsArray:_array_index:0:readOnlyShare = no
Or to get more verbose logs:
sudo serveradmin settings netboot:logging_level = "HIGH"
To stop the service:
sudo serveradmin stop netboot
In the beginning of this article, I mentioned that ways to configure NetInstall images. I’ll cover NetInstall and NetRestore in later articles as they tend to be more involved workflow-wise than copying a volume into a Network Disk Image. But to end this one, many an old-school admin might wonder where all the settings went that used to be in the GUI. Well, serveradmin still maintains a lot of the older stuff. To see a list of all available settings, run serveradmin with the settings verb and then netboot:
sudo serveradmin settings netboot
If there was a feature you want to use (e.g. maximum users), you should see it in the resultant list:
netboot:netBootFiltersRecordsArray = _empty_array
netboot:netBootStorageRecordsArray:_array_index:0:sharepoint = yes
netboot:netBootStorageRecordsArray:_array_index:0:clients = yes
netboot:netBootStorageRecordsArray:_array_index:0:volType = "hfs"
netboot:netBootStorageRecordsArray:_array_index:0:okToDeleteSharepoint = no
netboot:netBootStorageRecordsArray:_array_index:0:readOnlyShare = no
netboot:netBootStorageRecordsArray:_array_index:0:path = "/"
netboot:netBootStorageRecordsArray:_array_index:0:okToDeleteClients = yes
netboot:netBootStorageRecordsArray:_array_index:0:volName = "Mav"
netboot:netBootStorageRecordsArray:_array_index:1:sharepoint = yes
netboot:netBootStorageRecordsArray:_array_index:1:clients = yes
netboot:netBootStorageRecordsArray:_array_index:1:volType = "hfs"
netboot:netBootStorageRecordsArray:_array_index:1:okToDeleteSharepoint = yes
netboot:netBootStorageRecordsArray:_array_index:1:readOnlyShare = no
netboot:netBootStorageRecordsArray:_array_index:1:path = "/Volumes/Base_Image"
netboot:netBootStorageRecordsArray:_array_index:1:okToDeleteClients = yes
netboot:netBootStorageRecordsArray:_array_index:1:volName = "Base_Image"
netboot:netBootStorageRecordsArray:_array_index:2:sharepoint = yes
netboot:netBootStorageRecordsArray:_array_index:2:clients = yes
netboot:netBootStorageRecordsArray:_array_index:2:volType = "hfs"
netboot:netBootStorageRecordsArray:_array_index:2:okToDeleteSharepoint = yes
netboot:netBootStorageRecordsArray:_array_index:2:readOnlyShare = no
netboot:netBootStorageRecordsArray:_array_index:2:path = "/Volumes/New Volume 1"
netboot:netBootStorageRecordsArray:_array_index:2:okToDeleteClients = yes
netboot:netBootStorageRecordsArray:_array_index:2:volName = "New Volume"
netboot:netBootPortsRecordsArray:_array_index:0:deviceAtIndex = "en3"
netboot:netBootPortsRecordsArray:_array_index:0:isEnabledAtIndex = yes
netboot:netBootPortsRecordsArray:_array_index:0:nameAtIndex = "Thunderbolt Ethernet"
netboot:logging_level = "MEDIUM"
netboot:filterEnabled = no
netboot:netBootImagesRecordsArray:_array_index:0:imageType = "netboot"
netboot:netBootImagesRecordsArray:_array_index:0:IsInstall = no
netboot:netBootImagesRecordsArray:_array_index:0:Kind = "1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:0 = "iMac10,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:1 = "iMac11,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:2 = "iMac11,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:3 = "iMac11,3"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:4 = "iMac12,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:5 = "iMac12,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:6 = "iMac13,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:7 = "iMac13,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:8 = "iMac13,3"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:9 = "iMac7,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:10 = "iMac8,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:11 = "iMac9,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:12 = "Mac-031B6874CF7F642A"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:13 = "Mac-27ADBB7B4CEE8E61"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:14 = "Mac-50619A408DB004DA"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:15 = "Mac-77EB7D7DAF985301"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:16 = "MacBook5,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:17 = "MacBook5,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:18 = "MacBook6,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:19 = "MacBook7,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:20 = "MacBookAir2,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:21 = "MacBookAir3,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:22 = "MacBookAir3,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:23 = "MacBookAir4,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:24 = "MacBookAir4,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:25 = "MacBookAir5,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:26 = "MacBookAir5,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:27 = "MacBookAir6,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:28 = "MacBookAir6,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:29 = "MacBookPro10,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:30 = "MacBookPro10,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:31 = "MacBookPro3,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:32 = "MacBookPro4,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:33 = "MacBookPro5,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:34 = "MacBookPro5,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:35 = "MacBookPro5,3"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:36 = "MacBookPro5,4"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:37 = "MacBookPro5,5"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:38 = "MacBookPro6,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:39 = "MacBookPro6,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:40 = "MacBookPro7,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:41 = "MacBookPro8,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:42 = "MacBookPro8,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:43 = "MacBookPro8,3"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:44 = "MacBookPro9,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:45 = "MacBookPro9,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:46 = "Macmini3,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:47 = "Macmini4,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:48 = "Macmini5,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:49 = "Macmini5,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:50 = "Macmini5,3"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:51 = "Macmini6,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:52 = "Macmini6,2"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:53 = "MacPro3,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:54 = "MacPro4,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:55 = "MacPro5,1"
netboot:netBootImagesRecordsArray:_array_index:0:DisabledSystemIdentifiers:_array_index:56 = "Xserve3,1"
netboot:netBootImagesRecordsArray:_array_index:0:Description = "NetBoot of OS X 10.9 (13A598) Install (7.14 GB)."
netboot:netBootImagesRecordsArray:_array_index:0:Name = "NetBoot of Install OS X Mavericks"
netboot:netBootImagesRecordsArray:_array_index:0:pathToImage = "/Library/NetBoot/NetBootSP0/NetBoot of Install OS X Mavericks.nbi/NBImageInfo.plist"
netboot:netBootImagesRecordsArray:_array_index:0:Index = 1280
netboot:netBootImagesRecordsArray:_array_index:0:osVersion = "10.9"
netboot:netBootImagesRecordsArray:_array_index:0:BackwardCompatible = no
netboot:netBootImagesRecordsArray:_array_index:0:SupportsDiskless = no
netboot:netBootImagesRecordsArray:_array_index:0:EnabledSystemIdentifiers = _empty_array
netboot:netBootImagesRecordsArray:_array_index:0:Language = "Default"
netboot:netBootImagesRecordsArray:_array_index:0:BootFile = "booter"
netboot:netBootImagesRecordsArray:_array_index:0:IsDefault = no
netboot:netBootImagesRecordsArray:_array_index:0:Type = "HTTP"
netboot:netBootImagesRecordsArray:_array_index:0:Architectures = "4"
netboot:netBootImagesRecordsArray:_array_index:0:IsEnabled = yes
netboot:netBootImagesRecordsArray:_array_index:0:RootPath = "NetBoot.dmg"
netboot:afpUsersMax = "50"