Cobbler (v3.3.7) Ubuntu Deployment Guide

Posted by Sus-Admin on Monday, April 07, 2025

This guide assumes that you have a Fedora 34 server or workstation system configured to run Cobbler v3.3.7 similarly to the Cobbler v3.3.6 Beginner’s guide.

Table of Contents

  1. Objective
    1. Caveats
  2. Cobbler Server Prep
    1. Dependencies
  3. Ubuntu 20.04 PXE Deployment
  4. Ubuntu 22.04 PXE Deployment
  5. Ubuntu 24.04 PXE Deployment
  6. Tips & Troubleshooting

Objective

Starting where the Beginner’s guide left off, further configure the Cobbler v3.3.7 server to deploy the latest 3 releases of Ubuntu Server LTS (Ubuntu 20.04, 22.04, 24.04) via PXE network boot, using the same system and network environment. This guide assumes that you still have selinux and firewalld configured and enabled as described in the Beginner’s guide.

Caveats

  • starting with Ubuntu 20.04, Canonical switched to using their in-house cloud-init autoinstall solution, which Cobbler 3.3.7 does not support natively, requiring a few advanced configurations.

    • Ubuntu did offer compatability/support with the Debian’s preseed autoinstallation model in the Ubuntu 20.04 Legacy release, but this guide only provides procedures for deploying Ubuntu systems using cloud-init.
  • Despite my efforts (and unlike the Beginner’s Guide) Ubuntu 20.04 PXE clients will require an internet connection at the time of installation, since the fallback: offline-install option is not available in that version’s cloud-init implementation and was only introduced as of Ubuntu 22.04 release..

    • Also unlike my other guides, this PXE deployment will use the installation media (ISO file) instead of a repo mirror when installing the target OS (except for Ubuntu 20.04, however it still requires to use the ISO file in PXE process, so it’s very similar and consistent), so even though the distribution will be imported as usual, it’s important to make the ISO file available over HTTP as well.

Cobbler Server Prep

Cobbler v3.3.7 does not come with a sample template for the cloud-init autoinstall files, so create those before getting started, as well as some Cobbler sync-triggers to correct the bootloader configurations for compatability with cloud-init.

Dependencies

Create the new Cobbler template and snippets necessary to generate the cloud-init autoinstall config file by copying the 3 text blocks below to new files with the name and path noted above each text block:

  • /var/lib/cobbler/templates/cloud-init_user-data

    #cloud-config
    autoinstall:
      version: 1
      apt:
        preserve_sources_list: true
        primary:
        - arches: [amd64, i386]
          uri: http://$http_server/cblr/links/$distro
    ##      uri: http://us.archive.ubuntu.com/ubuntu
        - arches: [default]
    ##      uri: http://$http_server/cblr/links/$distro
          uri: http://ports.ubuntu.com/ubuntu-ports
        fallback: offline-install
      identity:
    $SNIPPET('cloud-init_hostname')
        password: $default_password_crypted
        realname: ubuntu
        username: ubuntu
      kernel:
        package: linux-generic
      keyboard:
        layout: us
        toggle: null
        variant: ''
      locale: en_US.UTF-8
    $SNIPPET('cloud-init_network')
      ssh:
        allow-pw: true
        install-server: true
      storage:
        layout:
          name: lvm
          sizing-policy: all
      package_update: false
      package_upgrade: false
      late-commands:
    ## Figure out if we're automating OS installation for a system or a profile
    #if $getVar('system_name','') != ''
    #set $what = "system"
    #else
    #set $what = "profile"
    #end if
        - wget -O /target/tmp/autoinstall-user-data.yaml http://$http_server/cblr/svc/op/autoinstall/$what/$name
        - chroot /target /bin/bash -s ssh-keygen -t rsa -b 2048 -m ssh2 -N "" -f /root/.ssh/id_rsa
    
  • /var/lib/cobbler/snippets/cloud-init_hostname

    #if $getVar("system_name","") != ""
        #if $hostname != ""
        hostname: $hostname
        #else
        #set $myhostname = $getVar('name','').replace("_","-")
        hostname: $myhostname
        #end if
    #else
    ## profile based install so just provide one interface for starters
    #set $myhostname = $getVar('hostname',$getVar('name','cobbler')).replace("_","-")
        hostname: $myhostname
    #end if
    
  • /var/lib/cobbler/snippets/cloud-init_network

    #if $getVar("system_name","") != ""
      network:
        ethernets:
        #set ikeys = $interfaces.keys()
        #import re
        #for $iname in $ikeys
            #set $idata = $interfaces[$iname]
            ## Ignore BMC interface
            #if $idata["interface_type"].lower() == "bmc"
                #continue
            #end if
        #end for
        #for $iname in $ikeys
            #set $idata    = $interfaces[$iname]
            #set $mac      = $idata["mac_address"]
            #set $static   = $idata["static"]
            #set $ip       = $idata["ip_address"]
            #set $netmask  = $idata["netmask"]
            #set $type     = $idata["interface_type"]
            ## Ignore BMC interface
            #if $type == "bmc"
                #continue
            #end if
          $iname:
            match:
              macaddress: $mac
            #if $static == True:
                #if $ip != "":
                    #if $netmask != "":
                        #set $mask = sum([bin(int(x)).count('1') for x in $netmask.split('.')])
            dhcp4: false
            addresses:
              - $ip/$mask
                    #else
            dhcp4: false
            addresses:
              - $ip/24
                    #end if
                    #if $gateway != "":
            gateway4: $gateway
                    #end if
                    #if $name_servers and $name_servers[0] != "":
            nameservers:
              addresses:
                        #for $dns in $name_servers
                - $dns
                        #end for
                    #end if
                #else
            dhcp4: true
                #end if
            #else
            dhcp4: true
            #end if
        #end for
        version: 2
    #else
    ## profile based install so use DHCP
      network:
        ethernets: 
          eth0:
            dhcp4: true
        version: 2
    #end if
    

