Creating a NetBoot server with CentOS 7 and BSDPy

When I see people asking about NetBoot on Mac OS X or NetSUS, I often recommend people use BSDPy in a Docker container on Linux instead.

Which usually results in this kind of reaction:


So here is my guide for getting a NetBoot server setup quickly and easily with CentOS 7 and a BSDPy Docker container.

Bare with me, this is a bit of a long post as I’ll be walking you through it step by step.

Getting Started!

Get yourself a copy of the CentOS 7 ISO image, I chose to get the Everything ISO.

I’m going to create the Linux server as a VM in VMWare Fusion 7 on Mac OS X, but use whatever Hyper-Visor you want. Start your VM and begin the install.

Screen Shot 2015-04-24 at 12.42.08 pm

When you get to the install wizard. Make the usual choices for your environment date and time, network time server, keyboard and language support.

When you get to Software Selection lets use the default Minimal Install, we will install any extra packages we need manually.

No need to have a super bulky netboot server full of software that we are not going to use.

Screen Shot 2015-04-24 at 12.45.31 pm

For the Installation Destination, I make a couple of changes to the partitioning from the default.

Make sure to choose “I will configure partitioning myself” then click Done.

Screen Shot 2015-04-24 at 12.49.15 pm

You will be presented with the following dialog box.

Screen Shot 2015-04-24 at 12.50.27 pm

Click on the link to create them automatically. You should end up with it looking like this:

Screen Shot 2015-04-24 at 12.56.08 pm

Click Done and choose Accept Changes. Now ensure the VM has network connected and specify and hostname if you require.

Screen Shot 2015-04-24 at 12.57.51 pm

Begin the Install and set a password for the Root user. We don’t need to create any additional users, so we can leave that blank.

Screen Shot 2015-04-24 at 12.59.24 pm

Once complete, Reboot and you will be presented with a login screen:

Screen Shot 2015-04-24 at 1.05.38 pm

Configuring the server

Login with the Root user and the password that you set earlier.

First we will disable the Firewall and disable SELinux so that Docker containers are able to connect to the network with out issue.

Run the following commands:

~]# systemctl stop firewalld && systemctl disable firewalld
~]# sed -i -e 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

Now give your machine a reboot so that it starts up with SELinux turned off.

We need to install some extra packages;  Docker, and I also prefer to use Nano over Vi for text editing duties so we will include that. If you are behind a proxy server, you will need to tell the package manager (yum) to use your proxy server details.

To do this we simply put the proxy server details into the yum.conf file which is achieved by using the command:

~]# echo "proxy=" >> /etc/yum.conf

If you need to provide a username and password you can do that do with:

~]# echo "proxy=" >> /etc/yum.conf

Now lets update our package manager and install docker and nano with the below commands:

~]# yum -y update 
~]# yum -y install docker nano

Screen Shot 2015-04-24 at 1.23.22 pm

New in Docker 1.5 is the way it handles proxy servers. The Docker docs are here if you are interested: 

If you do not require a proxy server, then you can ignore these commands and move on to the next section.

Configuring Docker Proxy Server Settings

Create a directory called:     docker.service.d

~]# mkdir /etc/systemd/system/docker.service.d

Create a file called:     http-proxy.conf

~]# nano /etc/systemd/system/docker.service.d/http-proxy.conf

Now make sure this file has the following content:


Hit Control-x to exit, and hit Y to save changes.

If you need to provide a username and password for authenticated proxy access, then use the same syntax we used earlier: Eg.

Now just flush changes and restart docker:

~]# systemctl daemon-reload
~]# systemctl restart docker

Now we have Docker installed and configured for proxy servers if required.

Starting Docker Automatically

We need to get the Docker service running and configured to start every time the machine is turned on.

~]# service docker start 
~]# chkconfig docker on service docker restart

Screen Shot 2015-04-24 at 1.36.36 pm

Now we can pull down the BSDPy Docker container. The container has a page here, if you are interested. This particular container is one that I have built, feel free to inspect the docker file to see how it was created.

~]# docker pull hunty1/bsdpydocker

Now lets create a place to store our NetBoot images.

~]# mkdir /nbi

Take note of your server’s IP address which you can get from running: ip addr

Your IP address will be next to inet under the name of the ethernet adapter which will probably start with eth or eno or similar. On my machine my IP address is as you can see from this:

Screen Shot 2015-04-24 at 2.10.19 pm

If you want to set a static IP for the server then I recommend you follow this guide:

Running the Docker Container

To start the NetBoot server, we have to run our Docker image which creates a Container for it. Think of it like an image is just a template and when we run the template a container gets created and runs our application inside of it.

~]# docker run --restart=always -d -v /nbi:/nbi -p 69:69/udp -p 67:67/udp -p 80:80 -e BSDPY_IP=YourLinuxServerIP --name netboot_server hunty1/bsdpydocker

Now thats a lot of commands, so lets break it down:

