Author: Jeff McCune
Avoid paying for a Mac OS X Server license if just need to automate your host installation work flow. Installing machines by hand is such a PITA...
Note: Even seasoned Unix administrators will spend a few hours setting all this crap up. Depending on your salary, it may be wise to just throw down for a Mac OS X Server license. Apple really does just let you click it in...
With that said, this information will give you unparalleled control over the whole system.
NOTE: HTTP is easier than NFS to get working with both Intel and PowerPC as the service providing the root file system image. NFS works, I'd just recommend starting with HTTP since it's a relatively simple and well understood protocol.
This is a private network, so you should have total control. Here's what works for me.
| Service | Why we need it |
|---|---|
| NetRestore Helper | NetBoot-Install Images are easeily created using this free tool written by Mike Bombich. |
| CentOS | CentOS is like RedHat Enterprise, just with Yum preconfigured. We'll use CentOS to host the services required to make BSDP NetBoot-Install work. |
| ISC DHCP server | Service BSDP Broadcast Requests on the private network. ISC DHCP now works fine with Intel and PowerPC machines without patches to it's sourcecode. |
| TFTP server | We need to serve the darwin kernel, bootloader, and kernel extension cache file. A Mac's firmware speaks TFTP initially. |
| DNS Server | Service DNS Requests on the private network. We'll use dnsmasq since it's trivial to setup. |
| NFS Server | Serve Root File System. I prefer NFS to HTTP since the clients can re-mount the NFS server easily. NetRestore Helper exposes this feature as a single checkbox. |
| HTTP Server | Serve Root File System DMG's & Rails Application Server. It's generally good to have an HTTP server handy, since it's easy to understand and configure. I'm partial to Lighttpd since it's small, fast, and easy to setup. |
We're assuming the linux gateway dual-homed server is located at:
| Internal Interface | |
|---|---|
| Interface: | eth1 |
| IP: | 192.168.7.1 |
| NetMask: | 255.255.255.0 |
| External Interface | |
|---|---|
| Interface: | eth0 |
| IP: | DHCP |
I use this bash script to route traffic from DHCP clients on the private network to the external network, using the linux server as a router gateway:
#!/bin/bash # iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE iptables -A FORWARD -i eth0 -m state --state NEW,INVALID -j DROP echo 1 > /proc/sys/net/ipv4/ip_forward
Install ISC-DHCP from the CentOS base repository:
yum -y install dhcp
Install HTTP Server:
yum -y install lighttpd
Install a TFTP server:
yum -y install tftp-server
Install a lightweight DNS server:
yum -y install dnsmasq
Here's how we configure ISC DHCP to service Apple BSDP requests. This should work with BSDP requests coming from OpenFirmware and Intel EFI.
First, tell dhcpd to start only on the internal interface. We don't want to hijack an existing DHCP server on the public LAN.
# /etc/sysconfig/dhcpd DHCPDARGS=eth1
Enable DHCP startup on boot:
chkconfig --level 2345 dhcpd on
NOTE: Many thanks to **Christopher J. Suleski** for emailing me a working ISC DHCP configuration for Intel machines. Without his efforts, this information wouldn't be available. Sample /etc/dhcpd.conf:
# JJM ISC DHCP Configuration, providing BSDP Service to Apple Hardware.
# 2006-12-05
#
ddns-update-style none;
ddns-updates off;
ignore client-updates;
allow booting;
authoritative;
class "AppleNBI-i386" {
match if substring (option vendor-class-identifier, 0, 14) = "AAPLBSDPC/i386";
option dhcp-parameter-request-list 1,3,17,43,60;
if (option dhcp-message-type = 1) { option vendor-class-identifier "AAPLBSDPC/i386"; }
if (option dhcp-message-type = 1) { option vendor-encapsulated-options 08:04:81:00:00:67; }
# The Apple Boot Loader binary image. This file will in turn TFTP the kernel image and extension cache.
filename "macnbi-i386/booter";
## JJM Root FS DMG on HTTP Server:
# option root-path "http://192.168.7.1/Netboot/NetBootSP0/MacOSX10.4.5.i386.JJM.nbi/NetInstall-Restore.dmg";
## JJm Root FS DMG on NFS Server.
# (Note the placement of the second ":" This indicates where /var/netboot is mounted on each client.
# The Resources folder should be in the folder indicated by the :, /nbi in this instance.
## NOTE: THIS ROOT PATH IS TOO LONG AND WILL NOT WORK.
# option root-path "nfs:192.168.7.1:/disk/0/Netboot/NetBootSP0:MacOSX10.4.5.i386.JJM.nbi/NetInstall-Restore.dmg";
## NOTE: Try to keep the root path as short as possible. I copy the DMG files to /nbi and export that folder.
option root-path "nfs:192.168.7.1:/nbi:NBI-i386.dmg";
}
class "AppleNBI-ppc" {
match if substring (option vendor-class-identifier, 0, 13) = "AAPLBSDPC/ppc";
option dhcp-parameter-request-list 1,3,6,12,15,17,43,53,54,60;
# The Apple Boot Loader binary image. This file will in turn TFTP the kernel image and extension cache.
filename "macnbi-ppc/booter";
option vendor-class-identifier "AAPLBSDPC";
if (option dhcp-message-type = 1) {
option vendor-encapsulated-options 08:04:81:00:00:09;
}
elsif (option dhcp-message-type = 8) {
option vendor-encapsulated-options 01:01:02:08:04:81:00:00:09;
}
else {
option vendor-encapsulated-options 00:01:02:03:04:05:06:07;
}
## JJM Root FS DMG on HTTP Server:
# option root-path "http://192.168.7.1/Netboot/NetBootSP0/MacOSX10.4.5.powerpc.JJM.nbi/NetInstall-Restore.dmg";
## JJm Root FS DMG on NFS Server.
# (Note the placement of the second ":" This indicates where /var/netboot is mounted on each client.
# The Resources folder should be in the folder indicated by the :, /nbi in this instance.
## NOTE: THIS ROOT PATH IS TOO LONG AND WILL NOT WORK.
# option root-path "nfs:192.168.7.1:/disk/0/Netboot/NetBootSP0:MacOSX10.4.5.powerpc.JJM.nbi/NetInstall-Restore.dmg";
## NOTE: Try to keep the root path as short as possible. I copy the DMG files to /nbi and export that folder.
option root-path "nfs:192.168.7.1:/nbi:NBI-ppc.dmg";
}
subnet 192.168.7.0 netmask 255.255.255.0 {
pool {
range 192.168.7.100 192.168.7.199;
}
default-lease-time 7200; # 2 hours
max-lease-time 86400; # 1 day
option domain-name "alpha.secure.lan";
option routers 192.168.7.1;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.7.255;
option domain-name-servers 192.168.7.1;
option time-offset -18000; # EST
allow unknown-clients;
}
Start the DHCP server:
/etc/init.d/dhcpd stop /etc/init.d/dhcpd start
We need this to serve the kernel image to the client firmware. Enable TFTP Services:
chkconfig --level 2345 tftp on
Copy the booter into place. Obtain the bootloader and kernel files from the NetBoot-Install image you created with NetRestore Helper, or by generating them yourself (See the Extras Section. My /tftpboot looks like this:
[root@tom ~]# find /tftpboot/ -type f /tftpboot/macnbi-i386/mach.macosx /tftpboot/macnbi-i386/booter /tftpboot/macnbi-i386/mach.macosx.mkext /tftpboot/macnbi-ppc/mach.macosx /tftpboot/macnbi-ppc/booter /tftpboot/macnbi-ppc/mach.macosx.mkext
Restart the TFTP server:
/etc/init.d/xinetd restart
You can test TFTP transfers using a tftp client:
yum install tftp tftp localhost binary get /macnbi-ppc/booter
We need an HTTP server to provide our root file system over the network. It will also server the image we clone to the client hard disk.
# /etc/lighttpd/lighttpd.conf # Add / Uncomment server.modules = ( "mod_alias", "mod_access", "mod_accesslog" ) alias.url = ( "/Netboot/" => "/disk/0/NetBoot/" ) server.dir-listing = "enable"
The "*.nbi" folders created with Netrestore Helper should be copied to /disk/0/NetBoot/NetBootSP0/
Enable lighttpd startup:
chkconfig --level 2345 lighttpd on
Restart lighttpd:
/etc/init.d/lighttpd restart
NOTE: NFS works with an unpatched ISC DHCP server, but you must keep the root-path option string as short as possible. There's an option length limit. I'm not sure of the exact value, but it's enough to be annoying. This is why the ISC patch is necessary in some cases, which you may have seen floating around the web.
I prefer NFS over HTTP, since it allows the client to easily mount the Resources directory of the NetBoot server. This emulates the behavior of a standard Mac OS X server, and the option to mount the server's file system is a single checkbox in NetRestore Helper.
My /etc/exports looks like this:
# NFS Export the NetBoot Folder /disk/0/NetBoot 192.168.7.0/24(async,ro,no_root_squash,insecure) # Shorten the path string we need to send over DHCP. /nbi 192.168.7.0/24(async,ro,no_root_squash,insecure)
Restart the NFS Services:
/etc/init.d/nfs restart
/etc/init.d/nfslock restart
Configure NFS to start on boot:
chkconfig --level 2345 nfs on
chkconfig --level 2345 nfslock on
In order to use NFS between the NBI clients and server, you must modify the DHCP configuration to inform the clients NFS is used instead of HTTP.
Modify the root-path class option to use NFS instead of HTTP:
# /etc/dhcpd.conf # Example for PowerPC: option root-path "nfs:192.168.1.7:/nbi:NBI-ppc.dmg"; # Example for i386: option root-path "nfs:192.168.1.7:/nbi:NBI-i386.dmg";
Important: Note the placement of the second ":" in the root-path option for NFS. This indicates what is mounted onto /var/netboot on each client. This helps us access the Resources folder on each client. I strongly recommend keeping data inside the Resources folder as a working copy of some revision control system... CVS, Subversion, Bazaar, etc...
At this point, all the services required to boot a Mac OS X workstation from the network are installed and configured.
tail -n 100 -f /var/log/messages We need to turn off DHCP support in dnsmasq:
/etc/dnsmasq.conf:
local=/lan/ read-ethers listen-address=192.168.7.1,127.0.0.1 no-dhcp-interface=eth1 expand-hosts
Generate host entries for DNS. These hosts will look like dhcp102.alpha.secure.lan:
perl -e 'for ($x=100;$x<200;$x++) { printf "192.168.7.%02d\t dhcp%03d\n", $x, $x; }' \
>> /etc/hosts
Testing Forward DNS:
dig dhcp107 @127.0.0.1
You should get back:
; <<>> DiG 9.2.4 <<>> dhcp107 @127.0.0.1 ; (1 server found) ;; global options: printcmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19499 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;dhcp107. IN A ;; ANSWER SECTION: dhcp107. 0 IN A 192.168.7.107 ;; Query time: 7 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Tue Dec 5 21:08:13 2006 ;; MSG SIZE rcvd: 41
Testing Reverse DNS: dig -x 192.168.1.107 @127.0.0.1 You should get back:
; <<>> DiG 9.2.4 <<>> -x 192.168.7.102 @127.0.0.1 ; (1 server found) ;; global options: printcmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38306 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;102.7.168.192.in-addr.arpa. IN PTR ;; ANSWER SECTION: 102.7.168.192.in-addr.arpa. 0 IN PTR dhcp102.alpha.secure.lan. ;; Query time: 6 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Tue Dec 5 21:06:17 2006 ;; MSG SIZE rcvd: 82
It's a good idea to have all the hosts agree on their SSH host identification keys:
Create directories for every host:
perl -e 'for ($x=100;$x<200;$x++) { printf "mkdir dhcp%03d\n", $x; }' | bash
Generate SSH Keys for every host:
perl -e 'for ($x=100;$x<200;$x++) { printf "ssh-keygen -q -t rsa -f dhcp%03d/ssh_host_rsa_key -N \"\" -C \"\"\n", $x; }' | bash
perl -e 'for ($x=100;$x<200;$x++) { printf "ssh-keygen -q -t dsa -f dhcp%03d/ssh_host_dsa_key -N \"\" -C \"\"\n", $x; }' | bash
Sometimes it's beneficial to update to a more recent version of the Darwin kernel and extension cache in order to boot new hardware without generating an entirely new NetBoot-Install image using NetRestore Helper.
Here's how. We'll generate the files from a machine of each architecure and copy them into the /tftpboot folder of the Linux BSDP server.
These steps must be run on an Intel Mac. In 10.5, Leopard, we'll finally have a unified system.
Make the Container:
mkdir /tmp/macnbi-i386
Generate the kernel image:
ditto /mach_kernel /tmp/macnbi-i386/mach.macosx
Or, thin out the fat kernel binary:
lipo -extract i386 -output /tmp/macnbi-i386/mach.macosx /mach_kernel
Create the kernel extension cache:
kextcache -a i386 -s -l -n -z -m /tmp/macnbi-i386/mach.macosx.mkext /System/Library/Extensions
Copy the Boot Loader binary:
ditto /usr/standalone/i386/boot.efi /tmp/macnbi-i386/booter
You'll then want to copy /tmp/macnbi-i386 to the tftpboot folder on the Linux BSDP server and make sure /etc/dhcpd.conf is providing the correct path to the booter file.
These steps must be run on an PowerPC Mac. In 10.5, Leopard, we'll finally have a unified system.
Make the Container:
mkdir /tmp/macnbi-ppc
Copy the Mach Kernel:
ditto /mach_kernel /tmp/macnbi-ppc/mach.macosx
Create the kernel extension cache:
kextcache -a ppc -s -l -n -z -m /tmp/macnbi-ppc/mach.macosx.mkext /System/Library/Extensions
Copy the Boot Loader binary:
ditto /usr/standalone/ppc/bootx.bootinfo /tmp/macnbi-ppc/booter
You'll then want to copy /tmp/macnbi-ppc to the tftpboot folder on the Linux BSDP server and make sure /etc/dhcpd.conf is providing the correct path to the booter file.