Table of Contents


If you don’t already know, I work at a small Racine County school district in Wisconsin as the sole IT sysadmin. I started there about a year ago, and ever since I’ve been trying to figure out how to make my job easier while providing the necessary equipment to students and staff. One of the biggest things I’ve noticed is students rarely use Windows for anything other than accessing Google Apps via Chrome (and games, but that’s a story for another time). I started thinking to myself how we might be able to better utilize our existing hardware without spending a dime, and that’s when I came up with the idea to install Ubuntu on a limited number of machines. If you want to read on how I think that things like Ubuntu can get students more interested in technology, I’ve created a separate post here.

pxelinux – Messing with WDS’s TFTP PXE server

To start off with what we need to do is get WDS to push out the syslinux derivative pxelinux — a lightweight bootloader designed to be used with PXE booting. If you’re unaware, WDS is basically the Windows installer disc (Windows PE) designed to work over the network plus some PXE-specific bootloaders. For my example I will be adding Ubuntu 13.04 with using Windows Server 2008 R2 as my WDS server.

Hint: I basically just followed the official syslinux wiki:

  1. Download the syslinux package: (I used 4.04. They changed something with 4.06 that I didn’t want to deal with.)
  2. For the sake of this tutorial, just extract the contents of the syslinux package to your desktop in a folder named syslinux. Also to note I will be calling your WDS root folder %wdsroot% in the steps below. Mine is located at C:/RemoteInstall on my server.
  3. Move Desktop/syslinux/core/pxelinux.0 to %wdsroot%/boot/<arch> and rename it to
  4. Move the files Desktop/syslinux/com32/menu/vesamenu.c32 and Desktop/syslinux/com32/modules/chain.c32 to %wdsroot%/boot/<arch>
  5. Create a new folder named pxelinux.cfg in %wdsroot%/boot/<arch>
  6. Create a new file with the contents listed below
    DEFAULT vesamenu.c32
     PROMPT 0
     # Timeout in units of 1/10 s
     TIMEOUT 300
     MENU ROWS 16
     MENU COLOR BORDER 30;44 #20ffffff #00000000 none
     MENU COLOR SCROLLBAR 30;44 #20ffffff #00000000 none
     MENU COLOR TITLE 0 #ffffffff #00000000 none
     MENU COLOR SEL 30;47 #40000000 #20ffffff
     MENU TITLE PXE Boot Menu
     LABEL wds
     MENU LABEL Windows Deployment Services
     KERNEL pxeboot.0
     LABEL local
     MENU LABEL Boot from Harddisk
     Type 0x80
     LABEL ubuntu-thirteen-four
     menu label Ubuntu 13.04 Desktop
     kernel /linux/ubuntu/13.04-desktop/casper/vmlinuz
     APPEND boot=casper netboot=nfs nfsroot=<wds server ip>:/linux/ubuntu/13.04-desktop/ initrd=/linux/ubuntu/13.04-desktop/casper/initrd.lz quiet splash
  7. Make a copy of pxeboot.n12 and name it pxeboot.0
  8. Create a directory tree called linux/ubuntu/13.04-desktop under %wdsroot%/boot/<arch>
  9. Now we want to extract the contents of the Ubuntu 13.04 Desktop CD to the 13.04-desktop folder we created. I usually just mount the ISO and copy the files over
  10. We need to tell the WDS server that we want to boot our clients to pxelinux instead of WDS via the PXE server. Type these commands in command prompt with elevated privileges: (For x64, change x86 to x64)
    wdsutil /set-server / /architecture:x86
    wdsutil /set-server / /architecture:x86
  11. Now we need to enable Services for NFS on our WDS server. Any Windows sysadmin should know how to do this so I won’t really cover it. I shared the “linux” folder found under %wdsroot%/boot/<arch> with guest access allowed. Might want to test this before you try booting off PXE.

That should be it. Usually I like the idea of restarting the WDS service and then just verifying all of my options and make sure my files are in the correct place. Now you can PXE boot your client. Hopefully instead of the normal WDS bootloader you now get a bootloader with a gray background. Choose the Ubuntu option, give it a couple minutes, and then you should see the Ubuntu live desktop!

Active Directory Authentication

