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.

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
    <code class="EnlighterJSRAW" data-enlighter-language="shell">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)
    <code class="EnlighterJSRAW" data-enlighter-language="shell">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:
    <code class="EnlighterJSRAW" data-enlighter-language="shell">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/

  1. 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.