How To Install ZorinOS 16 Over LAN

How to install ZorinOS 16 over the network

In case of lacking any form of external media device such as a USB, CD-ROM, hard drive, etc., it's still possible to install ZorinOS 16 over the network using another computer as an TFTP server. This guide attempts to provide straight forward step-by-step instructions to run a TFTP server from which to load the ZorinOS 16 ISO.

There are multiple ways to set this up. Different resources found online may differ from the instructions listed here. In addition, the exact files to be used vary from one distribution to another. Keep all of this in mind when comparing this guide with other resources.


  1. A separate computer running on the same local network. This guide will assume that it runs Debian 12; other flavors of Linux should work the same but the package names and/or configuration files may be different. If you don't have Linux you can follow along from within a virtual machine, as long as it has access to the local network.

  2. A TFTP server, to serve the bootloader over the network.

  3. A DHCP server with proxy capabilities, to specify the path to the bootloader that is served by the TFTP server.

  4. A HTTP server to serve the ISO image file.

  5. ZorinOS 16 ISO file.

The TFTP and DHCP servers are provided by the same package, dnsmasq. The HTTP server will be provided by Python's http.server module since it's already installed by default in most Linux distributions, but any other software will do.

Install Dependencies

Let's get started with the basics, installing all the necessary software to setup our servers.

sudo apt install pxelinux syslinux dnsmasq

Configure dnsmasq

Despite the name, dnsmasq can do more than providing a DNS server, which in fact is one thing that we do not need for this. The first step will be to disable this.

Before making any changes to configuration files it's a good idea to make a backup copy of the original. Now let's edit it with the following options. Please read the comments for details on what each line does:

sudo cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
sudo nano /etc/dnsmasq.conf /etc/dnsmasq.conf
# Disables DNS server

# Enables the TFTP server

# Specifies the path for the files served by the TFTP server.

# After the initial connection with the TFTP server, a random port will be
# selected by the OS for all subsequent exchanges. Specifying a range of
# ports here will allow to narrow the list of random ports to be used,
# making it easier to create predictable firewall traffic rules. The ports 
# must be under 1025 (unless running as root) and not in use.

# The local network range to listen for DHCP requests. Adjust this to point
# to your own address range as needed. The proxy option will prevent the
# DHCP server from attempting to provide IP addresses to other devices on
# the network. Instead it will provide details about the location of the
# PXE server.

# Bootloader to use for BIOS powered devices.
pxe-service=x86PC,"PXELINUX (BIOS)",bios/pxelinux

# Bootloader to use for UEFI powered devices.
pxe-service=x86-64_EFI,"PXELINUX (EFI)",efi64/syslinux.efi

# Useful for debugging and seeing the traffic generated.

We need to create the directory where the TFTP server will be serving files from, as specified in the configuration above.

sudo mkdir /srv/tftp/

Inside this directory we want to create another two directories, containing the files required by BIOS and UEFI powered systems, respectively.

sudo mkdir -p /srv/tftp/{bios,efi64}

And restart the dnsmasq service.

sudo systemctl restart dnsmasq.service

Place the bootloader files into the TFTP root

We need a bootloader, among other things. These files will be served by the TFTP server, which we got from the packages that we installed earlier. All we need to do is place them inside the TFTP server root as defined in the dnsmasq.conf file:

sudo cp /usr/lib/syslinux/modules/bios/{ldlinux,vesamenu,libcom32,libutil}.c32 /usr/lib/PXELINUX/pxelinux.0 /srv/tftp/bios

And repeat the process for the UEFI files:

sudo cp /usr/lib/syslinux/modules/efi64/ldlinux.e64 /usr/lib/syslinux/modules/efi64/{vesamenu,libcom32,libutil}.c32 /usr/lib/SYSLINUX.EFI/efi64/syslinux.efi /srv/tftp/efi64

Create the GRUB menu options

Next, we need to create the define the GRUB menu options. For that we need to create a directory called pxelinux.cfg with a single file, default. This file will have a very bare menu with a single option for ZorinOS, but it'll do. It will have the following contents:

UI vesamenu.c32

LABEL zorin 16 core network boot
    KERNEL ::boot/casper/vmlinuz
    INITRD ::boot/casper/initrd.lz4
    APPEND root=/dev/ram0 ramdisk_size=1048576 ip=dhcp netboot=url url=

The KERNEL and INITRD lines define the files served by the TFTP server, that are used to boot over the network. The :: serves as a placeholder for the root directory as defined in dnsmasq.conf. This means that we need have to have a boot directory containing these temporary bootloader and kernel files, which we'll create next.

The APPEND line defines additional parameters for the kernel. Here we specify how to boot and where to load the actual live ISO file. Make sure the IP address points to the right server. It may work with domain names as well but I haven't tried it.

In order to use this file regardless of whether the client machine runs on BIOS or UEFI, we can create symbolic links to it in either of the respective folders we created earlier.

sudo ln -s /srv/tftp/pxelinux.cfg /srv/tftp/bios/pxelinux.cfg
sudo ln -s /srv/tftp/pxelinux.cfg /srv/tftp/efi64/pxelinux.cfg

Extract the ISO files

As per the previous step, we need to provide the files to initialize the OS over the network. We can get these from the ZorinOS ISO by mounting it somewhere in the file system temporarily, and then copying the relevant files to our TFTP root.

sudo mkdir /mnt/zorin16
sudo mount -o loop -t iso9660 ~/Downloads/Zorin-OS-16.3-Core-64-bit.iso /mnt/zorin16

And copy the files to our TFTP root folder.

sudo mkdir /srv/tftp/boot
sudo cp -r /mnt/zorin16/* /srv/tftp/boot/

At this point, we should have the following file structure for our TFTP server:

├── bios
│ ├── ldlinux.c32
│ ├── libcom32.c32
│ ├── libutil.c32
│ ├── pxelinux.0
│ ├── pxelinux.cfg -> /srv/tftp/pxelinux.cfg
│ └── vesamenu.c32
├── boot
│ ├── boot
│ ├── casper
│ ├── dists
│ ├── efi
│ ├── isolinux
│ ├── md5sum.txt
│ ├── pool
│ └── README.diskdefines
├── efi64
│ ├── ldlinux.e64
│ ├── libcom32.c32
│ ├── libutil.c32
│ ├── pxelinux.cfg -> /srv/tftp/pxelinux.cfg
│ ├── syslinux.efi
│ └── vesamenu.c32
└── pxelinux.cfg
└── default

Make Firewall Rules

Since you need to access files over the network we may need to create a few rules for the server firewall. These rules allow incoming traffic for the DCHP server (67), the initial connection to the TFTP server (69) and subsequent connections, as specified by the tftp-port-range option in dnsmasq.conf (in this example I chose a range between ports 7000 to 7100), the PXE server (4011) and HTTP server (80).

sudo ufw allow 67/udp
sudo ufw allow 69/udp
sudo ufw allow 4011/udp
sudo ufw allow 7000:7100/udp
sudo ufw allow 80/tcp

Run the HTTP server

Finally, start the HTTP server:

sudo python3 -m pip http.server 80 -d ~/Downloads

The -d or --directory option should point to the folder that contains the ISO file. In this example I'm using the Downloads folder, and also specifying the port which should be set to 80.

Start the target machine

Now, you're ready to start the target machine and choose the network book option. After a bit it will load the bootloader files and show the prompt that we created, with a single option for ZorinOS 16. Upon selecting this with Enter, it will load the iso file over HTTP and start up the live version of ZorinOS.