Oliver Smith
on 3 April 2023
Closing the digital divide with Compudopt and Ubuntu Desktop
Compudopt is a US based organisation with an inspiring mission; to provide technology access and education to under-resourced youth and their communities. This goal speaks to the heart of Ubuntu’s own mission, to bring free software to the widest audience.
When Compudopt reached out to the Ubuntu Desktop and Landscape teams here at Canonical for advice on how to use Ubuntu Desktop to breathe new life into refurbished devices we were excited to help!
In this spotlight, Thijs van de Kamp, National Director of Technical Operations at Compudopt, talks us through how he used a combination of iPXE and Subiquity, the Ubuntu Server installer, to deploy and configure custom desktop images and enroll them in Landscape. He also takes us through some of his specific configurations as a reference for other users looking to do the same.
In Ubuntu 23.04, Subiquity will become the default installer for Ubuntu Desktop, check out the end of this post for more information on this exciting change.
But now, over to Thijs!
About Compudopt
My name is Thijs van de Kamp, and I am the National Director of Technical Operations at Compudopt. Compudopt is a non-profit organisation dedicated to providing technology access and education to under-resourced youth and their communities. Our programs aim to eliminate limited access to computers, facilitate growth in technical and digital literacy skills, help provide no or low cost high-speed internet options, and support the future of youth and their communities. As the National Director of Technical Operations, I am proud to be part of this mission and to help bridge the digital divide for those in need.
Why Ubuntu
We use Ubuntu for the machines that we distribute to the community; it is a robust, free solution that gives an excellent experience to our end-users.
Ubuntu’s security features are one of its biggest benefits as an open-source solution. The operating system’s architecture is designed to prioritise security, with regular updates and patches released to address any vulnerabilities that are discovered. These updates are also available to users free of charge, ensuring that their devices remain secure without any added financial burden.
Furthermore, Ubuntu’s open-source nature means that its security features are constantly being scrutinised and improved by developers all around the world, making it a constantly-evolving and reliable solution for security-conscious individuals.
Overall, Ubuntu’s status as an open-source operating system provides numerous benefits and conveniences, from its cost-effectiveness and user-friendly interface to its security features and continuous development.
These advantages make Ubuntu an excellent choice for Compudopt to provide reliable, affordable, and secure devices to the communities we serve.
The challenge
Compudopt covers multiple locations across the United States, and has provisioned and donated tens of thousands of laptops since it was founded in 2007.
At Compudopt, we strive to ensure that every individual who receives one of our devices has an identical experience, which includes access to comprehensive support.
To achieve this goal, we employ a standardised installation process across multiple sites, which enables our support staff to have a clear understanding of the device’s capabilities. However, creating a consistent installation process poses a significant challenge.
Fortunately, by utilising Subiquity, we can customise the device’s image according to our preferences using a single YAML file.
Additionally, Landscape, a helpful tool for support, enables us to remotely assist device recipients with tasks such as password resets, eliminating the need for them to visit one of our local sites or mail the device to us for support.
One of the major challenges in creating a standardised installation process is ensuring that all necessary drivers are included. Fortunately, Ubuntu’s extensive device support means that the deployment process is quicker and more efficient than other available options.
The solution
At our organisation, each location has a single bare-metal iPXE server that we manually configure to serve installations. However, we plan to streamline this process by using GitHub to ensure that each site has the most up-to-date configuration. Our workbenches are equipped with switches that can deploy software packages, including the Ubuntu installation, from the iPXE server.
To ensure the security and availability of our Landscape data, we currently host it on Google Cloud. One of the most valuable features of this setup is the ability to take snapshots of the VM, which enhances reliability and minimises potential data loss.
iPXE Ubuntu Desktop installation configuration in detail
The deployment we created leverages iPXE and starts from a base Ubuntu Server ISO.
The steps in this guide are designed to accomplish the following:
- Serve a custom package in a PPA to be installed during deployment.
- Install Ubuntu Desktop.
- Set a custom background.
- Create a hidden administrator account for tech support purposes.
- Install applications for the end users.
- Address network issues turning the Server ISO to Desktop installation.
- Use a proxy cache server to minimise the WAN load during installation.
Prerequisites
- tftpd-hpa
- apache2
- squid-deb-proxy
Server Configuration
TFTPD-HPA
We need to make sure that the TFTP server knows where the .ipxe files are located. You can set this in the file located at “/etc/default/tftpd-hpa”. This is where you can point to the folder and set several options, we will give a quick explanation of the options we used.
TFTP_OPTIONS
-c
,allow for new files to be created.
--secure
, change root directory on startup. This means the remote host does not need to pass along the directory as part of the transfer, and increases security
--listen
, run the server in standalone (listen) mode, rather than run from inetd. In listen mode, the `–timeout` option is ignored, and the `–address` option can be used to specify a specific local address or port to listen to.
-v
, increase the logging verbosity of tftpd. This flag can be specified multiple times for even higher verbosity
The live version of our tftpd-hpa looks like this:
# /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/pxe-boot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="-c --secure --listen -v"
OPTIONS="-l -s -r"
Apache2
During the installation we use a web server, for our purposes we chose Apache2. The file that needs to be modified is “/etc/apache2/sites-available/000-default.conf”.
Apache2 Options
, this can be any directory, we choose to host the files in the same folder for a few different reasons.DocumentRoot /pxe-boot
, this is to make sure we have full access to the files during installation.Require all granted
<VirtualHost *:80>
# ServerAdmin [email protected]
DocumentRoot /pxe-boot
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<Directory />
Options +FollowSymLinks +Indexes
Require all granted
</Directory>
Squid-deb-proxy
We are using squid-deb-proxy to cache all the packages that we install, this is to make sure we do not have a WAN bottleneck and in case we lose our connection we can still complete our deployments. The files we need to modify are located at “/etc/squid-deb-proxy/squid-deb-proxy.conf”, we also need to create a file at “/etc/squid-deb-proxy/mirror-dstdomain.acl.d/10-default”.
The file squid-deb-proxy.conf is a large file, we have included the important parts below:
# allow access only to official archive mirrors
# uncomment the third and fouth line to permit any unlisted domain
#http_access deny !to_archive_mirrors
#http_access allow !to_archive_mirrors
# don't cache domains not listed in the mirrors file
# uncomment the third and fourth line to cache any unlisted domains
cache deny !to_archive_mirrors
#cache allow !to_archive_mirrors
# allow access from our network and localhost
http_access allow allowed_networks
# And finally deny all other access to this proxy
http_access deny all
To enable the relevant sources and store the contents of the “10-default” file we use:
# /etc/squid-deb-proxy/mirror-dstdomain.acl.d/10-default
#
# network destinations that are allowed by this cache
# launchpad personal package archives (disabled by default)
ppa.launchpad.net
ppa.launchpadcontent.net
#private-ppa.launchpad.net
# add additional mirror domains here (disabled by default)
#linux.dropbox.com
#download.virtualbox.org
#archive.getdeb.net
#packages.medibuntu.org
dl.google.com
#repo.steampowered.com
download.anydesk.com
boot.linuxgroove.com
geoip.ubuntu.com
Configuring the iPXE boot menu
The iPXE boot menu file should be located in the TFTP root directory. We use more options for the actual deployment, however for this example we are focussing on the Ubuntu installation. The iPXE menu file should look like this, we will explain in more detail below.
#!ipxe
:MENU
menu
item --gap -- ----------------Operating System Installation ------------------
item ubuntu Ubuntu 22.04 LTS Installation
item --gap -- ----------------iPXE Shell -------------------------------------
item shell iPXE Shell
choose --default return target && goto ${target}
:ubuntu
set base-url http://192.168.1.107/ubuntu/22.04
kernel ${base-url}/casper/vmlinuz
initrd ${base-url}/casper/initrd
imgargs vmlinuz initrd=initrd \
ip=dhcp \
url=${base-url}//${baseurl}install.iso \
cloud-config-url=/dev/null\
autoinstall \
ds=nocloud-net;s=http://192.168.1.107/ubuntu/22.04/jammy/ \
boot
goto MENU
:shell
shell ||
goto MENU
We are setting the base-url for the installation first, this is where we keep the files that are important for the installer hosted by the Apache2 server that we configured earlier.
and vmlinuz
initrd
are located in the casper folder. You can mount the ISO to the folder, by adding this to fstab you can ensure that these are always available upon reboot. For example the fstab entry can look like this
/pxe-boot/ubuntu/22.04/install.iso /pxe-boot/ubuntu/22.04/iso iso9660 loop,ro,auto 0 0"
`imgargs
lets you use arguments for the kernel:
This will let the machine get an ip address from the DHCP server:
ip=dhcp
The file `install.iso
is the Ubuntu 22.04 LTS Server ISO, this will let the installer know where it is located.
url=${base-url}//${baseurl}install.iso
This command prevents the iso from being loaded twice and makes it possible to load on a machine with 4GB of RAM.
cloud-config-url=/dev/null
This is indicating it is an autoinstall, it is a bit redundant since it is also located in the user-data.
Autoinstall
This is letting Subiquity know where the “user-data” and “meta-data” are located.
ds=nocloud-net;s=http://192.168.1.107/ubuntu/22.04/jammy/
Autoinstall configuration
The user-data we are using looks like this:
#cloud-config
autoinstall:
identity:
hostname: jammy-desktop
password: $6$5lpwCLsKLEzMkSJc$keOAhA6aO/5RocGhmhVA7LSNuW911Rx5HHXFEa75oGK20cEdAAgn14H5f5nGeq6QgcSyLPrWcg1.JvjXbhrN/
realname: Ubuntu user
username: ubuntu
keyboard:
layout: us
toggle: null
variant: ''
locale: en_US.UTF-8
proxy: "http://192.168.1.107:8000"
apt:
preserve_sources_list: true
sources:
compudopt-ppa:
source: ppa:compudopt/compudopt
packages:
- compudopt-overrides
- ubuntu-desktop^
- plymouth-theme-ubuntu-logo
- grub-gfxpayload-lists
- systemd-hwe-hwdb
- python3-magic
- gimp
- ubuntu-restricted-addons
- ubuntu-restricted-extras
- landscape-client
kernel:
package: linux-generic-hwe-22.04
storage:
layout:
name: direct
ssh:
allow-pw: true
authorized-keys: []
install-server: false
updates: all
timezone: America/Chicago
late-commands:
- 'sed -i.bak -e "s|#WaylandEnable=false$|DefaultSession=ubuntu-xorg.desktop|g" /target/etc/gdm3/custom.conf'
- 'echo "%sudo ALL=(ALL) NOPASSWD:ALL" > /target/etc/sudoers.d/nopw'
- chmod 440 /target/etc/sudoers.d/nopw
- curtin in-target --target=/target -- sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT=""/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"/' /etc/default/grub
- curtin in-target --target=/target -- update-grub
- curtin in-target --target=/target -- wget -O /tmp/google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- curtin in-target --target=/target -- apt install /tmp/google-chrome-stable_current_amd64.deb -y
- curtin in-target --target=/target -- wget -O /tmp/anydesk.deb https://download.anydesk.com/linux/anydesk_6.2.1-1_amd64.deb
- curtin in-target --target=/target -- apt install /tmp/anydesk.deb -y
- curtin in-target --target=/target -- apt install scratch -y
- curtin in-target --target=/target -- apt remove byobu -y
- curtin in-target --target=/target -- wget -O /sbin/reset.sh http://boot.linuxgroove.com/ubuntu/reset.sh
- chmod +x /target/sbin/reset.sh
- curtin in-target --target=/target -- useradd -m -r -s /bin/bash admin
- 'echo "admin:password" | chpasswd -R /target'
- curtin in-target --target=/target -- usermod -aG sudo admin
- touch /target/var/lib/AccountsService/users/admin
- 'echo "[User]" >> /target/var/lib/AccountsService/users/admin'
- 'echo "SystemAccount=true" >> /target/var/lib/AccountsService/users/admin'
- 'rm -f /target/etc/netplan/*.yaml'
- 'echo "# Let NetworkManager manage all devices on this system" > /target/etc/netplan/01-network-manager-all.yaml'
- 'echo "network:" >> /target/etc/netplan/01-network-manager-all.yaml'
- 'echo " version: 2" >> /target/etc/netplan/01-network-manager-all.yaml'
- 'echo " renderer: NetworkManager" >> /target/etc/netplan/01-network-manager-all.yaml'
- curtin in-target --target=/target -- wget -O /sbin/reset.sh http://192.168.1.107/ubuntu/22.04/scripts/reset.sh
- chmod +x /target/sbin/reset.sh
- curtin in-target --target=/target -- wget -O /home/snaps.tar http://192.168.1.107/ubuntu/22.04/snaps/snaps.tar
- curtin in-target --target=/target -- wget -O /home/snaps.sh http://192.168.1.107/ubuntu/22.04/scripts/snaps.sh
- chmod +x /target/home/snaps.sh
- curtin in-target --target=/target -- wget -O /etc/rc.local http://192.168.1.107/ubuntu/22.04/scripts/rc.local
- chmod +x /target/etc/rc.local
- 'mkdir -p /target/home/ubuntu/.local/share/applications'
- 'cp /target/usr/share/applications/provider-setup.desktop /target/home/ubuntu/.local/share/applications/provider-setup.desktop'
- 'sed -i.bak -e "s|NoDisplay=true$||g" /target/home/ubuntu/.local/share/applications/provider-setup.desktop'
- 'mkdir -p /target/home/ubuntu/.config/autostart'
- 'touch /target/home/ubuntu/.config/gnome-initial-setup-done'
- 'cp /target/usr/share/applications/provider-setup.desktop /target/home/ubuntu/.config/autostart/'
- 'echo "X-GNOME-Autostart-enabled=true" >> /target/home/ubuntu/.config/autostart/provider-setup.desktop'
- curtin in-target --target=/target -- chown -R 1000:1000 /home/ubuntu
version: 1
Let’s break this down in more detail:
This is letting Subiquity know that it is an autoinstall.
autoinstall
We set up squid-deb-proxy earlier, this is letting Subiquity know to use this proxy.
proxy: “http://192.168.1.107:8000”
We are using custom .deb package hosting on our ppa. This installs the desktop background and an application created to register our machines with Landscape and gather system information for our administrators.
apt:
preserve_sources_list: true
sources:
compudopt-ppa:
source: ppa:compudopt/compudopt
This is where we indicate which packages will be installed. We had to add certain packages for the desktop experience since we are starting from the server ISO.
packages:
- compudopt-overrides
- ubuntu-desktop^
- plymouth-theme-ubuntu-logo
- grub-gfxpayload-lists
- systemd-hwe-hwdb
- python3-magic
- gimp
- ubuntu-restricted-addons
- ubuntu-restricted-extras
- landscape-client
We are using several late commands on our installation, so this is a great time to do some additional configuration.
We disabled Wayland so we are able to use AnyDesk for our support team. Once AnyDesk picks up support for Wayland we will enable it.
- 'sed -i.bak -e "s|#WaylandEnable=false$|DefaultSession=ubuntu-xorg.desktop|g" /target/etc/gdm3/custom.conf'
This is where we create the hidden admin account for our tech support, by making setting `SystemAccount=true
it will not show up on the login screen.
- curtin in-target --target=/target -- useradd -m -r -s /bin/bash admin
- 'echo "admin:password" | chpasswd -R /target'
- curtin in-target --target=/target -- usermod -aG sudo admin
- touch /target/var/lib/AccountsService/users/admin
- 'echo "[User]" >> /target/var/lib/AccountsService/users/admin'
- 'echo "SystemAccount=true" >> /target/var/lib/AccountsService/users/admin'
Here we are updating grub, installing Chrome, AnyDesk and Scratch. This way we get the most up-to-date versions, if there are connection issues this will still work since we are using the squid-deb-proxy that it can always fall back to.
- curtin in-target --target=/target -- update-grub
- curtin in-target --target=/target -- wget -O /tmp/google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- curtin in-target --target=/target -- apt install /tmp/google-chrome-stable_current_amd64.deb -y
- curtin in-target --target=/target -- wget -O /tmp/anydesk.deb https://download.anydesk.com/linux/anydesk_6.2.1-1_amd64.deb
- curtin in-target --target=/target -- apt install /tmp/anydesk.deb -y
- curtin in-target --target=/target -- apt install scratch -y
- curtin in-target --target=/target -- apt remove byobu -y
The Ubuntu Server does not use network-manager so when changing to desktop during installation you will get an error message. This makes sure that the network manager is functioning as needed in Ubuntu Desktop.
- 'rm -f /target/etc/netplan/*.yaml'
- 'echo "# Let NetworkManager manage all devices on this system" > /target/etc/netplan/01-network-manager-all.yaml'
- 'echo "network:" >> /target/etc/netplan/01-network-manager-all.yaml'
- 'echo " version: 2" >> /target/etc/netplan/01-network-manager-all.yaml'
- 'echo " renderer: NetworkManager" >> /target/etc/netplan/01-network-manager-all.yaml'
We are running a cron job on the server that downloads the updated snaps for our installation and puts them in a tar file. This tar then gets installed onto the server. As a result we are not using WAN during installation.
- curtin in-target --target=/target -- wget -O /home/snaps.tar http://192.168.1.107/ubuntu/22.04/snaps/snaps.tar
The script we use is located on the server side and we have it set up as a weekly cron job. It looks like this:
#!/bin/bash
old=$PWD
echo $old
cd `dirname $0`
for i in gnome-42-2204 gnome-3-38-2004 firefox snapd-desktop-integration snap-store zoom-client vlc core18 chromium gtk-common-themes; do
snap download --channel=stable $i
done
cd ..
tar cvf snaps.tar snaps
if [ $? -eq 0 ]; then
echo "snaps.tar archive created"
rm snaps/*.assert snaps/*.snap
fi
cd $old
The rc.local script cleans the snaps and restarts NetworkManager so the internet connection works on boot.
- curtin in-target --target=/target -- wget -O /etc/rc.local http://192.168.1.107/ubuntu/22.04/scripts/rc.local
- chmod +x /target/etc/rc.local
The script looks like this:
#!/bin/bash
/home/snaps.sh
if [ $? -eq 0 ]; then
rm -rf /home/snap*
rm /etc/rc.local
nmcli n off
sleep 2
nmcli n on
fi
Finally, in our setup we are using a Ubiquiti Dream Machine Pro, you can point to a DHCP Boot and TFTP server in the web GUI.
Signing off!
I want to express my heartfelt gratitude to both Ken VanDine, Engineering Manager for Ubuntu Desktop, and Rajan Patel, Product Manager for Landscape, for their exceptional support throughout this entire process. Their expertise and assistance have been invaluable in making this a seamless and smooth experience from start to finish. Along the way, we learned a great deal about the intricate details of Ubuntu deployment and Landscape integration, thanks to their guidance and knowledge.
Now back to Oliver!
Further Reading & Resources
We hope you enjoyed this insight into Compudopt’s mission and their experience deploying Ubuntu Desktop. In this example the team started from an Ubuntu Server ISO and leveraged Subiquity to transform it into a full Desktop environment. However, from Ubuntu 23.04 onwards, Subiquity will also become the default installer for Ubuntu Desktop. This means that some of the steps above will be significantly streamlined as necessary desktop packages will already be present. To find out more about Landscape, Subiquity and how to leverage autoinstall on Ubuntu Desktop 23.04, check out the links below.
- Automated Server installation documentation
- Using Ubuntu Live-Server to automate Desktop installation
- More about Landscape
To learn more about Compudopt and their mission, don’t forget to check out Compudopt.org.
If your organisation is looking to adopt Ubuntu Desktop and you’d like to find out more about how Canonical can help you get started, please:
All photos courtesy of Compudopt National.