I may end up revising this section due to the fact that right now I am using likewise-open for AD auth but it works. Grab yourself an install of Ubuntu and follow along:

  1. Open up Terminal
  2. Install Likewise Open and our OpenSSH server for testing
    sudo apt-get install likewise-open openssh-server
  3. Join our domain substituting “” for the FQDN of your AD domain and “domainadmin” for an AD user that has privileges to join computers to the domain (note: likewise-open will bind to your domain using the hostname. Configure this first if you need to)
    sudo domainjoin-cli join domainadmin
  4. Input the password for the user you specified
  5. Woot! Your computer is now joined to the domain. Check your domain to confirm that AD sees the computer.
  6. If you were to test authentication right now, it won’t work unless you do insert the domain before the username (ADadmin) so let’s fix that:
    sudo lwconfig AssumeDefaultDomain true
  7. Reboot the machine
  8. Test AD auth. Open up an SSH client on another machine and try logging into your Ubuntu client using AD credentials
  9. If #8 worked you’re good to go. If you notice, however, if you try logging in on the Ubuntu client, you only have the options of logging in via your local user(s), guest, or remote login. Run the commands below and then reboot to fix this:
    echo "greeter-hide-users=true" | sudo tee -a /etc/lightdm/lightdm.conf
    echo "allow-guest=false" | sudo tee -a /etc/lightdm/lightdm.conf
    echo "greeter-show-remote-login=false" | sudo tee -a /etc/lightdm/lightdm.conf
  10. Try logging in again via the login GUI

Using preseed to automate Ubuntu installs

This was the section I had the most issues with. Documentation is thin, and usually in engineer-ese. Just follow the steps below and if you want to know anything, feel free to leave a comment.

I guess I should kick off by saying what preseed is. When you preseed you basically create a configuration file that answers questions that you are asked during the install of modern Debian Linux distros. You can do things such as specify partitioning settings, locale, keyboard layout, and packages that you may want to install along the way. You can also run scripts which we will be doing in the last section. If you want to check out what a preseed file may look like, scroll down a bit or check out the one from 12.04’s documentation.

  1. Since we’ll be loading our preseed file from http, we need an http server. I like Apache. Many places use Apache for other purposes too. If you want to use a current Apache server, please please please restrict it only to the network you will be preseeding on. If you do not have an Apache server already, you will need a machine running Ubuntu Server. Straight Debian will work too.
    sudo apt-get install apache2
  2. Just for good measure, under the root of your Apache site (usually /var/www) make a directory named preseed
  3. Create a new file named ubuntu.seed and type the following lines in it:
    d-i mirror/country string US
    d-i mirror/http/hostname string
    d-i mirror/http/directory string /debian# Install the Ubuntu desktop.
    tasksel tasksel/first multiselect ubuntu-desktop
    ubiquity ubiquity/keep-installed string icedtea6-plugin Localization
    d-i debian-installer/locale string en_US
    # Keyboard
    d-i keyboard-configuration/layoutcode string us
    # Networking
    d-i netcfg/choose_interface select auto
    d-i hw-detect/load_firmware boolean true
    d-i netcfg/get_hostname string
    d-i apt-setup/services-select multiselect security, volatile
    # Time
    d-i clock-setup/utc boolean false
    d-i time/zone string US/Central
    d-i clock-setup/ntp boolean true
    # Root Account
    d-i passwd/root-password password rootpassword
    d-i passwd/root-password-again password rootpassword
    # Local Account
    d-i passwd/user-fullname string Local Admin
    d-i passwd/username string localadmin
    d-i passwd/user-password password localadminpass
    d-i passwd/user-password-again password localadminpass
    d-i user-setup/encrypt-home boolean false
    # Packages
    d-i pkgsel/include string openssh-server vim likewise-open curl
    # Finishing
    d-i finish-install/reboot_in_progress note
    d-i cdrom-detet/eject boolean false
  • Make sure you change the account information in the file to something to your liking
  • Remember that file name default under %wdsroot%/boot/<arch>/pxelinux.cfg? Open that up again and append the following to the bottom:
    LABEL ubuntu-thirteen-four-preseed
    menu label Ubuntu 13.04 Desktop - Preseed
    kernel /linux/ubuntu/13.04-desktop/ubuntu-installer/i386/linux
    APPEND boot=casper preseed/url=http://<apache server ip>/preseed/ubuntu.seed install auto-install/enable=true netboot=nfs nfsroot=<wds server ip>:/linux/ubuntu/13.04-desktop/ initrd=/linux/ubuntu/13.04-desktop/ubuntu-installer/i386/initrd.gz
  • We need to change the installer for Ubuntu. The default live installer doesn’t work for preseed well. Luckily Canonical is there to help us out. You’ll need to download the Ubuntu Netboot Installer archive. If you are using 13.04 and x86 I’ve linked it here.
  • Extract the folder ubuntu-installer located in the archive to %wdsroot%/boot/<arch>/linux/ubuntu/13.04-desktop/
  • That’s it!


Hopefully now if you PXE boot again you will have the option for preseeding at the bottom. Try it out on a machine and see how the install goes. If it’s all good, we’ll move onto the next part for setting up a cache to speed up the install process.

Setting up an APT cache

So anyone that’s installed packages before on Debian with a slow connection knows how long it can take. Multiply that by X number of machines you want to deploy and it can add up fast. Hell, even the Ubuntu installer loads tons of packages from the internet. We can cut the install time in half just by setting up a package cache.