The above section should resemble the standard netplan YAML configuration file for Ubuntu once generated.

Assumptions: For automated Cobbler System deployments (not Profiles…), each system interface defined should have the corresponding MAC address defined (a standard requirement in Cobbler). Less intuitively, this solution only adds DNS servers to static interfaces with an IP address defined, since DNS servers are set per-system in Cobbler, but per-interface in Ubuntu cloud-init/netplan; the above snippet will revert any interface to DHCP if it is set to static but has no IP defined.

Create 2 Cobbler sync-triggers to correct the GRUB and PXELINUX boot configurations to support Ubuntu cloud-init installations, which will run each time the cobbler sync action is performed:

  • /var/lib/cobbler/triggers/sync/post/fix-ubuntu-profiles-GRUB_PXE.sh

    #!/bin/bash 
    for PROFILE in $(cobbler profile list); do
        DIST=$(cobbler profile report --name $PROFILE | grep ^Distribution | awk {' print $3 '});
        VER=$(cobbler distro report --name $DIST | grep "OS Version" | awk {' print $4 '});
        [[ ($VER == "focal" || $VER == "jammy" || $VER == "noble") ]] || continue;
        sed -i "s,auto-install/enable=true priority=critical netcfg/choose_interface=auto url=http://10.0.0.10/cblr/svc/op/autoinstall/profile/${PROFILE} hostname=.* domain=local.lan suite=${VER},," /var/lib/tftpboot/grub/x86_64_menu_items.cfg;
        sed -i "s,auto-install/enable=true priority=critical netcfg/choose_interface=auto url=http://10.0.0.10/cblr/svc/op/autoinstall/profile/${PROFILE} hostname=.* domain=local.lan suite=${VER},," /var/lib/tftpboot/pxelinux.cfg/default;
        DIST="" && VER="";
    done
    
  • /var/lib/cobbler/triggers/sync/post/fix-ubuntu-systems-GRUB_PXE.sh

    #!/bin/bash 
    for SYSTEM in $(cobbler system list); do
        PROFILE=$(cobbler system report --name $SYSTEM | grep ^Profile | awk {' print $3 '})
        DIST=$(cobbler profile report --name $PROFILE | grep ^Distribution | awk {' print $3 '});
        VER=$(cobbler distro report --name $DIST | grep "OS Version" | awk {' print $4 '});
        [[ ($VER == "focal" || $VER == "jammy" || $VER == "noble") ]] || continue;
        MAC=$(cobbler system report --name $SYSTEM | grep "MAC Addr" | awk {' print $4 '})
        sed -i "s,auto-install/enable=true priority=critical netcfg/choose_interface=auto url=http://10.0.0.10/cblr/svc/op/autoinstall/system/${SYSTEM} hostname=.* domain=local.lan suite=${VER},," /var/lib/tftpboot/grub/system/$MAC;
        MAC=$(echo $MAC | sed 's,:,-,g');
        sed -i "s,auto-install/enable=true priority=critical netcfg/choose_interface=auto url=http://10.0.0.10/cblr/svc/op/autoinstall/profile/${PROFILE} hostname=.* domain=local.lan suite=${VER},," /var/lib/tftpboot/pxelinux.cfg/01-$MAC;
    	PROFILE="" && DIST="" && VER="" && MAC="";
    done
    

