Building Linux Thin Clients
Deploy Linux thin clients using modern LTSP, PXE boot, and NFS root setups. Covers server config, squashfs images, UEFI/BIOS PXE, and Wayland caveats.
Before you start
- ▸A dedicated server on the same Layer 2 network segment as the clients
- ▸Root or sudo access on the server
- ▸A Gigabit switch and a subnet reserved for thin clients
- ▸Basic familiarity with DHCP, DNS, and Linux networking concepts
Thin clients boot from a server, run applications remotely or in a local lightweight environment, and keep hardware costs low. Linux makes this practical without enterprise licensing fees. This guide covers the core concepts, PXE booting, LTSP 5/Epoptes-era versus modern LTSP (the complete rewrite), and a leaner alternative using a stateless NFS root. Expect to spend a few hours on your first deployment; subsequent clients add minutes.
Core Concepts
A thin client architecture has three moving parts:
- Boot server: responds to PXE requests via DHCP and serves the kernel/initrd via TFTP.
- Root filesystem server: exports a squashfs image or NFS tree the client mounts as its root.
- Application server: runs sessions the client connects to—SSH X11 forwarding, XDMCP, or a full Wayland compositor over SSH with hardware-accelerated clients (the modern LTSP model).
All three roles can live on one machine or be split across a rack. For fewer than 30 seats, one beefy server is typical.
Server Hardware and Network Requirements
The server is the bottleneck. Budget roughly 1 CPU core and 512 MB RAM per concurrent user for lightweight desktop sessions (XFCE, MATE). A Gigabit switch is the practical minimum; separate the thin-client VLAN from general traffic to avoid broadcast storms during simultaneous PXE boots.
- Server: 8+ cores, 32 GB RAM, SSD storage for the image
- Clients: Any x86-64 machine with a PXE-capable NIC (UEFI or legacy BIOS both work)
- Network: Gigabit switch, dedicated VLAN or segment preferred
Install and Configure LTSP
Modern LTSP (github.com/ltsp/ltsp) is a complete rewrite that supports Ubuntu, Debian, and derivatives. It dropped the old chroot model—clients now boot a squashfs image built directly from the server's root filesystem or a separate chroot.
Install LTSP on Debian/Ubuntu
sudo add-apt-repository ppa:ltsp/ppa # Ubuntu only; Debian uses the official repo
sudo apt update
sudo apt install --install-recommends ltsp epoptes dnsmasq
On Debian stable, LTSP is in the main repository:
sudo apt update
sudo apt install ltsp epoptes dnsmasq
Epoptes is the classroom management tool—optional but useful. dnsmasq will handle DHCP proxy and TFTP; if you already run a DHCP server (pfSense, a router), configure dnsmasq in proxy mode instead.
Configure dnsmasq
Edit /etc/dnsmasq.d/ltsp.conf. The example below assumes your server is at 192.168.10.1 and you want dnsmasq to be the authoritative DHCP server on a dedicated subnet:
cat /etc/dnsmasq.d/ltsp.conf
Typical content (adjust to your network):
interface=eth1
dhcp-range=192.168.10.100,192.168.10.200,12h
dhcp-boot=ltsp/boot/pxelinux.0
enable-tftp
tftp-root=/srv/tftp
If another device owns DHCP, use proxy mode—replace dhcp-range with:
dhcp-range=192.168.10.0,proxy
Build the Client Image
LTSP builds a squashfs image of the running system. Run this as root on the server:
sudo ltsp image /
This creates /srv/ltsp/images/amd64.img. The first build takes several minutes; subsequent runs are faster because only changes are recompressed.
For a separate chroot (useful when clients need a different package set than your server):
sudo debootstrap --arch=amd64 jammy /srv/ltsp/jammy http://archive.ubuntu.com/ubuntu
sudo ltsp image /srv/ltsp/jammy
Generate the iPXE/TFTP Tree
sudo ltsp kernel /srv/ltsp/images/amd64.img
sudo ltsp initrd
sudo ltsp ipxe
These commands populate /srv/tftp/ltsp/ with the kernel, initrd, and iPXE configuration.
Configure Client Parameters
LTSP uses /etc/ltsp/ltsp.conf for per-client and global settings. A minimal working config:
cat /etc/ltsp/ltsp.conf
[server]
HORIZONTAL_RESOLUTION=1920
VERTICAL_RESOLUTION=1080
LDM_SERVER=192.168.10.1
[clients]
SCREEN_07=ltsp-session
LDM (LTSP Display Manager) handles graphical login over SSH—it encrypts all display traffic without extra configuration, which is a significant security improvement over raw XDMCP.
PXE Boot Deep Dive
PXE (Pre-boot eXecution Environment) works in stages: the NIC broadcasts a DHCP request, the server returns an IP plus a next-server (TFTP host) and filename (bootloader path). The client downloads the bootloader via TFTP, which then fetches the kernel and initrd.
UEFI vs Legacy BIOS PXE
Legacy BIOS clients request pxelinux.0. UEFI clients request an EFI bootloader. LTSP's ltsp ipxe command handles both by placing the correct binaries. In dnsmasq, tag them explicitly if you have a mixed fleet:
dhcp-match=set:efi-x86_64,option:client-arch,7
dhcp-boot=tag:efi-x86_64,ltsp/boot/grubx64.efi
dhcp-boot=tag:!efi-x86_64,ltsp/boot/pxelinux.0
Verify TFTP Delivery
tftp 192.168.10.1 -c get ltsp/boot/pxelinux.0 /tmp/test.0 && echo OK
Run this from another machine on the same subnet. If it fails, check firewall rules—TFTP uses UDP port 69.
Firewall Rules
Open the required ports on the server. With ufw (Debian/Ubuntu):
sudo ufw allow from 192.168.10.0/24 to any port 67 proto udp # DHCP
sudo ufw allow from 192.168.10.0/24 to any port 69 proto udp # TFTP
sudo ufw allow from 192.168.10.0/24 to any port 22 proto tcp # SSH/LDM
With firewalld (Fedora/RHEL — note LTSP is Debian-centric, but the networking stack applies):
sudo firewall-cmd --zone=internal --add-service=dhcp --permanent
sudo firewall-cmd --zone=internal --add-service=tftp --permanent
sudo firewall-cmd --zone=internal --add-service=ssh --permanent
sudo firewall-cmd --reload
Lightweight Alternative: Stateless NFS Root
If LTSP is more than you need—say, kiosk terminals running a single browser—a hand-rolled NFS root is simpler to audit and maintain.
Export an NFS Root
# Install NFS server
sudo apt install nfs-kernel-server # Debian/Ubuntu
sudo dnf install nfs-utils # Fedora/RHEL
# Add to /etc/exports
echo '/srv/nfsroot 192.168.10.0/24(ro,sync,no_root_squash,no_subtree_check)' \
| sudo tee -a /etc/exports
sudo exportfs -rav
Build the NFS Root
sudo debootstrap --arch=amd64 jammy /srv/nfsroot http://archive.ubuntu.com/ubuntu
sudo chroot /srv/nfsroot apt install -y linux-image-generic openssh-server xorg openbox
Set a root password inside the chroot, configure /srv/nfsroot/etc/fstab with tmpfs entries for /tmp and /var/run, and point your PXE bootloader kernel line at root=/dev/nfs nfsroot=192.168.10.1:/srv/nfsroot ip=dhcp ro.
This approach gives you full control but no LDM, no centralized user management out of the box—add those yourself with LDAP or a shared home NFS mount.
Centralized User Accounts
Thin clients are only useful if users can log in from any machine. Options in order of complexity:
- Shared NFS home: export
/homefrom the server; mount it on clients (or LTSP handles this automatically). - LDAP with sssd: full directory service; required for larger deployments.
- Local accounts synced via Ansible: pragmatic for under 10 users.
Wayland Considerations
LTSP's LDM model runs the compositor on the server and uses SSH X11 forwarding—this is still X11 under the hood. Native Wayland remote display is not yet as seamless; Waypipe is the closest option for forwarding Wayland clients over SSH, but it is experimental for thin-client fleets. Stick with an X11 desktop session (XFCE, MATE, or GNOME in Xorg mode) for production thin clients today.
Verification
- Boot a client from the network (set NIC as first boot device in BIOS/UEFI).
- Watch it obtain a DHCP address and pull the bootloader via TFTP—the LTSP boot screen appears.
- Log in with a local or domain account; the session should open on the server and display on the client.
- On the server:
whoshould show the client's hostname;topshould show the session's CPU load on the server.
who
# ltspuser tty7 2024-11-01 09:14 (192.168.10.105)
Troubleshooting
- Client gets IP but TFTP times out: UDP port 69 blocked by firewall, or TFTP root path mismatch. Run
journalctl -u dnsmasq -fon the server and watch the request land. - Kernel boots but drops to initramfs: The squashfs image path in the iPXE config is wrong. Rebuild with
sudo ltsp ipxeafter any image change. - Login fails at LDM: SSH from the server back to itself as the target user first (
ssh localhost) to confirm PAM/account setup. - Screen resolution wrong: Set
HORIZONTAL_RESOLUTIONandVERTICAL_RESOLUTIONper-client using MAC-based sections inltsp.conf:[aa:bb:cc:dd:ee:ff]. - NFS root client hangs at boot: Check
no_root_squashis set in exports and that the NFS service is running (systemctl status nfs-server).
Frequently asked questions
- What is the difference between old LTSP 5 and modern LTSP?
- LTSP 5 used per-architecture chroots and a separate LDAP/NIS stack. Modern LTSP (2019+) builds squashfs images from the server's own root, uses standard SSH for encrypted display (LDM over SSH), and requires far less configuration. The two are not compatible; upgrade paths require a fresh server setup.
- Can thin clients run local applications instead of everything on the server?
- Yes. LTSP supports a 'local apps' mode where specific applications run on the client CPU but display through the server session. This is useful for multimedia or locally-attached hardware. Configure it per-application in ltsp.conf using the LOCALAPPS option.
- How many thin clients can one server realistically support?
- With lightweight desktops (XFCE, MATE) and typical office workloads, a 16-core server with 64 GB RAM can support 40–60 concurrent sessions. CPU-bound tasks like video decoding stress the server quickly; set realistic per-user resource limits with systemd slices or cgroups.
- Do thin clients need any local storage?
- No. The entire root filesystem is served over the network as a squashfs image or NFS export. Some deployments add a small local disk for swap when RAM is scarce, but it is not required. Diskless operation simplifies hardware procurement and replacement.
- Is Wayland supported for thin-client sessions?
- Not reliably in production yet. LTSP's LDM uses X11 forwarding over SSH. Waypipe can forward individual Wayland clients over SSH but is not stable enough for a full desktop fleet. Run GNOME, XFCE, or MATE in Xorg mode for thin clients until Wayland remote display matures.
Related guides
Configure Prometheus Alertmanager
Configure Prometheus Alertmanager with routing trees, receivers, inhibition rules, grouping, Go templates, and PagerDuty/Slack on-call integrations.
Build an Intranet Server on Linux
Set up a complete small-office intranet on one Linux box: Nginx web server, dnsmasq local DNS, Samba file sharing, and a Wiki.js team wiki.
Build an nftables Firewall Script
Build a complete nftables firewall from scratch: tables, chains, sets, default-deny input policy, service allowlisting, and persistent systemd configuration.
Caddy as a Reverse Proxy
Set up Caddy as a reverse proxy with automatic HTTPS, load balancing, WebSocket passthrough, reusable snippets, and header control — no certbot required.