If you’ve installed Ubuntu before and paid attention to how many packages it downloads, you probably know how much this will help. I noticed after setting up the cache I was able to eliminate around 650MB of package downloading from the internet. That’s a nice big number.

To set up the cache we will be utilizing apt-cacher-ng:

  1. Install apt-cacher-ng on your Ubuntu server
    sudo apt-get install apt-cacher-ng
    sudo apt-get update
  2. Reboot just for fun.
  3. That’s it. No, really. All we need to do now is configure our client
  4. Since we’ve already done preseed, we can modify our ubuntu.seed file to use our cacher as a proxy. Find the following lines:
    d-i mirror/country string US
    d-i mirror/http/hostname string
    d-i mirror/http/directory string /debian

    Insert this line under that section:
    d-i mirror/http/proxy string http://<cache server ip>:3142/

  5. Done!

To test you will have to run the installer at least twice. Once for downloading the initial packages, a second time for doing an install via the cache. Time both of them too! I went from a 10 minute install on the non-cached install to less than 5 minutes on the cached install!

Tying it all together

Okay, so far we’ve got our PXE server set up to boot Ubuntu Live and our Ubuntu preseeded installer. We’ve seen how we can join a machine to AD with working authentication. And finally we have our apt cache set up to save us precious amounts of time. The final step then is to tie everything together so when we want to install Ubuntu our steps will look like this:

  1. PXE boot the client, choose the preseed installer option
  2. Input a couple of important fields we don’t want to skip (hostname and partitioning)
  3. Wait for the base system to install
  4. Install some packages that we want
  5. When the installer is done, the machine will reboot automatically
  6. Run some scripts on the first start up so we can join our AD domain and customize the login screen, along with setting up our apt cache as a proxy on our client

Alright, it’s getting late (3:30AM) so let’s wrap this up:

  1. Modify your ubuntu.seed file again and throw this at the bottom:
    d-i preseed/late_command string sed -i '/exit 0/ d' /target/etc/rc.local; echo "sh /home/" >> /target/etc/rc.local; echo "exit 0" >> /target/etc/rc.local; wget -O - >> /target/home/
    All this does is grab our script file from our web server and modifies rc.local on our install so it will run on the first boot. The script will run once because it will delete itself.
  2. On your Apache server in the preseed directory make another directory called scripts
  3. Put these lines into a file named
    cd /tmp
    # Cache Repo
    echo "Acquire::http::Proxy "http://<apt cache ip>:3142";" | tee /etc/apt/apt.conf.d/90-apt-proxy.conf
    # Google Repo
    # I added this in case anyone wanted to install Google Chrome automatically.
    # If you don't want this remove the next 4 lines and "google-chrome-stable" below
    wget -q -O - | sudo apt-key add -
    echo "deb stable main" | sudo tee /etc/apt/sources.list.d/google.list | tee /etc/apt/sources.list.d/google.list
    apt-get update
    # Install some packages we want
    apt-get -y install google-chrome-stable vlc
    # Network Interfaces
    # On some machines Ubuntu will just refuse to use DHCP on our NIC. We'll change that.
    rm /etc/network/interfaces
    touch /etc/network/interfaces
    echo "auto lo" | tee -a /etc/network/interfaces
    echo "iface lo inet loopback" | tee -a /etc/network/interfaces
    echo "auto eth0" | tee -a /etc/network/interfaces
    echo "iface eth0 inet dhcp" | tee -a /etc/network/interfaces
    # Join to AD
    apt-get -y install likewise-open
    domainjoin-cli join <domainadmin> <password>
    lwconfig AssumeDefaultDomain true
    # Change login screen settings
    echo "greeter-hide-users=true" | tee -a /etc/lightdm/lightdm.conf
    echo "allow-guest=false" | tee -a /etc/lightdm/lightdm.conf
    echo "greeter-show-remote-login=false" | tee -a /etc/lightdm/lightdm.conf
    sed -i '/sh /home/ d' /etc/rc.local
    rm /home/
    shutdown -r now
  • That’s it! Preseed will grab that script from your Apache server on each install and run it on the first boot. The script will auto delete itself and will reboot the computer when it is done running.


I think that’s it for now. It should cover pretty much everything. I’m going to hit publish on this post, but I’ll be back around for cleaning it up a bit.