Docker Run

~]# docker run --restart=always -d

Basically the above is saying go ahead and run a docker image, if the container exits, like if the linux host was powered off. Then the next time that docker loads (which will be at system startup), it will try to restart this container. The -d flag means run in daemonized mode rather than interactive. This way it runs in the background and doesn’t require any user input or intervention. Just how a service should run


-v /nbi:/nbi

The -v flag means volumes, what we are doing here is that we are telling docker to map the directory /nbi into /nbi of the container. This allows our container to have access to /nbi and thus our NetBoot image. Think of it like a shared folder between the host and the container.


-p 69:69/udp -p 67:67/udp -p 80:80

The -p flag here just maps the ports from the Linux host to the BSDPy container. What we are doing here is basically forwarding all the UDP traffic on ports 69 and 67 from the linux host to our container. We are also forwarding UDP and TCP traffic on port 80 from the linux host to the container. Port 69 is for TFTP and Port 67 is for DHCP and Port 80 is HTTP which is how the client will be netbooting.

Environmental Variables

-e BSDPY_IP=YourLinuxServerIP

The -e flag here is passing an environmental variable to our container. The variable is DOCKER_BSDPY_IP Essentially we need to tell our container what the IP address is of our linux host is so make sure this is set correctly. ie.


Name of Container

--name netboot_server hunty1/bsdpydocker

The –name flag here allows us to give a name to this running container, you can call it what ever you like. I like to use the function or service the container is providing as the name as it makes it easy to see at a glance what my Linux host is providing. So in the above example I have the name set to netboot_server.

After the name we have hunty1/bsdpydocker this is a reference to the docker image that we pulled down from the Docker public registry earlier. This is the name of the image that we are telling Docker to run and create a container for.

So now run the command and it should come back with the UUID of the Container

Screen Shot 2015-04-24 at 2.22.03 pm

Kind of uninteresting. So how do we see whats happening? Lets see what containers are running on the server:

~]# docker ps -a

Screen Shot 2015-04-24 at 2.22.03 pm

So we can see that the netboot_server container is up and running. To see some logs from the container we can run:

~]# docker logs -f netboot_server

This is kind of like running a tail -f, it gives you the last 10 or so lines of the log file and will live update so you can see events in the log as they happen.

Screen Shot 2015-04-24 at 2.25.54 pm

We now have a fully operational NetBoot Server!

You might be wondering great but how do I get it to server a NetBoot.nbi file that I have created? Well there are plenty of ways, we could scp it across, or, a little bit more of a friendly approach is to install Samba, and access the /nbi directory we created earlier via SMB from your Mac.

So lets do that. To exit out of the log view if you are still in it, hit control-c

Installing samba:

~]# yum -y install samba samba-client

Now we need to setup a user account to authenticate to our samba share. I’m going to call my user ‘smbuser’

~]# useradd smbuser

Now we set the password

~]# smbpasswd -a smbuser

Now lets setup samba to share out the nbi directory. First backup the smb.conf file

~]# mv /etc/samba/smb.conf /etc/samba/smb.conf.backup

Now create a new smb.conf file

~]# nano /etc/samba/smb.conf

And ensure it has the following content:

## Minimal SMB Conf file for CentOS 7
workgroup = MYGROUP
server string = Samba Server Version %v
log file = /var/log/samba/log.%m
max log size = 50
security = user
passdb backend = tdbsam
local master = no
create mask = 0744
force create mode = 0744
directory mask = 0755
force directory mode =0755
inherit permissions = yes

#============================ Share Definitions ==============================

path = /nbi
available = yes
read only = no
browseable = yes
public = no
writable = yes

We can now enable the samba service and fire it up:

~]# systemctl start smb
~]# systemctl start nmb
~]# nmbsystemctl enable smb
~]# systemctl enable nmb

You will need to give your smbuser permissions to the nbi folder, so run

~]# chown smbuser /nbi

Drop your NetBoot.nbi into this share.

Screen Shot 2015-04-24 at 3.37.44 pm

Now once it has finished copying over. Go ahead and restart you docker container

~]# docker restart netboot_server

And to check that it has picked up the new netboot image:

~]# docker logs -f netboot_server
-=- Starting new BSDP server session -=-
04/24/2015 03:45:58 PM - DEBUG: Considering NBI source at /nbi/DEC_NetBoot_14D131_v1.nbi
04/24/2015 03:45:58 PM - DEBUG: [========= Using the following boot images =========]
04/24/2015 03:45:58 PM - DEBUG: /nbi/DEC_NetBoot_14D131_v1.nbi
04/24/2015 03:45:58 PM - DEBUG: [=========     End boot image listing      =========]

Go ahead and try to netboot a client device and you should be away!

Congratulations you now have a NetBoot server running in a Docker container on Linux!

Now for bonus points here is a couple of scripts to get you up and running super fast.

Script 1.