Mark the above 2 cobbler sync-triggers as executable

chmod u+x /var/lib/cobbler/triggers/sync/post/fix-ubuntu-profiles-GRUB_PXE.sh
chmod u+x /var/lib/cobbler/triggers/sync/post/fix-ubuntu-systems-GRUB_PXE.sh

More info on cobbler triggers in the Tips & Troubleshooting section below

Download the latest 3 releases of Ubuntu Server LTS

cd ~/Downloads && wget https://releases.ubuntu.com/24.04/ubuntu-24.04.1-live-server-amd64.iso
cd ~/Downloads && wget https://releases.ubuntu.com/22.04/ubuntu-22.04.5-live-server-amd64.iso
cd ~/Downloads && wget https://releases.ubuntu.com/20.04/ubuntu-20.04.6-live-server-amd64.iso

Ubuntu 20.04 PXE Deployment

Mount the Ubuntu 20.04 live server installer and import to Cobbler

[ -d /mnt/Ubuntu] || mkdir /mnt/Ubuntu
mount -t iso9660 -o loop,ro ~/Downloads/ubuntu-20.04.6-live-server-amd64.iso /mnt/Ubuntu
cobbler import --name Ubuntu20 --path /mnt/Ubuntu

Copy the installation media to the public HTTP share (The location of this file will be used in the kernel-options for relavent Cobbler Distros/Profiles/Systems)

mkdir -p /var/www/cobbler/pub/cloud-init/Ubuntu20
cp ~/Downloads/ubuntu-20.04.6-live-server-amd64.iso /var/www/cobbler/pub/cloud-init/Ubuntu20/.

Edit the kernel options for the new Cobbler Distro to install Ubuntu automatically by default:

NAME="Ubuntu20-casper-x86_64" && cobbler distro edit --name $NAME --kernel-options "root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url=http://10.0.0.10/cblr/pub/cloud-init/Ubuntu20/ubuntu-20.04.6-live-server-amd64.iso autoinstall cloud-config-url=http://10.0.0.10/cblr/svc/op/autoinstall/profile/$NAME" && unset NAME

alternatively, use the following kernel-options to install Ubuntu manually via PXE network boot

cobbler distro edit --name Ubuntu20-casper-x86_64 --kernel-options 'root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url=http://10.0.0.10/cblr/pub/cloud-init/Ubuntu20/ubuntu-20.04.6-live-server-amd64.iso cloud-config-url=/dev/null'

More info on these configs in the Tips & Troubleshooting section below.

Since the PXE client will install the OS from the internet, create a new autoinstall (cloud-init) template from the file created above, changing the apt uri.

sed -z 's,      uri: http://$http_server/cblr/links/$distro\n#      uri: http://us.archive.ubuntu.com/ubuntu,#      uri: http://$http_server/cblr/links/$distro\n      uri: http://us.archive.ubuntu.com/ubuntu,' /var/lib/cobbler/templates/cloud-init_user-data | tee /var/lib/cobbler/templates/Ubuntu20_cloud-init_user-data

Then configure it as the autoinstallation template for the Ubuntu 20.04 Cobbler Profile

cobbler profile edit --name Ubuntu20-casper-x86_64 --autoinstall Ubuntu20_cloud-init_user-data

Create a new Cobbler System to install Ubuntu 20.04 automatically based on the system’s (PXE client’s) MAC address, replacing the “aa:bb:cc:dd:ee:ff” with the MAC address of your PXE client, and being sure not to use a duplicate MAC or IP addresse of any other Cobbler System:

