Table of Contents

About

This sections covers the configuration of a Linux server (currently using Debian) that will be made to server network boot images for connecting Apple OS X clients such that they can boot directly off the server.

Requirements

Booting OS X over the network requires several server softwares to be installed. Here is a list that must be installed:

The notes do not cover a full configuration of ISC DHCPd and assumes that you have an ISC DHCPd server set up on your network that hands out IP addresses to clients. Similarly, setting up Apache is also not covered here - you will need to install Apache2 and figured out where the web root is and check that it is capable of serving the default files to clients on the network.

For simplicity's sake, this guide considers that trivial FTP, ISC DHCPd and Apache2 runs on the same server located on a class C network at 192.168.0.1.

Creating the Image

The System Image Utility (part of the server install) is only able to create images for the current OS X version that the utility runs under. In other words, the System Image Utility from the Snow Leopard server will be able to created images only for booting or installing Snow Leopard; the System Image Utility from the El Capitan server will be able to create images only for booting or installing El Capitan; etc…

There are several types of images that can be created by the System Image Utility:

The tutorial covers creating a NetBoot image for El Capitan: an image that can be booted off over the network.

Once you have the server installed and you have made sure that Install OS X El Capitan.app is placed in /Applications you can start the System Image Utility application and follow the on-screen prompts.

Select:

  1. Source: Install OS X El Capitan
  2. NetBoot Image

and then all the other options can be left at their defaults. The wizard will ask you where to save the image - the easiest, of course, is to place it on the desktop from where parts of it will be transferred to the server.

Configuring Trivial FTP

Under Debian, we would install the tftpd-server and then configure tftpd by editing the /etc/defaults/tftpd-hpa:

# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="192.168.0.1:69"
#TFTP_OPTIONS="--secure"

It is a good idea to remove the –secure in TFTP_OPTIONS or comment out TFTP_OPTIONS like in the example above. After that, restart trivial ftp by issuing:

/etc/init.d/tftpd-hpa restart

The next step is to transfer the files created by the System Image Utility in the i386 sub-folder to /srv/tftp/Apple/NetBoot/macnbi-i386. You should end-up with the following structure in the macnbi-i386 folder:

+ macnbi-i386
      +
      |
      +- booter
      +- PlatformSupport.plist
      +- x86_64
           +
           |
           +- kernelcache

With these files in-place we can now configure the Apache root that will be serving the actual image.

Configuring Apache to Serve Images

Assuming that you have a web root under /var/www, we will be creating the path /var/www/Apple/NetBoot/El Capitan where we will transfer some additional files created by the System Image Utility (mostly, the image itself).

You should end-up with the following structure in /var/www/Apple/NetBoot/El Capitan:

+ El Capitan
     +
     |
     + NBImageInfo.plist
     + NetBoot.dmg

To check, you should be able to point your browser at your server and check that you can download NetBoot.dmg and NBImageInfo.plist.

Configure DHCPd

The first thing that must be added to DHCPd is an option to allow booting over the network. The DHCPd configuration file (usually located at /etc/dhcp/dhcpd.conf) must be edited in order to add the following options in a global scope:

# Allow booting
allow booting;
allow bootp;

The next step is to add a class for NetBoot OS X clients to the DHCPd configuration file. It is a good idea to read through the settings because it is all documented:

class "Apple-Intel-Netboot" {
    # Limit this class to only Intel Apple machines
    match if substring (option vendor-class-identifier, 0, 14) = "AAPLBSDPC/i386";
    
    # From: http://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xml
    # 1 - Subnet Mask
    # 3 - Router
    # 17 - Root Path
    # 43 - Vendor Specific
    # 60 - Class ID
    # Send these options to the client (possibly forcing it, if the client didn't request it)
    option dhcp-parameter-request-list 1,3,17,43,60;