Join the Conversation


    1. Sure, as far as I know apt-mirror will literally mirror the entire repo thus consuming more disk space. apt-cacher-ng will basically download on a need-to-install basis or rather it will only download a package if a client requests it and it doesn’t have the same package/version already in the cache.

  1. Mr. Hartl
    Does this attempt succeeds using windows server 2012?
    What are the possible changes if used the 2012?

    1. Honestly, I couldn’t really tell you as I don’t run in a 2012 environment. I imagine it’s roughly the same.

      1. Dear, good night!
        We try to carry out the process in Windows Server 2012, but we are faced with some details not addressed, such as the fact that we have to do the same setup for X86 and X64 folders.
        The biggest problems occurred when we were testing the operation of the solution, because we were stuck to the following message:
        BusyBox v1.20.2 (Ubuntu 1:1.20.0-8ubuntu1) built-in shell (ash)
        Enter ‘help’ for a list of buikt-in commands.
        Have you ever experienced this? Thank you for your contribution to this tutorial.

        1. In Server 2008 R2 you have to do both x86 and x64, but you can skip it if you force 64 bit clients to grab the x86 pxe boot binary. As far as where you were stuck, this comment is quite a bit later, but it seems like you may need to check your boot options for Ubuntu. It doesn’t sound like it’s loading the live FS. The only good advice I can give is check your paths!

          1. Hey guys,
            This is an awesome tutorial, Thank You Pat. I had my server setup from the syslinux wiki, but wanted a live Ubuntu as well. The way to fix the issue with ending up at the BusyBox prompt (initramfs) is to add the NTFS permission “ANONYMOUS LOGON” to your shared “linux” folder. The “Everyone” group will not work, it must be ANONYMOUS LOGON. This worked for me with Windows Server 2012 R2.

            Thank you again!

  2. This guide was extremely helpful to me! I don’t know if you would know why, but I originally tried using this guide with Ubuntu 12.04 LTS rather than 13.04, and Ubuntu wasn’t booting up – I guess it was trying to mount it in /cdrom but it wasn’t liking that? When I used 13.04 instead it decided to work just fine. I just thought it was interesting. Thanks for the guide though!

    1. I ran into that at some point too I think… it has to do with one of the boot options. I wish I could say which one it was, but I failed to document my changes :/

  3. Hi, Pat.
    First of all, I want to tell you big thanks for your article. Very useful guide.
    Could you help me, please? I see the gray menu but nothing changes when I choose “Live Desktop” option and I don’t see any boot notifications. I created NFS-share and I can connect to it from linux machine and view directory content. I’m using syslinux 5.10 with WDS based on Windows 2008 R2 SP1 and Ubuntu Desktop 13.04 x64 as distro which i want to install. I don’t understand what is wrong because when I’m trying netboot distro it works fine.
    Thanks a lot.

    1. If verbose mode isn’t enabled, once you hit enter it should boot up. If you’ve let it sit for a while, something’s obviously wrong. You can change your pxelinux.cfg/default file and remove “quiet splash” from your boot options to enable verbose mode. That may give some insight to what is hanging it up.

  4. Very nice, simple illustration. I tried it with ubuntu-13.04-desktop-i386.iso and the netboot installer using your link. I’m tried this setup from a pxe/tftp/apache configured on a RHEL server.

    It fails at one point asking to choose a mirror as it failed to download some files from the configured apache mirror. In the another terminal, I got an error “Resolver (libc6-udeb): package doesn’t exist.

    Note that, I’ve copied the content of ubuntu-13.04-desktop-i386.iso under /var/www/html/ubuntu

    Please advise what am I missing here

    Thanks in advance


    1. You’ll have to extract the ISO into wherever your PXE server is configured to look at. Unfortunately it won’t take the straight ISO.

  5. Hi Pat,

    Thank you for sharing this really nice and helpful article.

    I followed your steps and configured our Windows server 2012 to serve :
    Darik BAN
    Ubuntu 13

    Problem :
    This configuration works fine for older x86 systems and my virtualbox machines. But on x64 and x86x64 machines, it shows up the default WDS configuration boot screen (without linux).

    Steps :
    I have tried to configure “:\RemoteInstall\Boot\x64” in a similar fashion as “:\RemoteInstall\Boot\x86”

    1) I have copied pxelinux.0, related files and changed “default” accordingly.
    2) Downloaded and copied the amd64 version of the netboot of ubuntu.

    You quoted “In Server 2008 R2 you have to do both x86 and x64, but you can skip it if you force 64 bit clients to grab the x86 pxe boot binary.”

    Can you please elaborate a bit more on that ?

    1. Yeah sure thing. The two wdsutil commands that are run simply just need to be changed so the arch is set to 64 bit, but so that it still points to the x86 directory. This can be done with the commands below
      wdsutil /set-server /bootprogram:boot\x86\ /architecture:x64
      wdsutil /set-server /N12bootprogram:boot\x86\ /architecture:x64

      Try that out. It’s a bit fuzzy since it’s been a while since I set this up, but I think it should work!

Leave a comment

Leave a Reply to pathartl Cancel reply

Your email address will not be published. Required fields are marked *