NAME="Ubuntu20-auto" && cobbler system add --name $NAME --profile Ubuntu20-casper-x86_64 --kernel-options "root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url=http://10.0.0.10/cblr/pub/cloud-init/Ubuntu20/ubuntu-20.04.6-live-server-amd64.iso autoinstall cloud-config-url=http://10.0.0.10/cblr/svc/op/autoinstall/system/$NAME" --mac-address "aa:bb:cc:dd:ee:ff" --static true --ip-address "10.0.0.20" --netmask "255.255.255.0" --gateway "10.0.0.1" --name-servers "10.0.0.1 1.1.1.1 10.0.0.10" --hostname "Ubuntu20" --netboot-enabled true && unset NAME

Alternatively, configure the Cobbler System kernel-options to run as a manual installation:

cobbler system add --name Ubuntu20 --profile Ubuntu20-casper-x86_64 --kernel-options 'root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url=http://10.0.0.10/cblr/pub/cloud-init/Ubuntu20/ubuntu-20.04.6-live-server-amd64.iso autoinstall cloud-config-url=/dev/null' --mac-address "aa:bb:cc:dd:ee:ff"

Finally, sync up Cobbler, then the PXE Client VM can be powered on and should automatically boot to PXE and install Ubuntu 20.04 to the VM HDD using the “Ubuntu20_cloud-init_user-data” cloud-init template created above.

  • The resulting system will have the root super-user account disabled, and will only be accessible with the ubuntu user specified in the cloud-init config file.
cobbler sync

the PXE Client will not install Ubuntu from the local mirror @ /var/www/cobbler/distro_mirror, and since the fallback: ofline-install option was not available for Ubuntu 20.04 cloud-init, this distro requires an internet connection to install, as detailed in this guide.

Ubuntu 22.04 PXE Deployment

Take similar steps as above to import and automatically deploy Ubuntu 22.04 LTS Server over PXE, using the original cloud-init_user-data autoinstall template created above.

[ -d /mnt/Ubuntu ] || mkdir /mnt/Ubuntu
mount -t iso9660 -o loop,ro /home/fedora/Downloads/ubuntu-22.04.5-live-server-amd64.iso /mnt/Ubuntu
cobbler import --name Ubuntu22 --path /mnt/Ubuntu

mkdir -p /var/www/cobbler/pub/cloud-init/Ubuntu22
cp ~/Downloads/ubuntu-22.04.5-live-server-amd64.iso /var/www/cobbler/pub/cloud-init/Ubuntu22/.

cobbler distro edit --name Ubuntu22-casper-x86_64 --kernel-options 'root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url=http://10.0.0.10/cblr/pub/cloud-init/Ubuntu22/ubuntu-22.04.5-live-server-amd64.iso autoinstall cloud-config-url=http://10.0.0.10/cblr/svc/op/autoinstall/profile/Ubuntu22-casper-x86_64'

cobbler profile edit --name Ubuntu22-casper-x86_64 --autoinstall cloud-init_user-data

NAME="Ubuntu22-auto" && cobbler system add --name $NAME --profile Ubuntu22-casper-x86_64 --kernel-options "root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url=http://10.0.0.10/cblr/pub/cloud-init/Ubuntu22/ubuntu-22.04.5-live-server-amd64.iso autoinstall cloud-config-url=http://10.0.0.10/cblr/svc/op/autoinstall/system/$NAME" --mac-address "aa:bb:cc:dd:ee:ff" --static true --ip-address "10.0.0.22" --netmask "255.255.255.0" --gateway "10.0.0.1" --name-servers "10.0.0.1 1.1.1.1 10.0.0.10" --hostname "Ubuntu22" --netboot-enabled true && NAME=""

cobbler sync

Again, the PXE Client is not installing via the local repo @ /var/www/cobbler/distro_mirror, but now that the fallback: offline-install option is available with Ubuntu 22.04 cloud-init, the installer will NOT require and internet connection to install, instead installing using the live server installer (.iso file) available on Cobbler’s public HTTP share and specified in the kernel options.

Ubuntu 24.04 PXE Deployment