This will disable the firewall and SELinux and prompt you to reboot.

Script 2.

This will set everything else up for you. Once complete just upload the netboot image to your server and reboot the linux server (Or just restart the docker container, so it finds the new nbi)



  1. Estimated very good contribution.

    I followed exactly. In System Preferences you can see the network drive (Net Install), can even click to boot from the network drive, but when reboot fails to load the network disk.

    I tried booting pressing the Alt / Option button but still no network disk is shown.

    I tried to boot from the disk into the Recovery but do not see the network drive.

    I think the error occurs only when the iMac does not have APIPA IP that is so.

    Maybe they can correct this fault would help me or what I suggest



  2. I am getting the following error (by the way, I am using DOCKER_BSDPY_IP rather than BSDPY_IP, does that matter because your screenshots are different from your web page):

    docker run –restart=always -d -v /nbi:/nbi -p 69:69/udp -p 67:67/udp -p 80:80 -e DOCKER_BSDPY_IP= –name netboot_server hunty1/bsdpydocker

    Usage of loopback devices is strongly discouraged for production use. Either use `–storage-opt dm.thinpooldev` or use `–storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning.


  3. This method works well but I was wondering…. we use the Casper Mac Management system – so do I still need to add the netboot server to Casper itself (in Casper -> Computer Management -> Netboot Servers). I assume I don’t because we are using a different method to the NetSUS Jamf appliance so that entry is not required. Would that be correct?


    1. It’s up to you. If you use that feature of Casper then yes you can add your netboot server in there. The type of netboot server is irrelevant, it could be NetSUS, OS X Server or BSDPy. A NetBoot server is a NetBoot server


  4. Okay but what would adding the BSDPy to my Casper Mac Management system achieve? What would it do for us as a company? If there is no real benefit then I won’t bother. Thanks.


    1. Perhaps read up on the Casper documentation to decide if its a feature that provides value to you. Again BSDPy is just a netboot server, its function is exactly the same as the netboot service provided by OS X Server or NetSUS

      Liked by 1 person

  5. Thanks for this. Was trying on CentOS 6 bare metal, could not get it working. Moved to CentOS 7,Took 10 minutes following these steps have been up and testing with no issues for past 4 days..awesome


  6. Hi,
    I did this on CentOS 7 and I can see the NBI on the log but when it tries to serve them I see this:

    08/18/2017 12:28:41 PM – DEBUG: Return ACK[SELECT] to a8:20:66:21:55:6 – on port 68
    08/18/2017 12:28:41 PM – DEBUG: –> TFTP URI: tftp://
    08/18/2017 12:28:41 PM – DEBUG: –> Boot Image URI:

    I get no boot image URI and doesnt work

    here what it serves

    08/18/2017 12:26:21 PM – DEBUG: ——- Start Docker env vars ——-
    08/18/2017 12:26:21 PM – DEBUG: BSDPY_IFACE: eth0
    08/18/2017 12:26:21 PM – DEBUG: BSDPY_PROTO: http
    08/18/2017 12:26:21 PM – DEBUG: BSDPY_IP:
    08/18/2017 12:26:21 PM – DEBUG: ——- End Docker env vars ——-
    08/18/2017 12:26:21 PM – DEBUG: tftprootpath is /nbi
    08/18/2017 12:26:21 PM – INFO: Server priority: [52, 14]
    08/18/2017 12:26:21 PM – DEBUG: Found $BSDPY_IP – using custom external IP
    08/18/2017 12:26:21 PM – DEBUG: Using HTTP basedmgpath
    08/18/2017 12:26:21 PM – INFO: Server IP:
    08/18/2017 12:26:21 PM – INFO: Server FQDN:
    08/18/2017 12:26:21 PM – INFO: Serving on eth0
    08/18/2017 12:26:21 PM – INFO: Using http to serve boot image
    08/18/2017 12:26:21 PM – DEBUG:
    -=- Starting new BSDP server session -=-
    08/18/2017 12:26:21 PM – DEBUG: [========= Updating boot images list =========]
    08/18/2017 12:26:21 PM – DEBUG: Considering NBI source at /nbi/Casper93.nbi
    08/18/2017 12:26:21 PM – DEBUG: Considering NBI source at /nbi/Netboot02062014.nbi
    08/18/2017 12:26:21 PM – DEBUG: Considering NBI source at /nbi/Netboot_9.3.1_Retina.nbi
    08/18/2017 12:26:21 PM – DEBUG: Considering NBI source at /nbi/LAR-iMAC-10.8.nbi




    1. try stopping and restarting the netboot container or even the entire server.
      Also how old are the machines you are trying to boot? Try using the option key to bring up the boot picker and select the NBI from there, rather than use the N key at startup.
      I’ve found that quite old machines ie pre 2010 machines have some issues with netbooting when there are multiple netboot images available and actually cause this problem you are seeing on the netboot server


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s