├── postinstall.sh ├── pxe.conf ├── src ├── Makefile ├── build_doc.py └── README.md.in ├── pxelinux.cfg.default ├── autoinstall-nouser.yaml.sample ├── autoinstall-landscape.yaml.sample ├── .github └── workflows │ └── generation-up-to-date.yaml ├── autoinstall.yaml └── README.md /postinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Install language packs for English 4 | apt install -y $(check-language-support -l en) 5 | -------------------------------------------------------------------------------- /pxe.conf: -------------------------------------------------------------------------------- 1 | interface=,lo 2 | bind-interfaces 3 | dhcp-range=,192.168.0.100,192.168.0.200 4 | dhcp-boot=pxelinux.0 5 | enable-tftp 6 | tftp-root=/srv/tftp 7 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | default: clean build 2 | 3 | clean: 4 | rm -f ../README.md out.temp 5 | 6 | build: 7 | ./build_doc.py README.md.in ../README.md 8 | 9 | test: 10 | ./build_doc.py README.md.in out.temp 11 | diff -u ../README.md out.temp 12 | -------------------------------------------------------------------------------- /pxelinux.cfg.default: -------------------------------------------------------------------------------- 1 | DEFAULT install 2 | LABEL install 3 | KERNEL vmlinuz 4 | INITRD initrd 5 | APPEND root=/dev/ram0 ramdisk_size=1500000 ip=dhcp cloud-config-url=http://192.168.0.2/autoinstall.yaml url=http://192.168.0.2/ubuntu-22.04.1-live-server-amd64.iso autoinstall 6 | -------------------------------------------------------------------------------- /autoinstall-nouser.yaml.sample: -------------------------------------------------------------------------------- 1 | ## This sample snippet can optionally be included in the autoinstall.yaml file. 2 | # This inhibits user creation, which for Desktop images means that 3 | # gnome-initial-setup will prompt for user creation on first boot. 4 | user-data: 5 | users: [''] 6 | -------------------------------------------------------------------------------- /autoinstall-landscape.yaml.sample: -------------------------------------------------------------------------------- 1 | ## This sample snippet can optionally be included in the autoinstall.yaml file. 2 | user-data: 3 | landscape: 4 | client: 5 | url: "https://landscape.canonical.com/message-system" 6 | ping_url: "http://landscape.canonical.com/ping" 7 | … 8 | -------------------------------------------------------------------------------- /.github/workflows/generation-up-to-date.yaml: -------------------------------------------------------------------------------- 1 | name: Doc Generation up to date 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | defaults: 18 | run: 19 | working-directory: src 20 | 21 | steps: 22 | - uses: actions/checkout@v3 23 | 24 | - name: Set up Python 25 | uses: actions/setup-python@v3 26 | 27 | - name: Confirm document up to date 28 | run: make test 29 | -------------------------------------------------------------------------------- /src/build_doc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # do some basic preprocessing: 4 | # * handle #include directives 5 | # * skip outputting certain comments, in the markdown and in included files 6 | 7 | import sys 8 | 9 | infile = sys.argv[1] 10 | outfile = sys.argv[2] 11 | 12 | 13 | def readlines(filename): 14 | with open(filename, 'r') as fp: 15 | return fp.readlines() 16 | 17 | 18 | with open(outfile, 'w') as fp: 19 | for line in readlines(infile): 20 | tokens = line.split(' ') 21 | if tokens[0] == '#include': 22 | filename = tokens[1].split('"')[1] 23 | for includeline in readlines(filename): 24 | if not includeline.startswith('##'): 25 | fp.write(includeline) 26 | elif tokens[0] == '%%': 27 | continue 28 | else: 29 | fp.write(line) 30 | -------------------------------------------------------------------------------- /autoinstall.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | autoinstall: 3 | # version is an Autoinstall required field. 4 | version: 1 5 | 6 | # This adds the default ubuntu-desktop packages to the system. 7 | # Any desired additional packages may also be listed here. 8 | packages: 9 | - ubuntu-desktop 10 | 11 | # This adds the default snaps found on a 22.04 Ubuntu Desktop system. 12 | # Any desired additional snaps may also be listed here. 13 | snaps: 14 | - name: firefox 15 | - name: gnome-3-38-2004 16 | - name: gtk-common-themes 17 | - name: snap-store 18 | - name: snapd-desktop-integration 19 | 20 | # User creation can occur in one of 3 ways: 21 | # 1. Create a user using this `identity` section. 22 | # 2. Create users as documented in cloud-init inside the user-data section, 23 | # which means this single-user identity section may be removed. 24 | # 3. Prompt for user configuration on first boot. Remove this identity 25 | # section and see the "Installation without a default user" section. 26 | identity: 27 | realname: '' 28 | username: ubuntu 29 | # A password hash is needed. `mkpasswd --method=SHA-512` can help. 30 | # mkpasswd can be found in the package 'whois' 31 | password: '' 32 | hostname: ubuntu-desktop 33 | 34 | # Subiquity will, by default, configure a partition layout using LVM. 35 | # The 'direct' layout method shown here will produce a non-LVM result. 36 | storage: 37 | layout: 38 | name: direct 39 | 40 | # Ubuntu Desktop uses the hwe flavor kernel by default. 41 | early-commands: 42 | - echo 'linux-generic-hwe-22.04' > /run/kernel-meta-package 43 | 44 | # The live-server ISO does not contain some of the required packages, 45 | # such as ubuntu-desktop or the hwe kernel (or most of their depdendencies). 46 | # The system being installed will need some sort of apt access. 47 | # proxy: http://192.168.0.1:3142 48 | 49 | late-commands: 50 | # Enable the boot splash 51 | - >- 52 | curtin in-target -- 53 | sed -i /etc/default/grub -e 54 | 's/GRUB_CMDLINE_LINUX_DEFAULT=".*/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"/' 55 | - curtin in-target -- update-grub 56 | 57 | # Let NetworkManager handle network 58 | - rm /target/etc/netplan/00-installer-config*yaml 59 | - >- 60 | printf "network:\n version: 2\n renderer: NetworkManager" 61 | > /target/etc/netplan/01-network-manager-all.yaml 62 | 63 | # Remove default filesystem and related tools not used with the suggested 64 | # 'direct' storage layout. These may yet be required if different 65 | # partitioning schemes are used. 66 | - >- 67 | curtin in-target -- apt-get remove -y 68 | btrfs-progs cryptsetup* lvm2 xfsprogs 69 | 70 | # Remove other packages present by default in Ubuntu Server but not 71 | # normally present in Ubuntu Desktop. 72 | - >- 73 | curtin in-target -- apt-get remove -y 74 | ubuntu-server ubuntu-server-minimal 75 | binutils byobu curl dmeventd finalrd gawk 76 | kpartx mdadm ncurses-term needrestart open-iscsi openssh-server 77 | sg3-utils ssh-import-id sssd thin-provisioning-tools vim tmux 78 | sosreport screen open-vm-tools motd-news-config lxd-agent-loader 79 | landscape-common htop git fonts-ubuntu-console ethtool 80 | 81 | # Keep cloud-init, as it performs some of the installation on first boot. 82 | - curtin in-target -- apt-get install -y cloud-init 83 | 84 | # Finally, remove things only installed as dependencies of other things 85 | # we have already removed. 86 | - curtin in-target -- apt-get autoremove -y 87 | 88 | # A postinstall script may optionally be used for further install 89 | # customization. Deploy this postinstall.sh script on the webserver. 90 | # - wget -O /target/postinstall.sh http://192.168.0.2/postinstall.sh 91 | # - curtin in-target -- bash /postinstall.sh 92 | # - rm /target/postinstall.sh 93 | 94 | # Additional cloud-init configuration affecting the target 95 | # system can be supplied underneath a user-data section inside of 96 | # autoinstall. 97 | # user-data: 98 | # … 99 | -------------------------------------------------------------------------------- /src/README.md.in: -------------------------------------------------------------------------------- 1 | # Using Ubuntu Live-Server to automate Desktop installation 2 | %% This file has some basic preprocessing, see build_doc.py for details. 3 | %% Edit this document instead of the generated one. 4 | 5 | ## Abstract 6 | This document describes the procedure to perform an automated install of Ubuntu 22.04.x LTS Desktop. This is implemented by using the Ubuntu 22.04.x LTS Server ISO, installing Desktop on top, and removing unneeded default Server packages. 7 | 8 | ## Introduction 9 | The Ubuntu 22.04 LTS live-server ISO uses Subiquity, which means that the 10 | Subiquity Autoinstall format is used for automation. 11 | 12 | This document was written for, and is up to date with, Ubuntu 22.04.1. 13 | 14 | As a quick introduction to Autoinstall, it is a YAML format where the installer 15 | has default values for almost all of the configuration. As such, simple 16 | Autoinstalls can be very short, if the default configuration is acceptable. 17 | 18 | This document covers just enough Autoinstall to get a Desktop experience. It's 19 | highly likely that the Autoinstall will need further configuration to meet 20 | practical installation requirements. 21 | 22 | All sample configuration files and scripts can be found in this git repository. 23 | 24 | For more information on Autoinstall, please see: 25 | * [Automated Server Installs](https://ubuntu.com/server/docs/install/autoinstall) 26 | * [Automated Server Install Quickstart](https://ubuntu.com/server/docs/install/autoinstall-quickstart) 27 | * [Automated Server Installs Config File Reference](https://ubuntu.com/server/docs/install/autoinstall-reference) 28 | 29 | ## Autoinstall 30 | Below is an almost-ready-to-use autoinstall.yaml. Please adjust the `identity` section to set a password hash and confirm the desired user information. 31 | ```yaml 32 | #include "../autoinstall.yaml" 33 | ``` 34 | 35 | ### Postinstall script 36 | At the end of the sample autoinstall.yaml is an example of downloading and calling an external postinstall script. Here is one such example script, replicating the default language pack installation found on Ubuntu Desktop. 37 | ```sh 38 | #include "../postinstall.sh" 39 | ``` 40 | 41 | ### Installation without a default user 42 | It is possible to install the system without a default user. In this situation on first boot of the system, Gnome Initial Setup will start and ask to create a user, its regional settings and a few default options. 43 | 44 | To do so, entirely remove the "identity" section from the seed file and add to the end an empty "users" entry in a user-data section as follows: 45 | ```yaml 46 | #include "../autoinstall-nouser.yaml.sample" 47 | ``` 48 | 49 | ### Registration with Landscape 50 | To register the installed system with Landscape, cloud-init’s [Landscape](https://cloudinit.readthedocs.io/en/latest/topics/modules.html#landscape) support can be used. Please ensure that a user-data section is present in the autoinstall data, and supply the appropriate values. See also [`man landscape-config`](https://manpages.ubuntu.com/manpages/jammy/en/man1/landscape-config.1.html). 51 | ```yaml 52 | #include "../autoinstall-landscape.yaml.sample" 53 | ``` 54 | 55 | ## Netboot 56 | The procedure for netboot is equivalent to what is documented in the ["Netbooting the live server installer"](https://discourse.ubuntu.com/t/netbooting-the-live-server-installer/14510) document. That procedure has been updated for Ubuntu 22.04.x and adjusted to deliver the Autoinstall to the install environment. 57 | 58 | ### dnsmasq 59 | Assuming dnsmasq will be used to serve the netboot binaries: 60 | 61 | 1. `apt install dnsmasq` 62 | 2. Configure `/etc/dnsmasq.d/pxe.conf`. Adjust as appropriate for the installation network: 63 | ``` 64 | #include "../pxe.conf" 65 | ``` 66 | 3. Ensure that the `/srv/tftp` directory exists 67 | `mkdir -p /srv/tftp` 68 | 4. `systemctl restart dnsmasq.service` 69 | 70 | ### Hosting the Autoinstall and the ISO 71 | We need to host the Autoinstall YAML somewhere the netboot can get to it. This is a good opportunity to host the ISO, which should reduce the download time for the largest component. 72 | 73 | 74 | 1. Download the [22.04.1 Live Server ISO](https://releases.ubuntu.com/22.04.1/ubuntu-22.04.1-live-server-amd64.iso) 75 | 2. Install a web server. 76 | 3. Copy the configured autoinstall.yaml and the Live Server ISO to the appropriate directory being served by the web server. 77 | 78 | ### PXE Configuration 79 | 1. Download pxelinux.0 and put it into place: 80 | ``` 81 | wget http://archive.ubuntu.com/ubuntu/dists/focal/main/installer-amd64/current/legacy-images/netboot/pxelinux.0 82 | mv pxelinux.0 /srv/tftp/ 83 | ``` 84 | 85 | 2. Mount the Live Server ISO. 86 | ``` 87 | mount ubuntu-22.04.1-live-server-amd64.iso /mnt 88 | ``` 89 | 90 | 3. Copy the kernel, initrd, and ldlinux.c32 to where the dnsmasq serves tftp from: 91 | ``` 92 | cp /mnt/casper/{vmlinuz,initrd} /srv/tftp/ 93 | apt install syslinux-common 94 | cp /usr/lib/syslinux/modules/bios/ldlinux.c32 /srv/tftp/ 95 | ``` 96 | 97 | 4. Create /srv/tftp/pxelinux.cfg/default as below. Note that the APPEND and all following items should be on a single line, and that the configured URLs should point to the previous setup http server. 98 | ``` 99 | #include "../pxelinux.cfg.default" 100 | ``` 101 | 102 | # Install 103 | At this point everything needed should be in place. Boot the target system. It will perform the PXE netboot, download the ISO, use the Autoinstall configuration, and finally reboot to the installed environment. 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Using Ubuntu Live-Server to automate Desktop installation 2 | 3 | ## Abstract 4 | This document describes the procedure to perform an automated install of Ubuntu 22.04.x LTS Desktop. This is implemented by using the Ubuntu 22.04.x LTS Server ISO, installing Desktop on top, and removing unneeded default Server packages. 5 | 6 | ## Introduction 7 | The Ubuntu 22.04 LTS live-server ISO uses Subiquity, which means that the 8 | Subiquity Autoinstall format is used for automation. 9 | 10 | This document was written for, and is up to date with, Ubuntu 22.04.1. 11 | 12 | As a quick introduction to Autoinstall, it is a YAML format where the installer 13 | has default values for almost all of the configuration. As such, simple 14 | Autoinstalls can be very short, if the default configuration is acceptable. 15 | 16 | This document covers just enough Autoinstall to get a Desktop experience. It's 17 | highly likely that the Autoinstall will need further configuration to meet 18 | practical installation requirements. 19 | 20 | All sample configuration files and scripts can be found in this git repository. 21 | 22 | For more information on Autoinstall, please see: 23 | * [Automated Server Installs](https://ubuntu.com/server/docs/install/autoinstall) 24 | * [Automated Server Install Quickstart](https://ubuntu.com/server/docs/install/autoinstall-quickstart) 25 | * [Automated Server Installs Config File Reference](https://ubuntu.com/server/docs/install/autoinstall-reference) 26 | 27 | ## Autoinstall 28 | Below is an almost-ready-to-use autoinstall.yaml. Please adjust the `identity` section to set a password hash and confirm the desired user information. 29 | ```yaml 30 | #cloud-config 31 | autoinstall: 32 | # version is an Autoinstall required field. 33 | version: 1 34 | 35 | # This adds the default ubuntu-desktop packages to the system. 36 | # Any desired additional packages may also be listed here. 37 | packages: 38 | - ubuntu-desktop 39 | 40 | # This adds the default snaps found on a 22.04 Ubuntu Desktop system. 41 | # Any desired additional snaps may also be listed here. 42 | snaps: 43 | - name: firefox 44 | - name: gnome-3-38-2004 45 | - name: gtk-common-themes 46 | - name: snap-store 47 | - name: snapd-desktop-integration 48 | 49 | # User creation can occur in one of 3 ways: 50 | # 1. Create a user using this `identity` section. 51 | # 2. Create users as documented in cloud-init inside the user-data section, 52 | # which means this single-user identity section may be removed. 53 | # 3. Prompt for user configuration on first boot. Remove this identity 54 | # section and see the "Installation without a default user" section. 55 | identity: 56 | realname: '' 57 | username: ubuntu 58 | # A password hash is needed. `mkpasswd --method=SHA-512` can help. 59 | # mkpasswd can be found in the package 'whois' 60 | password: '' 61 | hostname: ubuntu-desktop 62 | 63 | # Subiquity will, by default, configure a partition layout using LVM. 64 | # The 'direct' layout method shown here will produce a non-LVM result. 65 | storage: 66 | layout: 67 | name: direct 68 | 69 | # Ubuntu Desktop uses the hwe flavor kernel by default. 70 | early-commands: 71 | - echo 'linux-generic-hwe-22.04' > /run/kernel-meta-package 72 | 73 | # The live-server ISO does not contain some of the required packages, 74 | # such as ubuntu-desktop or the hwe kernel (or most of their depdendencies). 75 | # The system being installed will need some sort of apt access. 76 | # proxy: http://192.168.0.1:3142 77 | 78 | late-commands: 79 | # Enable the boot splash 80 | - >- 81 | curtin in-target -- 82 | sed -i /etc/default/grub -e 83 | 's/GRUB_CMDLINE_LINUX_DEFAULT=".*/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"/' 84 | - curtin in-target -- update-grub 85 | 86 | # Let NetworkManager handle network 87 | - rm /target/etc/netplan/00-installer-config*yaml 88 | - >- 89 | printf "network:\n version: 2\n renderer: NetworkManager" 90 | > /target/etc/netplan/01-network-manager-all.yaml 91 | 92 | # Remove default filesystem and related tools not used with the suggested 93 | # 'direct' storage layout. These may yet be required if different 94 | # partitioning schemes are used. 95 | - >- 96 | curtin in-target -- apt-get remove -y 97 | btrfs-progs cryptsetup* lvm2 xfsprogs 98 | 99 | # Remove other packages present by default in Ubuntu Server but not 100 | # normally present in Ubuntu Desktop. 101 | - >- 102 | curtin in-target -- apt-get remove -y 103 | ubuntu-server ubuntu-server-minimal 104 | binutils byobu curl dmeventd finalrd gawk 105 | kpartx mdadm ncurses-term needrestart open-iscsi openssh-server 106 | sg3-utils ssh-import-id sssd thin-provisioning-tools vim tmux 107 | sosreport screen open-vm-tools motd-news-config lxd-agent-loader 108 | landscape-common htop git fonts-ubuntu-console ethtool 109 | 110 | # Keep cloud-init, as it performs some of the installation on first boot. 111 | - curtin in-target -- apt-get install -y cloud-init 112 | 113 | # Finally, remove things only installed as dependencies of other things 114 | # we have already removed. 115 | - curtin in-target -- apt-get autoremove -y 116 | 117 | # A postinstall script may optionally be used for further install 118 | # customization. Deploy this postinstall.sh script on the webserver. 119 | # - wget -O /target/postinstall.sh http://192.168.0.2/postinstall.sh 120 | # - curtin in-target -- bash /postinstall.sh 121 | # - rm /target/postinstall.sh 122 | 123 | # Additional cloud-init configuration affecting the target 124 | # system can be supplied underneath a user-data section inside of 125 | # autoinstall. 126 | # user-data: 127 | # … 128 | ``` 129 | 130 | ### Postinstall script 131 | At the end of the sample autoinstall.yaml is an example of downloading and calling an external postinstall script. Here is one such example script, replicating the default language pack installation found on Ubuntu Desktop. 132 | ```sh 133 | #!/bin/sh 134 | 135 | # Install language packs for English 136 | apt install -y $(check-language-support -l en) 137 | ``` 138 | 139 | ### Installation without a default user 140 | It is possible to install the system without a default user. In this situation on first boot of the system, Gnome Initial Setup will start and ask to create a user, its regional settings and a few default options. 141 | 142 | To do so, entirely remove the "identity" section from the seed file and add to the end an empty "users" entry in a user-data section as follows: 143 | ```yaml 144 | # This inhibits user creation, which for Desktop images means that 145 | # gnome-initial-setup will prompt for user creation on first boot. 146 | user-data: 147 | users: [''] 148 | ``` 149 | 150 | ### Registration with Landscape 151 | To register the installed system with Landscape, cloud-init’s [Landscape](https://cloudinit.readthedocs.io/en/latest/topics/modules.html#landscape) support can be used. Please ensure that a user-data section is present in the autoinstall data, and supply the appropriate values. See also [`man landscape-config`](https://manpages.ubuntu.com/manpages/jammy/en/man1/landscape-config.1.html). 152 | ```yaml 153 | user-data: 154 | landscape: 155 | client: 156 | url: "https://landscape.canonical.com/message-system" 157 | ping_url: "http://landscape.canonical.com/ping" 158 | … 159 | ``` 160 | 161 | ## Netboot 162 | The procedure for netboot is equivalent to what is documented in the ["Netbooting the live server installer"](https://discourse.ubuntu.com/t/netbooting-the-live-server-installer/14510) document. That procedure has been updated for Ubuntu 22.04.x and adjusted to deliver the Autoinstall to the install environment. 163 | 164 | ### dnsmasq 165 | Assuming dnsmasq will be used to serve the netboot binaries: 166 | 167 | 1. `apt install dnsmasq` 168 | 2. Configure `/etc/dnsmasq.d/pxe.conf`. Adjust as appropriate for the installation network: 169 | ``` 170 | interface=,lo 171 | bind-interfaces 172 | dhcp-range=,192.168.0.100,192.168.0.200 173 | dhcp-boot=pxelinux.0 174 | enable-tftp 175 | tftp-root=/srv/tftp 176 | ``` 177 | 3. Ensure that the `/srv/tftp` directory exists 178 | `mkdir -p /srv/tftp` 179 | 4. `systemctl restart dnsmasq.service` 180 | 181 | ### Hosting the Autoinstall and the ISO 182 | We need to host the Autoinstall YAML somewhere the netboot can get to it. This is a good opportunity to host the ISO, which should reduce the download time for the largest component. 183 | 184 | 185 | 1. Download the [22.04.1 Live Server ISO](https://releases.ubuntu.com/22.04.1/ubuntu-22.04.1-live-server-amd64.iso) 186 | 2. Install a web server. 187 | 3. Copy the configured autoinstall.yaml and the Live Server ISO to the appropriate directory being served by the web server. 188 | 189 | ### PXE Configuration 190 | 1. Download pxelinux.0 and put it into place: 191 | ``` 192 | wget http://archive.ubuntu.com/ubuntu/dists/focal/main/installer-amd64/current/legacy-images/netboot/pxelinux.0 193 | mv pxelinux.0 /srv/tftp/ 194 | ``` 195 | 196 | 2. Mount the Live Server ISO. 197 | ``` 198 | mount ubuntu-22.04.1-live-server-amd64.iso /mnt 199 | ``` 200 | 201 | 3. Copy the kernel, initrd, and ldlinux.c32 to where the dnsmasq serves tftp from: 202 | ``` 203 | cp /mnt/casper/{vmlinuz,initrd} /srv/tftp/ 204 | apt install syslinux-common 205 | cp /usr/lib/syslinux/modules/bios/ldlinux.c32 /srv/tftp/ 206 | ``` 207 | 208 | 4. Create /srv/tftp/pxelinux.cfg/default as below. Note that the APPEND and all following items should be on a single line, and that the configured URLs should point to the previous setup http server. 209 | ``` 210 | DEFAULT install 211 | LABEL install 212 | KERNEL vmlinuz 213 | INITRD initrd 214 | APPEND root=/dev/ram0 ramdisk_size=1500000 ip=dhcp cloud-config-url=http://192.168.0.2/autoinstall.yaml url=http://192.168.0.2/ubuntu-22.04.1-live-server-amd64.iso autoinstall 215 | ``` 216 | 217 | # Install 218 | At this point everything needed should be in place. Boot the target system. It will perform the PXE netboot, download the ISO, use the Autoinstall configuration, and finally reboot to the installed environment. 219 | --------------------------------------------------------------------------------