First, modify /var/lib/cobbler/distro_signatures.json to suppport Ubuntu 24.04 (which is not included with Cobbler at the time of writing) by pasting the following code block immediately following the Ubuntu 22 jammy signature definition:

      "noble": {
        "signatures": [
          "dists",
          ".disk"
        ],
        "version_file": "Release|info",
        "version_file_regex": "Suite: noble|Ubuntu 24.04",
        "kernel_arch": "linux-headers-(.*)\\.deb",
        "kernel_arch_regex": null,
        "supported_arches": [
          "i386",
          "amd64"
        ],
        "supported_repo_breeds": [
          "apt"
        ],
        "kernel_file": "(linux|vmlinuz(.*))",
        "initrd_file": "initrd($|.gz$|.lz$)",
        "isolinux_ok": false,
        "default_autoinstall": "",
        "kernel_options": "",
        "kernel_options_post": "",
        "template_files": "",
        "boot_files": [],
        "boot_loaders": {}
      },

With this modification made, be careful not to use the cobbler signature update command on the Cobbler server, which will remove any user-defined signatures.

Sync up Cobbler in order to apply the changes

cobbler sync

Take similar steps as above to import and automatically deploy Ubuntu 24.04 LTS Server over PXE

[ -d /mnt/Ubuntu ] || mkdir /mnt/Ubuntu
mount -t iso9660 -o loop,ro /home/fedora/Downloads/ubuntu-24.04.1-live-server-amd64.iso /mnt/Ubuntu
cobbler import --name Ubuntu24 --path /mnt/Ubuntu

mkdir -p /var/www/cobbler/pub/cloud-init/Ubuntu24
cp ~/Downloads/ubuntu-24.04.1-live-server-amd64.iso /var/www/cobbler/pub/cloud-init/Ubuntu24/.

cobbler distro edit --name Ubuntu24-casper-x86_64 --kernel-options 'root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url=http://10.0.0.10/cblr/pub/cloud-init/Ubuntu24/ubuntu-24.04.1-live-server-amd64.iso autoinstall cloud-config-url=http://10.0.0.10/cblr/svc/op/autoinstall/profile/Ubuntu24-casper-x86_64'

cobbler profile edit --name Ubuntu24-casper-x86_64 --autoinstall cloud-init_user-data

NAME="Ubuntu24-auto" && cobbler system add --name $NAME --profile Ubuntu24-casper-x86_64 --kernel-options "root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url=http://10.0.0.10/cblr/pub/cloud-init/Ubuntu24/ubuntu-24.04.1-live-server-amd64.iso autoinstall cloud-config-url=http://10.0.0.10/cblr/svc/op/autoinstall/system/$NAME" --mac-address "aa:bb:cc:dd:ee:ff" --static true --ip-address "10.0.0.24" --netmask "255.255.255.0" --gateway "10.0.0.1" --name-servers "10.0.0.1 1.1.1.1 10.0.0.10" --hostname "Ubuntu24" --netboot-enabled true && NAME=""

cobbler sync

Again, if using the fallback: offline-install option in the cloud-init template for this System, the PXE Client will use the .iso file hosted by Cobbler as the source for installation.

Tips & Troubleshooting

  1. The Cobbler 3.3.6 Beginner’s Guide Tips & Troubleshooting section contains some basic recommendations and limitations of Cobbler which will not be repeated here.

  2. Cobbler triggers

    • Cobbler is normally a dynamic and responsive app that implements many options, parameters, and configurations on-demand through edit|add|remove|etc... actions, not requiring a cobbler sync to commit most changes. However, it is recommended to run cobbler sync after any changes to a Cobbler Distro/Profile/System when using Cobbler sync-triggers in this manner (editing DHCP configs, boot options, etc…), unless you’re absolutely certain otherwise.

    • Cobbler recommends writing triggers as Python modules and has a lot of good info in their docs, but I have only written bash scripts that slowly but surely accomplish my needs.

  3. Troubleshooting the installation

    • The Ubuntu installer will reboot the system automatically upon completing a cloud-init auto-install. To prevent this, append the following line to the end of the autoinstall template (cloud-init_user-data) as the final command in the late-commands: section (be sure the spacing/indentation aligns with the rest of the late-command entries):

        rm /target/etc/apt/apt.conf.d/99needrestart
      
  4. More info on cloud-init

  5. The kernel-options used above were based off of Ubuntu’s official docs

  6. Additional references:


comments powered by Disqus

Related posts in 2025 Apr

Cobbler (v3.3.7) Ubuntu Deployment Guide
Posted on April 07, 2025
Read more