    if (option dhcp-message-type = 8) {
        # on DHCPInform Messages, Us/Our (Server), Them (Client)
        # Let Them know we're responding with Apple BSDP Information
        option vendor-class-identifier "AAPLBSDPC";
        if (substring(option vendor-encapsulated-options, 0, 3) = 01:01:01) {
            log(info, "BSDP_LIST");
            # BSDP List
            # Let Them know this is the let, what server, the server's priority, what Our default image is, and provide the image list
            option vendor-encapsulated-options
                # Start BSDP Inform/List Option 1 (01:), Length 1 (01:), Message Type List(1) (01:)
                01:01:01:
                # BSDP option code 3 (length 04) -- Server Identifier        
                03:04:
                    # Server IP (192.168.0.1), Dec->Hex
                    C0:A8:00:01:
                # BSDP option code 4 (length 02) -- Server Priority
                04:02:
                    # Priority (32768) Dec->Hex
                    80:00:
                # BSDP option code 7 (length 04) -- Default Image ID   
                07:04:
                    # This is what is picked as Default when you only hold down N on the client
                    #
                    # 01 breaks into: 0 or 8 for Non-Install (NetBoot) set or Install (NetInstal) set,
                    # Then 0 for Mac OS 9, 1 for Mac OS X (Client) 2 for OS X Server, and 3 for Hardware Diagnostics
                    #
                    # 4 through 127 (x4:00-xf:ff) reversed for future use
                    #
                    # And the last two are for the Image ID (Dec->Hex)
                    #
                    # IDs 1-4095 (00:01-0F:FF) are for Server-Specific Images (You will probably want an ID in this range)
                    # IDs 4096-65535 (10:00-FF:FF) Are "Globally-Unique", Multiple servers can present this same ID
                    # and the client will only see one image, and pick a random(?) server to talk to.
                    #
                    # Image ID - (137) Dec->Hex
                    01:00:00:89:
                # BSDP option code 9 -- Boot image list
                09:
                    # Length = 5 * <number of images> + <sum of the number of characters in the image name>
                    # For this case: 5 * (1 image) + (20 characters "NetBoot (El Capitan)") = 25 = 19 in Hex
                    19:
                        # This only appears once in the package, no matter how many images you have below
                        # Image ID (137) -- dec->hex, see above (Default Image ID) for how to formulate the full ID
                        01:00:00:89:
                             # Format: <sum of characters in image name>:<the name of the image in Hex>
                             # For this example: 20 characters so 14 hex:N:e:t:B:o:o:t: :(:E:l: :C:a:p:i:t:a:n:);
                             # Note that since no other images follow, this is ended by the semi-colon (;) - otherwise
                             # this segment would end with colon (:) after which the other images would follow.
                             14:4e:65:74:42:6f:6f:74:20:28:45:6c:20:43:61:70:69:74:61:6e:29;
                        # Image ID -- 138
                        #81:00:00:8A:
                        #     # Length(Hex:17,Dec:23):Name (DSR-NB01012012-05122012)
                        #     17:44:53:52:2d:4e:42:30:31:30:31:32:30:31:32:2d:30:35:31:32:32:30:31:32;
        } elsif (substring(option vendor-encapsulated-options, 0, 3) = 01:01:02) {
            log(info, "BSDP_SELECT");
            # This is BSDP Option 3 (Length 04)
            #
            # BSDP Select, This is the client selecting which image they want to boot from
            # Here we basically do if statements to catch what image is referenced
            # Since we MIGHT be clustered, Check to see if we're the server being asked.
            #
            # In this example "C0:A8:00:01" is the hex representation of "192.168.0.1" which
            # is the IP address of the server dishing out the image files for net booting.
            if (substring(option vendor-encapsulated-options, 9, 4) = C0:A8:00:01) {
                log(info, "BSDP_SELECT-Responding, Client is talking to us.");
                # Catch Image ID 01:00:00:89 defined above (NetBoot)
                if (substring(option vendor-encapsulated-options, 15, 4) = 01:00:00:89) {
                    log(info, "BSDP_SELECT-Image: NetBoot");
                    
                    # This file is retrieved from System Image Utility on OS X when it creates a NetBoot image.
                    # The "booter" file along with all the other files are created by the System Image Utility
                    # on OS X and placed where the .NBI folder is created under i386/. The files must be then
                    # be copied from OSX and then served by the server through tftpd (Trivial FTP) by this server.
                    #
                    # Tree structure is:
                    # /srv
                    #   +
                    #   |
                    #   +- /tftp
                    #        +
                    #        |
                    #        + /Apple
                    #            +
                    #            |
                    #            + /NetBoot
                    #                 +
                    #                 |
                    #                 +- /macnbi-i386
                    #                         +
                    #                         |
                    #                         +- booter
                    #                         +- PlatformSupport.plist
                    #                         +- x86_64
                    #                              +
                    #                              |
                    #                              +- kernelcache
                    #
                    filename "/srv/tftp/Apple/NetBoot/macnbi-i386/booter";
                    
                    # In this example HTTP is used to serve the image.
                    #
                    # Tree structure is:
                    # Web Server Root
                    #       +
                    #       |
                    #       +- /Apple
                    #            +
                    #            |
                    #            +- /Netboot
                    #            +
                    #            |
                    #            +- El Capitan (space encoded with %20)
                    #                   +
                    #                   |
                    #                   +- NetBoot.dmg
                    #                   +- NBImageInfo.plist
                    #
                    option root-path "http://192.168.0.1/Apple/NetBoot/El%20Capitan/NetBoot.dmg";
                    
                    # The image can also be served though NFS.
                    #option root-path "nfs:192.168.0.1:/srv/nfs/pxe/NetBoot:NetBoot.dmg";
                    
                } else {
                    log(info,"BSDP_SELECT-ERROR: Client responded with an image we don't have a match for! -- (Image added to list, but not in select catch?)");
                }
            } else {
                log(info,"BSDP_SELECT-Ignoring, Client is talking to another server--We're not worthy!"); # Log that we are not worthy of the client's time
            }
        }
    }
}

Most of the parts to configure are documented in the above snippet but some of them require some special attention.

Notes

name:    N  e  t  B  o  o  t     (  E  l     C  a  p  i  t  a  n  )
hexa: 14 4e 65 74 42 6f 6f 74 20 28 45 6c 20 43 61 70 69 74 61 6e 29
      +  +                                                        +
      |  |                                                        |
      |  +--------------------------------------------------------+
      |      20 characters (20 decimal is 14 in hexadecimal)
      |                       +
      |                       |
      +-----------------------+

Booting

After setting up everything, boot an OS X computer while holding down the Alt key. This will make you boot to the device selection from where you should see the NetBoot (El Capitan) image displayed as a globe on a hard-drive. For the first run, it is a good idea to select the icon with the cursor keys and then hold down +V while pressing enter in order to perform a verbose boot.

Switch to NFS

You can switch over to NFS for the image - which is perhaps a better option in the long run. In order to do that, you would amend the DHCPd configuration file to comment out the root-path and add a different one for NFS:

option root-path "nfs:192.168.0.1:/srv/nfs/pxe/NetBoot:NetBoot.dmg";

The root-path option can be broken down into:

nfs:192.168.0.1:/srv/nfs/pxe/NetBoot:NetBoot.dmg
 ^      ^               ^               ^
 |      |               |               |
 |      |               |               + the netboot image
 |      |               |
 |      |               + path to the image
 |      |
 |      + the nfs server
 |
 + use nfs

Additionally, an NFS server has to be configured. On Debian, this can be achieved by installing the nfs-server virtual package. After that, you would need to edit the /etc/exports file to export the path to the image. Assuming that the image is in /srv/nfs/pxe/NetBoot, you would add a line to /etc/exports such as:

/srv/nfs/pxe 192.168.0.0/24(ro,async,no_root_squash,no_subtree_check,insecure)

which will have the effect of exporting the subtree starting from /srv/nfs/pxe to the 192.168.0.0/24 network.

After that, you would have to restart the NFS server via: /etc/init.d/nfs-kernel-server restart or, in case you previously had exports, re-export by issuing: exportfs -arv.

Issues