Table of Contents

X2Go-ThinClientEditon-Live (TCE-Live, formerly known as TCE-NG)

If you are looking for installation instructions for the classic, NFS-filesystem-based X2Go-ThinClient, please go here

History, Rationale, Outlook

During the time of Debian Wheezy being Debian's stable release, we started developing a new ThinClientEdition then called TCE-Next Generation, or TCE-NG for short - one that is based on Debian-Live and thus does no longer rely on NFS (though NFS can still be used to deploy the image - but we do not recommend that approach). Instead, the entire image is loaded into the RAM of the ThinClient machine. To avoid confusion, and because it has since left the “NG” state, we now call it TCE-Live.

The disadvantage is that your ThinClient now needs at least 512 MB to 1 GB of RAM (see below). Working with 256 MB is possible when you use local storage instead of netbooting (don't use the toram parameter, either), but not really recommended.

However, the huge advantage is that there no longer is a need for any high-availibility setup concerning NFS (nor HTTP/HTTPS/FTP). If you follow our advice of loading the entire image into the ThinClient's RAM, or using local storage, all you need is an HTTP (HTTPS optional for later stages) or FTP server with a dedicated IP, if you want to use netbooting. It is also possible to deploy the image to the ThinClient's local storage, if present, and have it update in the background.

Besides, making changes to/updating the classic, NFS-based TCE (henceforth referred to as TCE-Classic) with the entire filesystem, not just its compressed image, spread out over the NFS share was rather finicky - with the current TCE-Live, you build and deploy a new image every time you make a change, and you can test it on a single client without interrupting your production environment. The local storage feature can also be used to create a portable version of both X2Go-TCE and X2GoClient for Windows, sharing the same configuration, on CD/DVD/USB media.

We've also received reports that TCE-Classic wouldn't work with Jessie, or at least it was very hard to get it to work. Our TCE-Live works just fine with Jessie, Stretch, and Buster as well.

ThinClient prerequisites for all TCE-Live variants

Build system prerequisites for all variants

Building your own X2Go-TCE Image

Configuring the Build

Change to a directory where you want to save your builds, and save the following file as x2go-tce-config:

# NOTE: This file gets sourced by the actual buildscript - so place it in the same directory as the buildscript or adjust the path in the buildscript.

# simple check for apt-cacher-ng being active - if
# we have a successful connect on port 3142, assume
# it's apt-cacher-ng and use it
#
if nc -z 127.0.0.1 3142 ; then 
    # bad idea with apt-cacher-ng, but will work with e.g. squid
    # export https_proxy=http://127.0.0.1:3128/ 
    # export http_proxy=http://127.0.0.1:3128/
    # export ftp_proxy=http://127.0.0.1:3128/

    export LB_APT_FTP_PROXY=http://127.0.0.1:3142/
    export LB_APT_HTTP_PROXY=http://127.0.0.1:3142/
fi

# set these to true to save source files
#export LB_SOURCE="true"
#export LBX2GO_GETSRC="true"

# Select ONE of the following git reposities
# this one loosely corresponds to "stable"
#export LBX2GO_CONFIG='https://gitlab.x2go.org/x2go/live-build-x2go.git::feature/openbox-magic-pixel-workaround-buster'
#export LBX2GO_CONFIG='https://gitlab.x2go.org/x2go/live-build-x2go.git::feature/mate-minidesktop-buster'
export LBX2GO_CONFIG='https://gitlab.x2go.org/x2go/live-build-x2go.git::feature/openbox-magic-pixel-workaround-bullseye'
#export LBX2GO_CONFIG='https://gitlab.x2go.org/x2go/live-build-x2go.git::feature/mate-minidesktop-bullseye'
#export LBX2GO_CONFIG='https://github.com/bauritcs/live-build-x2go.git::feature/openbox-magic-pixel-workaround-bookworm'
#export LBX2GO_CONFIG='https://github.com/bauritcs/live-build-x2go.git::feature/mate-minidesktop-bookworm'
# NOTES: 1) https://github.com/bauritcs loosely corresponds to "heuler"
#        2) Minidesktop builds are work in progress and not production-ready. Cont(r)act us if you need them; feel free to submit patches.
#        3) Add "-stretch" to the end of the LBX2GO_CONFIG string to create a stretch build,
#           add "-buster" to the end of the LBX2GO_CONFIG string to create a buster build,
#           add "-bullseye" to the end of the LBX2GO_CONFIG string to create a bullseye build
#           add "-bookworm" to the end of the LBX2GO_CONFIG string to create a bookworm build (will be in gitlab repo $SOON - use github.com/bauritcs for now)

# Select ONE of the following LBX2GO_ARCH lines and comment out the others
# (feel free to use long or short options)
# for 64-Bit builds, use:
export LBX2GO_ARCH='-a amd64 -k amd64'
# 32-Bit, larger memory footprint, but faster performance on i686 and newer
#export LBX2GO_ARCH='-a i386 -k 686-pae'
# 32-Bit, smallest memory footprint - not available on buster
# export LBX2GO_ARCH='--architectures i386 --linux-flavours 586'
# For ARM (Raspberry Pi):
#export LBX2GO_ARCH='-a arm64'
#export LBX2GO_ARCH_MODEL='Pi4' # you can also set this to 'Pi3'. Note that there must not be any whitespace between 'Pi' and the digit.

# If you want to use the stock ISO image as created by this script, add your boot parameters here
# export LBX2GO_BOOTAPPEND_LIVE="boot=live components noswap lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 silent quiet pubkey=http://x2go/x2go-tce/config/authorized_keys sessionsurl=http://x2go/x2go-tce/config/sessions toram"
export LBX2GO_BOOTAPPEND_LIVE="boot=live components noswap lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 silent quiet sessionsurl=https://x2go.baur-itcs.de/.config/x2go-demo/config/sessions pubkey=https://x2go.baur-itcs.de/.config/x2go-demo/config/authorized_keys toram "

if echo -e "$LBX2GO_CONFIG" | grep -q "openbox"; then
	LBX2GO_BOOTAPPEND_LIVE+="fastpo "
	export LBX2GO_BOOTAPPEND_LIVE
elif echo -e "$LBX2GO_CONFIG" | grep -q "minidesktop"; then
	LBX2GO_BOOTAPPEND_LIVE+='timezone=Europe/Berlin noautologin ' # if you use nottyautologin instead of noautologin, an autologin will be set for the account "user", which conflicts our setting for the account "x2gothinclient"
	export LBX2GO_BOOTAPPEND_LIVE
fi

# detect if the selected git repo is meant to build a buster, stretch or jessie image
if [ -z "${LBX2GO_CONFIG##*-stretch}" ] ; then
    export LBX2GO_DEBVERSION="stretch"
    export LBX2GO_BOOTAPPEND_LIVE+=" net.ifnames=0 biosdevname=0"
elif [ -z "${LBX2GO_CONFIG##*-buster-heuler}" ] ; then
    export LBX2GO_DEBVERSION="buster"
    export LBX2GO_BOOTAPPEND_LIVE+=" net.ifnames=0 biosdevname=0"
elif [ -z "${LBX2GO_CONFIG##*-buster-heuler-bpo}" ] ; then
    export LBX2GO_DEBVERSION="buster"
    export LBX2GO_BOOTAPPEND_LIVE+=" net.ifnames=0 biosdevname=0"
elif [ -z "${LBX2GO_CONFIG##*-buster}" ] ; then
    export LBX2GO_DEBVERSION="buster"
    export LBX2GO_BOOTAPPEND_LIVE+=" net.ifnames=0 biosdevname=0"
elif [ -z "${LBX2GO_CONFIG##*-bullseye}" ] ; then
    export LBX2GO_DEBVERSION="bullseye"
    export LBX2GO_BOOTAPPEND_LIVE+=" net.ifnames=0 biosdevname=0"
elif [ -z "${LBX2GO_CONFIG##*-bookworm}" ] ; then
    export LBX2GO_DEBVERSION="bookworm"
    export LBX2GO_BOOTAPPEND_LIVE+=" net.ifnames=0 biosdevname=0"
    export LBX2GO_ARCHIVE_AREAS="non-free-firmware "
else
    export LBX2GO_DEBVERSION="jessie"
fi

# newer versions of live-build use the plural form of this parameter
if $(LANG=C lb config --help | grep -q bootloaders) ; then
    export LBX2GO_BOOTLOADERPARAMNAME="--bootloaders"
else
    export LBX2GO_BOOTLOADERPARAMNAME="--bootloader"
fi

# set boot loader type - leave this unchanged unless you really know what you're doing
if echo $LBX2GO_ARCH | awk '{print $2}' | grep -q "arm" ; then
    # This is part of our experimental ARM support
    LBX2GO_BOOTLOADERPARAMNAME=" "
    LBX2GO_BOOTLOADER=" "
else
    export LBX2GO_BOOTLOADER="syslinux"
fi

# These options are meant to reduce the image size.
# Feel free to adapt them after consulting "man lb_config"
# FIXME export LBX2GO_SPACE='--apt-indices none
export LBX2GO_SPACE='--apt-indices false
                     --apt-recommends false
                     --cache false
                     --checksums none
                     --firmware-binary false
                     --memtest none
                     --win32-loader false'

# fixing some peculiarities for Ubuntu here
if $(lsb_release -i | grep -i ubuntu -q ) ; then
        [ -f /usr/lib/live/build/binary_rootfs ] || ln -s /usr/lib/live/build/lb_binary_rootfs /usr/lib/live/build/binary_rootfs
        export LBX2GO_MIRROR="  -m http://deb.debian.org/debian
                                --mirror-chroot-security http://security.debian.org/debian/
                                --mirror-binary-security http://security.debian.org/debian/
                                --parent-mirror-chroot-security http://security.debian.org/debian/
                                --parent-mirror-binary-security http://security.debian.org/debian/"
else
        export LBX2GO_UPDATES="--updates true"
fi

# These are default values that should not require tuning
export LBX2GO_DEFAULTS="--backports true
                        --firmware-chroot true
                        --initsystem sysvinit
                        --security true
                        $LBX2GO_UPDATES
                        $LBX2GO_MIRROR
                        $LBX2GO_BOOTLOADERPARAMNAME $LBX2GO_BOOTLOADER
                        --distribution $LBX2GO_DEBVERSION"

# This is part of our experimental ARM support
if echo $LBX2GO_ARCH | grep -q 'arm' && ! dpkg --print-architecture | grep -q 'arm' ; then
    export LBX2GO_DEFAULTS+=" --bootstrap-qemu-arch arm64 \
                              --bootstrap-qemu-static /usr/bin/qemu-aarch64-static \
                              --apt-options \"--yes -oAPT::Default-Release=${LBX2GO_DEBVERSION} -oAPT::Immediate-Configure=false\" "
fi

# This is part of our experimental ARM support
# This makes sure the resulting disk image is at least 1GB in size, even though our build currently requires way less.
# It's unlikely that anyone will need to boot from a smaller partition; but if we let live-build pick the minimum size automatically,
# we will not have enough space left to copy the firmware blobs into the right location.
if echo $LBX2GO_ARCH | grep -q 'arm' ; then
    export LBX2GO_DEFAULTS+=" --binary-filesystem fat32 \
                              --hdd-size 1024"
fi

export LBX2GO_ARCHIVE_AREAS="main contrib non-free $LBX2GO_ARCHIVE_AREAS"

# This is for minidesktop builds and currently only adds firefox-esr language packs
# export LBX2GO_LANG='de'

# This is to optimize squashfs size, based on a suggestion by intrigeri from the TAILS team
# note that this will permanently change /usr/lib/live/build/binary_rootfs
#
#
if dpkg --print-architecture | grep -q 'arm'; then
	# on arm, these parameters must not be used; if they're there, we need to reinstall the package to undo our patch
	if grep -q -- '-Xbcj x86 -b 1024K -Xdict-size 1024K' /usr/lib/live/build/binary_rootfs; then
		apt install --reinstall live-build
	fi
	# feel free to experiment with these options, but be prepared for subtle breakage 
	#export MKSQUASHFS_OPTIONS=' -Xbcj arm '
	#export MKSQUASHFS_OPTIONS=' -b 1024K -Xdict-size 1024K '
	#export MKSQUASHFS_OPTIONS=' -Xbcj arm -b 1024K -Xdict-size 1024K '
	export MKSQUASHFS_OPTIONS=''
else
	export MKSQUASHFS_OPTIONS=' -Xbcj x86 -b 1024K -Xdict-size 1024K '
fi

# This removes documentation, locales and man pages
# You can safely enable this if you intend to run X2GoClient in fullscreen mode all the time, or when building the ssh-only rescue image.
# For all other uses of the TCE-Live image creator (i.e. Minidesktop), your results may vary ... use at your own risk.
export LBX2GO_TCE_SHRINK="true"

# This patches the squashfs file into the initrd. Only parsed when image type "netboot" is set.
# Will require boot parameter live-media=/ instead of fetch=...
# Both TFTP client and TFTP server must support file transfers >32MB for this to work, if you want to deploy this initrd via TFTP, 
# so e.g. atftpd will not work - tftpd-hpa, however, seems to have no problem with larger files.
# When using iPXE, you can use http instead of TFTP.
# This is especially helpful if you want to netboot via http and cannot use the server's IP, but must specify a DNS name - as "fetch=..." only understands IPs.
#export LBX2GO_NOSQUASHFS="true"

# Select ONE of the following LBX2GO_IMAGETYPE lines and comment out the others
# to create an iso image:
#export LBX2GO_IMAGETYPE='iso'
# to create an iso image that can also be dd'ed to USB media:
export LBX2GO_IMAGETYPE='iso-hybrid'
# to create a netboot-image:
#export LBX2GO_IMAGETYPE='netboot'
# /!\ the options below are NOT RECOMMENDED unless you use live-build from Debian Buster /!\
# (Debian 10) or newer to create an image that can be written to a hard disk (for older 
# live-build versions, this always results in a "build failed" message, even though the build
# might have worked - use live-build from Buster or newer and things will work):
#export LBX2GO_IMAGETYPE='hdd'
## This might be required for hdd builds, especially for (u)efi
#export LBX2GO_BOOTLOADER="syslinux grub-pc grub-efi"
# to create a tar file only (seems to be broken in older live-build versions - Buster works):
#export LBX2GO_IMAGETYPE='tar'

# This is part of our experimental ARM support
if echo "$LBX2GO_ARCH" | grep -q "arm" ; then
	# enforce hdd image for arm at the moment (might need to support netboot later on too)
	if ! [ "$LBX2GO_IMAGETYPE" = "hdd" ] ; then
	        echo "WARNING: Replacing selected image type with 'hdd'.  That's all we currently support on ARM."
		export LBX2GO_IMAGETYPE="hdd"
	fi
fi

if [ "$LBX2GO_IMAGETYPE" = "netboot" ]; then
        export LBX2GO_DEFAULTS+=" $LBX2GO_BOOTLOADER"
fi

Live-Patching the Build

To add patches that aren't part of any package yet, you can use the directory ./patch/ for patches that should be added to all versions, and ./patch-minidesktop/ for patches that should only be added to the MATE-MiniDesktop Edition.

You will need to create a directory structure like

./patch/includes.chroot/etc/

to create/overwrite a file in

/etc/

within the live environment.

e.g. to override

/etc/x2go/x2gothinclient-minidesktop_start

with a custom version, run

mkdir -p ./patch-minidesktop/includes.chroot/etc/x2go/

and save the following file as

./patch-minidesktop/includes.chroot/etc/x2go/x2gothinclient-minidesktop_start
#!/bin/bash

# Copyright (C) 2010-2024 by X2Go project, https://wiki.x2go.org
#       Oleksandr Shneyder <o.shneyder@phoca-gmbh.de>
#       Moritz 'Morty' Struebe <Moritz.Struebe@informatik.uni-erlangen.de>
#       Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
#       Stefan Baur <X2Go-ML-1@baur-itcs.de>
#
# X2Go is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# X2Go is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

# make sure pulseaudio can be reached via TCP from the X2Go Server side...
if ! /usr/bin/pactl list modules | grep -A1 'module-native-protocol-tcp' | grep -q 'auth-ip-acl=127.0.0.1;::1' ; then
        /usr/bin/pactl 'load-module' 'module-native-protocol-tcp' 'auth-ip-acl=127.0.0.1;::1'
fi

# make sure we don't start before sessions and settings files exist - avoids race conditions
while ! [ -e ~x2gothinclient/.x2goclient/sessions ] ; do
        sleep 1;
done

while ! [ -e ~x2gothinclient/.x2goclient/settings ]; do
        sleep 1
done

[ -s /etc/x2go/x2gothinclient_bg.svg ] && X2GO_BG='--background="/etc/x2go/x2gothinclient_bg.svg'
[ -s /etc/x2go/x2gothinclient_branding.svg ] && X2GO_BRAND='--branding="/etc/x2go/x2gothinclient_branding.svg'


/usr/lib/x2go/x2goclient --no-menu \
                         $X2GO_BG \
                         $X2GO_BRAND \
                         --kbd-type=auto \
                         --set-kbd=1 \
                         --tray-icon \
                         --read-exports-from=~/export \
                         --no-session-edit \
                         --add-to-known-hosts \
                         &

Starting the Build

In the directory where you want to save your builds, save the following file as x2go-tce-build, and run it (e.g. via sudo bash ./x2go-tce-build):

#!/bin/bash

# read (source) the config file
. ./x2go-tce-config

# Create Timestamp
LBX2GO_TIMESTAMP=$(date +"%Y%m%d%H%M%S")

# Log all output to a logfile in /tmp
exec > >(tee "/tmp/$LBX2GO_TIMESTAMP.log") 2>&1

# Set Directory name
LBX2GO_TCEDIR="./live-build-x2go-${LBX2GO_TIMESTAMP}-${LBX2GO_IMAGETYPE}-$(echo $LBX2GO_ARCH | awk '{print $2}')-${LBX2GO_CONFIG##*/}"

if [ -z "$LBX2GO_ARCH" ] ||
	( echo "$LBX2GO_ARCH" | grep -q "arm" && [ -z "$LBX2GO_ARCH_MODEL" ] ) || 
   [ -z "$LBX2GO_SPACE" ] ||
   [ -z "$LBX2GO_CONFIG" ] ||
   [ -z "$LBX2GO_DEFAULTS" ] ||
   [ -z "$LBX2GO_DEBVERSION" ] ||
   [ -z "$LBX2GO_IMAGETYPE" ] ||
   [ -z "$LBX2GO_TIMESTAMP" ] ||
   [ -z "$LBX2GO_BOOTLOADERPARAMNAME" ] ||
   [ -z "$LBX2GO_BOOTLOADER" ] ||
   [ -z "$LBX2GO_ARCHIVE_AREAS" ]; then
    echo -e "One or more of the following variables is unset:"
    echo -e "LBX2GO_ARCH: '${LBX2GO_ARCH}'"
    echo "$LBX2GO_ARCH" | grep -q "arm" && echo -e "LBX2GO_ARCH_MODEL: '${LBX2GO_ARCH_MODEL}'"
    echo -e "LBX2GO_SPACE: '${LBX2GO_SPACE}'"
    echo -e "LBX2GO_DEFAULTS: '${LBX2GO_DEFAULTS}'"
    echo -e "LBX2GO_DEBVERSION: '${LBX2GO_DEBVERSION}'"
    echo -e "LBX2GO_CONFIG: '${LBX2GO_CONFIG}'"
    echo -e "LBX2GO_IMAGETYPE: '${LBX2GO_IMAGETYPE}'"
    echo -e "LBX2GO_TIMESTAMP: '${LBX2GO_TIMESTAMP}'"
    echo -e "LBX2GO_BOOTLOADERPARAMNAME: '${LBX2GO_BOOTLOADERPARAMNAME}'"
    echo -e "LBX2GO_BOOTLOADER: '${LBX2GO_BOOTLOADER}'"
    echo -e "LBX2GO_ARCHIVE_AREAS: '${LBX2GO_ARCHIVE_AREAS}'"
    echo -e "Please visit http://wiki.x2go.org/doku.php/doc:howto:tce"
    echo -e "and read up on the general prerequisites for X2Go-TCE"
else
    # This will create a timestamped subdirectory for the build
    mkdir -p $LBX2GO_TCEDIR
    cd $LBX2GO_TCEDIR

    X2GO_LBCONFIG_STRING=$(cat <<X2GOLBCONFIGSTRING
    lb config $LBX2GO_ARCH $LBX2GO_SPACE $LBX2GO_DEFAULTS \
       --config $LBX2GO_CONFIG --binary-images $LBX2GO_IMAGETYPE \
       --archive-areas "$LBX2GO_ARCHIVE_AREAS" \
       --bootappend-live "$LBX2GO_BOOTAPPEND_LIVE"
X2GOLBCONFIGSTRING
)
    # Our previous way of doing this had issues with newlines and multiple blanks. So we're now doing a bit
    # of sanitizing, then we eval the variable.
    X2GO_LBCONFIG_STRING=$(echo "$X2GO_LBCONFIG_STRING" | tr '\n' ' ' | tr -s ' ')
    eval "$X2GO_LBCONFIG_STRING"

    # This will copy any patches we have prepared
    if [ -d "../patch" ] ; then
        cp -a ../patch/* config/
    fi

    # This will copy any patches we have prepared for minidesktop
    if [ -d "../patch-minidesktop" ] && (echo "$LBX2GO_CONFIG" | grep -q minidesktop) ; then
        cp -a ../patch-minidesktop/* config/
    fi

    # This checks if a bootloader directory is present (e.g. because of a custom splash.svg)
    # and adds all other files that might be missing (live-build won't add them automatically
    # if the directory already exists)
    if [ -d config/bootloaders ] ; then
        rsync -aPH --ignore-existing --exclude="splash.svg" /usr/share/live/build/bootloaders/* config/bootloaders
    fi
    # When enabled, this silences the audible beep at syslinux/isolinux/pxelinux/extlinux startup.
    # Note that this is an accessibility feature for blind users, so use with care.
    sed -e "s/$(echo -e "\07")//g" -i config/bootloaders/*/menu.cfg

    # This enables an i386-only package in the sources.list file when an i386 build is requested
    if echo $LBX2GO_ARCH | grep -q -i "i386" ; then
        sed -i -e 's/# for i386 only #//' config/package-lists/desktop.list.chroot
    fi

    # This is part of our experimental ARM support
    # It adds required arm64-only packages when an arm64 build is requested
    if echo $LBX2GO_ARCH | grep -q "arm" ; then

	# bullseye and newer do not need this
    	if [ "${LBX2GO_DEBVERSION}" = "buster" ]; then 
		# firmware for wifi 
		echo "firmware-brcm80211/buster-backports" >>config/package-lists/raspi.list.chroot
	fi

	if [ "$LBX2GO_ARCH_MODEL" = "Pi3" ] ; then
		# modules required for Raspberry Pi 3 LAN
		echo "crc16" >> config/includes.chroot/etc/initramfs-tools/modules
		echo "mii" >> config/includes.chroot/etc/initramfs-tools/modules
		echo "smsc95xx" >> config/includes.chroot/etc/initramfs-tools/modules
		echo "usbcore" >> config/includes.chroot/etc/initramfs-tools/modules
		echo "usbnet" >> config/includes.chroot/etc/initramfs-tools/modules
		echo "fake-hwclock" >>config/package-lists/raspi.list.chroot
		echo "usbutils" >>config/package-lists/raspi.list.chroot

		# firmware for basic raspi functions - required for boot on Pi3
		echo "raspi3-firmware/buster" >>config/package-lists/raspi.list.chroot
		# standard linux kernel - for Pi3
		echo "linux-image-arm64/buster" >>config/package-lists/raspi.list.chroot

	elif [ "$LBX2GO_ARCH_MODEL" = "Pi4" ] ; then
		# bullseye and newer do not need this
		if [ "${LBX2GO_DEBVERSION}" = "buster" ]; then
			# firmware for basic raspi functions - required for boot on Pi4
			echo "raspi3-firmware/buster-backports" >>config/package-lists/raspi.list.chroot
			echo "raspi-firmware/buster-backports" >>config/package-lists/raspi.list.chroot

			# newer linux kernel - required for pi4/pi400
			echo "linux-image-arm64/buster-backports" >>config/package-lists/raspi.list.chroot
		fi
	else
		echo "WARNING: ARM Platform selected, but unknown model: '$LBX2GO_ARCH_MODEL'. Assuming no additional packages/patches are required."
	fi
    fi
 

    # This is for minidesktop builds only
    if [ -f config/package-lists/firefox-langpacks.list.chroot ]; then
            if [ -n "$LBX2GO_LANG" ]; then
                    for LBX2GO_SINGLE_LANG in $(echo "$LBX2GO_LANG" | tr ';' ' '); do
                            echo "LANG: '$LBX2GO_SINGLE_LANG'"
                            sed -i -e 's/#firefox-esr-l10n-'$LBX2GO_SINGLE_LANG'$/firefox-esr-l10n-'$LBX2GO_SINGLE_LANG'/' config/package-lists/firefox-langpacks.list.chroot
                    done
            else
                    rm config/package-lists/firefox-langpacks.list.chroot
            fi
    fi
    if [ "$LBX2GO_TCE_SHRINK" = "true" ] ; then
        echo '#!/bin/sh' >./config/hooks/0112-remove-folders.hook.chroot
        echo 'set -e' >>./config/hooks/0112-remove-folders.hook.chroot
        echo '# Remove folders' >>./config/hooks/0112-remove-folders.hook.chroot
        echo 'rm -rf ./usr/share/doc/*' >>./config/hooks/0112-remove-folders.hook.chroot
        echo 'rm -rf ./usr/share/locale/*' >>./config/hooks/0112-remove-folders.hook.chroot
        echo 'rm -rf ./usr/share/man/*' >>./config/hooks/0112-remove-folders.hook.chroot
        [ "$LBX2GO_IMAGETYPE" != "netboot" ] && echo 'rm -rf ./var/lib/apt/lists/*' >>./config/hooks/0112-remove-folders.hook.chroot
        chmod 755 ./config/hooks/0112-remove-folders.hook.chroot
    fi

    if [ -n "$LB_APT_HTTP_PROXY" ] || [ -n "$LB_APT_FTP_PROXY" ]; then
        echo "NOTICE: apt proxy variable(s) is/are set."
        echo "NOTICE: Trying to use the proxy for all downloads."
        echo "NOTICE: If this fails, look for #SETPROXY in the $0 source."
        # Here, we should have reached a point where it is safe to point all proxy variables
        # at the apt-cacher-ng proxy.  If you're seeing errors during your build that hint
        # at files not being downloaded, disable these three entries.
        export https_proxy=$LB_APT_HTTP_PROXY
	export http_proxy=$LB_APT_HTTP_PROXY
        export ftp_proxy=$LB_APT_FTP_PROXY
    fi

    # This is part of our experimental ARM support
    # It is used when building for the ARM architecture (on Intel/AMD hardware and on ARM).
    # It makes some necessary changes, and also tries to speed up squashfs creation when it 
    # detects a crossbuild environment.
    if echo $LBX2GO_ARCH | grep -q 'arm'; then

        # This command removes all references to fuseext, freerdp-nightly, and x2gothinclient from the
        # package list files.  Currently needed as there are no ARM packages for any of these.
        echo "WARNING: Removing all references to fuseext,freerdp-nightly and x2gothinclient from the build."
        sed -e 's/^.*fuseext.*$//g' -e 's/^.*freerdp-nightly.*$//g' -e 's/^.*x2gothinclient.*$//g' -i ./config/package-lists/*

	# This command removes the X2Go repository from the directory where additional
        # archives are stored.  Currently needed as the X2Go repository offers no arm64 
        # packages, but Debian Buster does - so that's what we're falling back to.
        echo "WARNING: Removing all references to the X2Go repository from the build."
        rm ./config/archives/*x2go*

	# The following is a hack to reduce squashfs creation time in a crossbuild environment.
	# We're replacing mksquashfs in the changeroot with a wrapper script that drops the 
	# original mksquashfs call into a file.

	if (uname -r | grep -q 'i.86' || uname -r | grep -q 'amd64') ; then
		# We need to do this as a background task, waiting for the mksquashfs executable to
		# appear in the changeroot; as the changeroot will only be created later on, once
		# lb build is called.
			
		# The other background task waits until the command file has been created, then
		# it applies some necessary patches to it, and starts the mksquashfs command natively
		# on the build host, rather than in the changeroot environment.
		# This is because in the changeroot, we'd be running the ARM mksquashfs in a qemu
		# software emulation of the ARM architecture, while on the host, we can use all the
		# native, raw CPU power and cores available to us.

		# To make sure we don't have any lingering processes in the background, we're passing
		# our own PID along to the background tasks, and tell them to terminate if our PID
		# disappears while they're still in their waiting/looping state.

		MASTERPID=$$

		# Replace mksquashfs in chroot with script
		# (script will undo this upon completion)
		(
		    # wait until the chroot has been populated or until our parent process dies
		    while ! [ -x ./chroot/usr/bin/mksquashfs ]; do
			ps $MASTERPID >/dev/null || exit 1
			sleep 1
		    done
		    # make sure we don't overwrite the real executable if it has already been
		    # moved out of the way
		    if ! [ -x ./chroot/usr/bin/mksquashfs.real ]; then
			cp ./chroot/usr/bin/mksquashfs ./chroot/usr/bin/mksquashfs.real
		    fi
		   echo '#!/bin/bash' >./chroot/usr/bin/mksquashfs
		   # log the name we've been called with and all parameters into this file
		   echo 'echo "$0 $@" >/tmp/filesystem.squashfs.temp' >>./chroot/usr/bin/mksquashfs
		   # once the native mksquashfs is complete, we will remove this file
		   echo 'while [ -f /tmp/filesystem.squashfs.temp ]; do' >>./chroot/usr/bin/mksquashfs
		   echo '        sleep 1' >>./chroot/usr/bin/mksquashfs
		   echo 'done' >>./chroot/usr/bin/mksquashfs
		   # so let's wait until it has been removed before deleting ourselves ...
		   echo 'rm /usr/bin/mksquashfs' >>./chroot/usr/bin/mksquashfs
		   # ... and moving the real executable back into its place
		   echo 'mv /usr/bin/mksquashfs.real /usr/bin/mksquashfs' >>./chroot/usr/bin/mksquashfs
		   chmod 755 ./chroot/usr/bin/mksquashfs
		) &

		# start the native mksquashfs after patching the parameters
		(
		    # wait until the trigger file has been created or until our parent process dies
		    while ! [ -f ./chroot/tmp/filesystem.squashfs.temp ]; do
			ps $MASTERPID >/dev/null || exit 1
			sleep 1
		    done
		    # using any of the available filters (x86, arm, armthumb) for the 
		    # -Xbcj command results in an unusable squashfs on arm, so we drop the 
		    # parameter completely if it's there.
		    # also, all absolute paths (detected by beginning with " /") need to be
		    # prefixed with "./chroot" so the mksquashfs outside the chroot knows where
		    # to look for the corresponding paths/files.
		    sed -e 's/ -Xbcj x86/ /g' -e 's# /# ./chroot/#g' -i \
			./chroot/tmp/filesystem.squashfs.temp
		    #needs switch from e.g. /bin/mksquashfs to $(which mksquashfs)
		    sed -e "s#^.*mksquashfs#$(which mksquashfs)#g" -i \
			./chroot/tmp/filesystem.squashfs.temp
		    # now let's make this executable
		    chmod 755 ./chroot/tmp/filesystem.squashfs.temp

		    # we also need to add some more excludes because they shouldn't end up
		    # in the squashfs - no idea why we don't need them while inside the chroot ...
		    echo 'proc/*' >>./chroot/excludes
		    echo 'sys/*' >>./chroot/excludes
		    echo 'dev/pts/*' >>/.chroot.excludes
		    # now let's execute the script and, if it terminates without an error,
		    # we'll move the newly created squashfs into the chroot where the chrooted
		    # mksquashfs command would have created it; if that worked as well, we'll
		    # remove the script file so our dummy mksquashfs inside the chroot knows
		    # it's time to terminate itself.
		    ./chroot/tmp/filesystem.squashfs.temp && \
		    mv ./filesystem.squashfs ./chroot/ && \
		    rm ./chroot/tmp/filesystem.squashfs.temp
		) &
	fi
    fi

    if lb build ; then
        echo -e "Build is done: '$LBX2GO_TCEDIR'"
        ln $(realpath ./chroot/vmlinuz) ./x2go-tce-vmlinuz
        ln $(realpath ./chroot/initrd.img) ./x2go-tce-initrd.img
        ln ./binary/live/filesystem.squashfs ./x2go-tce-filesystem.squashfs

        if [ "$LBX2GO_IMAGETYPE" = "hdd" ] ; then
                ln ./live-image-$(echo $LBX2GO_ARCH | awk '{print $2}').img \
                   ./x2go-tce-live-image-$(echo $LBX2GO_ARCH | awk '{print $2}').img
        fi

        # This is part of our experimental ARM support
        if [ "$LBX2GO_IMAGETYPE" = "hdd" ] && echo $LBX2GO_ARCH | grep -q "arm" ; then
		# after the build, let's determine the name of our image file ...
		IMAGEFILE="./x2go-tce-live-image-$(echo $LBX2GO_ARCH | awk '{print $2}').img"

		# ... and change the partition type to reflect the file system actually in use for partition 1
		# ("b" is FAT32)
		sfdisk --part-type $IMAGEFILE 1 b

		# next, we need to patch two things inside the image, so we need to set up a loop device for it.
		FREELOOP=$(losetup -f) # note that this could become a TOCTOU issue if more than 1 process tries to use loop devices

		# as the image is a full disk image containing a partition, we need to jump to the position where the first partition starts
		losetup -o 1048576 $FREELOOP $IMAGEFILE

		# now let's mount it
		mkdir -p ./tempmount
		mount $FREELOOP ./tempmount

		# purge this dir, so we have enough space; we'll return to fill it later
		rm ./tempmount/live/*

		# first, we copy the contents of the boot/firmware/ folder to the root directory, because that is where these files are needed
		# see if inplace helps against out of space errors
		rsync -aP --inplace ./chroot/boot/firmware/* ./tempmount

		mkdir -p ./tempmount/live/
		rsync -aP ./binary/live/*.squashfs ./tempmount/live/

		# next, we replace the "root=" parameter with the parameters needed for live-booting
		sed -e 's#root=/dev/mmcblk0p2 #'"$LBX2GO_BOOTAPPEND_LIVE"' #' -i ./tempmount/cmdline.txt

		# here comes the cleanup part
		sync
		umount $FREELOOP
		losetup -d $FREELOOP
		rmdir ./tempmount
	fi

        if [ "$LBX2GO_IMAGETYPE" = "netboot" ] ; then
            if [ "$LBX2GO_NOSQUASHFS" = "true" ] ; then
                (cd binary; echo live$'\n'live/filesystem.squashfs |cpio -o -H newc | gzip --fast) >./x2go-tce-filesystem.cpio.gz
                cat ./x2go-tce-initrd.img ./x2go-tce-filesystem.cpio.gz >./x2go-tce-initrd-with-fs.img || exit 1
                rm ./x2go-tce-filesystem.cpio.gz
                # keeping these doesn't hurt, but feel free to rm them as well
                # rm ./x2go-tce-filesystem.squashfs ./x2go-tce-initrd.img
            fi
        fi
        if [ "$LBX2GO_IMAGETYPE" = "iso" ] || [ "$LBX2GO_IMAGETYPE" = "iso-hybrid" ] ; then
            genisoimage -o ./x2go-tce-squashfs-only.iso -R -J -graft-points live/filesystem.squashfs=./x2go-tce-filesystem.squashfs
            if [ -e ./live-image-$(echo $LBX2GO_ARCH | awk '{print $2}').hybrid.iso ] ; then
                    ln ./live-image-$(echo $LBX2GO_ARCH | awk '{print $2}').hybrid.iso \
                       ./original-x2go-tce-live-image-$(echo $LBX2GO_ARCH | awk '{print $2}').hybrid.iso
            elif [ -e ./live-image-$(echo $LBX2GO_ARCH | awk '{print $2}').iso ] ; then
                    ln ./live-image-$(echo $LBX2GO_ARCH | awk '{print $2}').iso \
                       ./original-x2go-tce-live-image-$(echo $LBX2GO_ARCH | awk '{print $2}').iso
            fi
            mv ./x2go-tce-filesystem.squashfs ./original-x2go-tce-filesystem.squashfs
        fi
        # create timestamp file
        stat -c %Y ./config/includes.chroot/lib >./x2go-tce-timestamp
        touch -m -d @$(cat x2go-tce-timestamp) x2go-tce-timestamp
        if [ "$LBX2GO_GETSRC" = "true" ] ; then
                if lb source debian ;
                then
                        echo -e "Source files have been downloaded: '$LBX2GO_TCEDIR'"
                else
                        echo -e "Source download failed: '$LBX2GO_TCEDIR'"
                fi
        else
                lb clean
                rm -rf ./cache
        fi
    else
        echo -e "Build failed: '$LBX2GO_TCEDIR'"
        if [ "$LBX2GO_IMAGETYPE" = "hdd" ] ; then
                echo "Looks like you tried to build an hdd image."
                echo "Older (pre-Debian-Buster) releases of live-build show a harmless error during"
                echo "the build, that can be safely ignored - but will still get you a 'Build failed'"
                echo "message in turn. So if you're running an older Debian release, you might want to"
                echo "look at the content of your build directory - maybe your build was successful"
                echo "after all, and this script was merely unable to detect it (computers are dumb)."
        fi
    fi
    cd ..
fi

Netbooting

Prerequisites

Setting up your own netbootable X2Go-TCE environment

Adding the X2Go-TCE files to your Boot and Web Server(s)

This is assuming you already have an existing, working PXE/TFTP and HTTP (with optional HTTPS) or FTP server setup.

Once you see the message “Build is done:”, go to the directory mentioned there, and copy x2go-tce-vmlinuz and x2go-tce-initrd.img to a suitable subdirectory under your TFTP root.

We suggest using ./x2go-tce.

To verify that both your installation in general and the newly copied files are reachable via TFTP, use a TFTP client - we suggest atftp - and perform these steps:
 cd $(mktemp -d)
 atftp your-tftp-server-ip-here
 tftp> get pxelinux.cfg/default
 tftp> get x2go-tce/x2go-tce-vmlinuz 
 tftp> get x2go-tce/x2go-tce-initrd.img 
 tftp> quit

Next, copy x2go-tce-filesystem.squashfs from the directory mentioned after “Build is done:” to a suitable subdirectory under your HTTP, HTTPS, or FTP root.

We suggest using ./x2go-tce.

To verify that both your installation in general and the newly copied file are reachable via HTTP, HTTPS, or FTP, use an HTTP/HTTPS/FTP client - we suggest wget - and perform these steps:
 cd $(mktemp -d)
wget -Y off http://your-http-server-ip-here/
wget -Y off http://your-http-server-ip-here/x2go-tce/x2go-tce-filesystem.squashfs

In case of an FTP URL, replace http with ftp in the example above. Same goes for https when trying to get that to work.

Note that you MUST use an IP address. X2Go-TCE WILL NOT WORK with a DNS name, even though this test here will accept IPs and DNS names alike. The only exception is when a template actually spells out that you should input a DNS name.

Adding the configuration files to your Boot Server

Again, this is assuming you already have an existing, working PXE/TFTP server setup.

x2go-tce
DEFAULT x2go-tce
PROMPT 0
MENU TITLE Linux Boot Menu
MENU COLOR TITLE 1 #ffffff #000000 std
MENU COLOR SEL 0 #ffffff #444444 std
MENU COLOR TABMSG 0 #999933 #000000 std
MENU COLOR UNSEL 0 #aaaaaa

LABEL x2go-tce
TIMEOUT 50
MENU LABEL X2Go-TCE
KERNEL x2go-tce/vmlinuz
APPEND initrd=x2go-tce/initrd.img boot=live components noswap aufs rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rd.driver.pre=loop rd.noverifyssl rd.skipfsck rd.live.overlay.check rd.live.overlay.reset rd.live.ram log_buf_len=1M quickreboot consoleblank=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rootwait=120 silent quiet splash lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 hostname=localhost noroot nouser fetch=http://your-http-server-ip-here/x2go-tce/x2go-tce-filesystem.squashfs FURTHER-OPTIONS-GO-HERE

Required unless using the X2Go Session Broker: Adding the x2go-tce.sessions session configuration file to your HTTP or FTP Server

Again, this is assuming you already have an existing, working HTTP or FTP server setup.

when using a Windows client, run x2goclient.exe –portable, or it will store the session information in the registry, rather than in a “sessions” file.

Optional: Adding the x2go-tce.authorized_keys keyfile to your HTTP or FTP Server

Again, this is assuming you already have an existing, working HTTP or FTP server setup.

Optional: Adding the x2go-tce.xorg.conf file to your HTTP or FTP Server

Again, this is assuming you already have an existing, working HTTP or FTP server setup.

Final Steps to boot a ThinClient

To boot your first X2Go-TCE ThinClient

Again, this is assuming you already have an existing, working PXE/TFTP server setup in place.

To make the X2Go-TCE image the default and only boot image

To create several configurations to accommodate varying hardware/use cases, but all booting the same basic image

Booting from local storage media

This section explains how to create images for local storage media.

Basically, proceed as shown for netboot above, but set LBX2GO_IMAGETYPE to iso-hybrid (recommended) or iso. Do not select hdd or tar - even though we are creating a local storage media installation.

  1. On your local storage media, create the following folders: /boot/X2Go-live1, /boot/X2Go-live2, /boot/X2Go-live-download.
  2. If you have serious space constraints, you can limit yourself to /boot/X2Go-live1, but you will be unable to use the autoupdater then.
  3. Copy ./x2go-tce-vmlinuz, ./x2go-tce-initrd.img, and ./x2go-tce-squashfs-only.iso to /boot/X2Go-live1/ (and to /boot/X2Go-live2/, if present).

Installing a boot loader

The next step is to install a boot loader. Currently, there are three choices, GRUB-legacy, syslinux, and GRUB4DOS.

Note that GRUB-legacy (and possibly GRUB4DOS as well) has a limit of 256 characters for /proc/cmdline. Current syslinux implementations double that value to 512 characters. So if you're seeing issues like X2Go-TCE hanging at boot when it comes to downloading config files, or certain parameters being ignored, when you specify a lot of and/or long parameters, you can either go ahead and shorten file names and paths (e.g. use “vml” instead of “x2go-tce-vmlinuz” and “http://host/” instead of “http://host.example.com/”, or switch to a different bootloader.

Installing GRUB-legacy

menu.lst
# sample grub-legacy menu.lst for booting X2Go-TCE from local media
# Depending on your setup, this goes either into C:\menu.lst or C:\boot\grub\menu.lst, or /boot/grub/menu.lst.
# C:\menu.lst is recommended for NTFS, /boot/grub/menu.lst for ext*. 
# Make sure you do not have menu.lst files at both locations.

default 0

timeout         5
color cyan/blue white/blue
# This says "password" in md5
password --md5 $1$v4.0xYdG$32uzkKsup9c1RsHZlzfQs1

title           X2Go-live1
find            /boot/X2Go-live1/x2go-tce-vmlinuz
root
kernel          /boot/X2Go-live1/x2go-tce-vmlinuz boot=live components noswap aufs rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rd.driver.pre=loop rd.noverifyssl rd.skipfsck rd.live.overlay.check rd.live.overlay.reset rd.live.ram log_buf_len=1M quickreboot consoleblank=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rootwait=120 lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 hostname=localhost noroot nouser silent quiet splash findiso=/boot/X2Go-live1/x2go-tce-squashfs-only.iso FURTHER-OPTIONS-GO-HERE
initrd          /boot/X2Go-live1/x2go-tce-initrd.img

title           X2Go-live2
find            /boot/X2Go-live2/x2go-tce-vmlinuz
root
kernel          /boot/X2Go-live2/x2go-tce-vmlinuz boot=live components noswap aufs rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rd.driver.pre=loop rd.noverifyssl rd.skipfsck rd.live.overlay.check rd.live.overlay.reset rd.live.ram log_buf_len=1M quickreboot consoleblank=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rootwait=120 lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 hostname=localhost noroot nouser silent quiet splash findiso=/boot/X2Go-live2/x2go-tce-squashfs-only.iso FURTHER-OPTIONS-GO-HERE
initrd          /boot/X2Go-live2/x2go-tce-initrd.img

Installing syslinux

syslinux.cfg
menu title X2Go-TCE
# This says "password" in md5
menu master passwd $1$v4.0xYdG$32uzkKsup9c1RsHZlzfQs1
UI menu.c32
default X2Go-live1
prompt 0
timeout 50
include X2Go-live1.cfg
include X2Go-live2.cfg
X2Go-live1.cfg
label X2Go-live1
        menu label X2Go-Live^1
        menu default
        linux /boot/X2Go-live1/x2go-tce-vmlinuz
        initrd /boot/X2Go-live1/x2go-tce-initrd.img
        append boot=live components noswap aufs rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rd.driver.pre=loop rd.noverifyssl rd.skipfsck rd.live.overlay.check rd.live.overlay.reset rd.live.ram log_buf_len=1M quickreboot consoleblank=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rootwait=120 lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 hostname=localhost noroot nouser silent quiet splash findiso=/boot/X2Go-live1/x2go-tce-squashfs-only.iso FURTHER-OPTIONS-GO-HERE
X2Go-live2.cfg
label X2Go-live2
        menu label X2Go-Live^2
        menu default
        linux /boot/X2Go-live2/x2go-tce-vmlinuz
        initrd /boot/X2Go-live2/x2go-tce-initrd.img
        append boot=live components noswap aufs rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rd.driver.pre=loop rd.noverifyssl rd.skipfsck rd.live.overlay.check rd.live.overlay.reset rd.live.ram log_buf_len=1M quickreboot consoleblank=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rootwait=120 lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 hostname=localhost noroot nouser silent quiet splash findiso=/boot/X2Go-live2/x2go-tce-squashfs-only.iso FURTHER-OPTIONS-GO-HERE

Installing GRUB4DOS

Installing GRUB4DOS allows you to keep the original Windows bootloader installed. The method below also allows you to write-mount the NTFS file system and thus to deploy updates using the autoupdater. This is done by chainloading GRUB4DOS from the native Microsoft Windows Bootloader

insertgrub.cmd
@echo off
setlocal
set BCDEDIT=%SYSTEM%\bcdedit.exe
if not exist %BCDEDIT% exit 1
for /f "tokens=3" %%A in ('%BCDEDIT% /create /d "PXE boot" /application bootsector') do set guid=%%A
%BCDEDIT% /set %guid% device partition=%SystemDrive%
%BCDEDIT% /set %guid% path \grldr.mbr

REM you can use /addfirst instead, if you want
%BCDEDIT% /displayorder %guid% /addlast

REM this sets a 5 second timeout until the default entry is booted
REM feel free to adjust to your needs, but NEVER set it to 0 or 1
REM in combination with using /default below unless you don't ever
REM intend to boot back into Windows again.
%BCDEDIT% /timeout 5

REM "bootsequence" means only the single, next reboot will default to this
%BCDEDIT% /bootsequence %guid% /addfirst

REM alternatively, you can uncomment this and make the ThinClient 
REM boot option the default boot option
REM %BCDEDIT% /default %guid%

endlocal
menu.lst
# sample grub-legacy menu.lst for booting X2Go-TCE from NTFS-formatted local media
# Depending on your setup, this goes either into C:\menu.lst or C:\boot\grub\menu.lst.
# C:\menu.lst is recommended. 
# Make sure you do not have menu.lst files at both locations.

default 0

timeout         5
color cyan/blue white/blue
# This says "password" in md5
password --md5 $1$v4.0xYdG$32uzkKsup9c1RsHZlzfQs1

title           X2Go-live1
find            /boot/X2Go-live1/x2go-tce-vmlinuz
root
kernel          /boot/X2Go-live1/x2go-tce-vmlinuz boot=live components noswap aufs rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rd.driver.pre=loop rd.noverifyssl rd.skipfsck rd.live.overlay.check rd.live.overlay.reset rd.live.ram log_buf_len=1M quickreboot consoleblank=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rootwait=120 lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 hostname=localhost noroot nouser silent quiet splash findiso=/boot/X2Go-live1/x2go-tce-squashfs-only.iso toram ntfs-uuid=xxxxxxxxxxxxx FURTHER-OPTIONS-GO-HERE
initrd          /boot/X2Go-live1/x2go-tce-initrd.img

title           X2Go-live2
find            /boot/X2Go-live2/x2go-tce-vmlinuz
root
kernel          /boot/X2Go-live2/x2go-tce-vmlinuz boot=live components noswap aufs rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rd.driver.pre=loop rd.noverifyssl rd.skipfsck rd.live.overlay.check rd.live.overlay.reset rd.live.ram log_buf_len=1M quickreboot consoleblank=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rootwait=120 lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 hostname=localhost noroot nouser silent quiet splash findiso=/boot/X2Go-live2/x2go-tce-squashfs-only.iso toram ntfs-uuid=xxxxxxxxxxxxx FURTHER-OPTIONS-GO-HERE
initrd          /boot/X2Go-live2/x2go-tce-initrd.img

Booting from CD/DVD/USB

  1. set the variables as shown in Configuring the Build
  2. after that, continue with export LBX2GO_IMAGETYPE=“iso-hybrid” (recommended) or export LBX2GO_IMAGETYPE=“iso”.
  3. see Boot Parameters for X2Go-TCE for a description of possible options, make your choices, add them where it says FURTHER-OPTIONS-GO-HERE and follow up with
    export LBX2GO_DEFAULTS+=" --bootappend-live boot=live components noswap aufs rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rd.driver.pre=loop rd.noverifyssl rd.skipfsck rd.live.overlay.check rd.live.overlay.reset rd.live.ram log_buf_len=1M quickreboot consoleblank=0 kernel.sysrq=1 keep_bootcon sysrq_always_enabled rootwait=120 silent quiet splash lang=de vconsole.keymap=de keyboard-layouts=de locales=de_DE.UTF-8 hostname=localhost noroot nouser live-media-path=live FURTHER-OPTIONS-GO-HERE
  4. after that, you can Start the Build.
  5. if you actually intend to write the image to CD/DVD or USB media, the only file you need is located at ./original-x2go-tce-live-image-i386.hybrid.iso after running the build script.
  6. if the image fails to boot, check the file system - there should be a folder live containing a file filesystem.squashfs. Adjust the value of live-media-path= accordingly.

Burning to CD/DVD

Use xorriso -as cdrecord -v dev=/dev/your-writer-device -dao ./original-x2go-tce-live-image-i386.hybrid.iso or whatever cd burning software you like. See https://wiki.debian.org/BurnCd for some additional suggestions.

Writing to USB media

When using iso-hybrid, this file can be dd'ed straight to USB media, no need to unpack, format, fiddle with a boot loader, etc.

So just do dd if=./original-x2go-tce-live-image-i386.hybrid.iso of=/dev/targetdevice and wait until it finishes.

Also, when using iso-hybrid and USB media, there are a few “cheats” to reclaim unused space on the USB media, and to turn it into a solution that allows you to run X2GoClient in portable mode on Windows, and boot it as X2Go-TCE, with a shared configuration file.

Persistent SSH Host Keys

As there is no simple way to have individual, persistent SSH Host Keys per ThinClient, and sharing secret host keys across machines is a bad idea, too, the default behavior is to generate a new key pair upon boot. If you need to SSH into ThinClients often, this may soon become annoying. Therefore, X2Go-TCE-Live comes with a script that, during the boot process, will scan for USB media and fixed disk media (with fixed disk media taking precedence, unlike the copysecring boot parameter that copies SSH Client Private Keys when set) for a directory config/sshdkeys. The volume must be labeled X2GO-TCE-LIVE and may use any supported file system, though write support is required if you want to store the keys from within X2Go-TCE-Live. If you're booting from fixed disk media/internal flash, you may put the folder directly in the root directory of your boot drive - just don't forget to change the volume label to the “magic value” X2GO-TCE-LIVE. If the directory exists, but is empty, all current SSH Host Keys will be copied into it (missing ones will be generated on the fly). Any SSH Host Keys found in the config/sshdkeys directory will be copied into /etc/ssh/ (in the ramdisk), with proper permissions and ownerships for sshd, and sshd will be told to reload its config if required.

Boot Parameters for X2Go-TCE

These are always required for security reasons, unless you are working on a debug image:
  • noroot - do not allow the local user account on the ThinClient (named “user”) to become root, e.g. using sudo Always set this unless you are debugging an image and need to log in locally!
  • nouser - do not allow the local user account on the ThinClient (named “user”) to log in at the console or remotely (using password “live”) Always set this unless you are debugging an image and need to log in locally!

Options already present in the templates that you may/should change to your needs

To have different hostnames for each thin client:
  • assign DNS names for your thin clients
  • set your DHCP server to reply to “request host-name” requests from dhclient
  • use hostname=localhost as shown above.

If you remove hostname=localhost entirely, all thin clients will share the hostname debian, which is the Debian-Live default host name. Similarly, if you set hostname=someothervalue, all thin clients booting this configuration will share the hostname someothervalue.

What options are available under FURTHER-OPTIONS-GO-HERE?

These two are mutually exclusive, i.e. never put both of them in the same config

These are entirely optional

These are only intended to be used with TCE images stored on local media

Client Branding/Theming using SVGs

It is possible to make X2Go-TCE-Live match your Corporate Design/Corporate Identity, using the “background” and “branding” parameters. This is actually a feature of X2GoClient itself, so it will also work on fat client installations, and even on Windows and macOS.

Before ...  ... and after.

You can find a more detailed explanation in the corresponding X2Go Wiki page.

Querying X2Go-TCE version info

images built using the https://github.com/LinuxHaus/live-build-x2go::feature/openbox repository/branch after 2017-07-27 10:50 UTC will create a file /var/run/x2go-timestamps.

A command like

ssh -A root@ThinClientIPorDNS 'cat /var/run/x2go-tce-timestamps'

will return a result like

--- BEGIN TIMESTAMPS ---
1501164001;X2Go-live1;X
1501160716;X2Go-live2;
---- END TIMESTAMPS ----

Which you can parse using grep, awk, and/or perl, for example.

The first field is the version number, the second field is the name of the instance, the third field, if set, indicates that this is the running instance.

“Tell me the version number of the currently running instance” could thus be queried like:

ssh -A root@ThinClientIPorDNS 'cat /var/run/x2go-tce-timestamps' | awk -F ';' '$3 == "X" { print $1 }'

This value can then be compared to the output of

curl http(s)://YourUpdateServerIPorDNS/path/to/image/x2go-tce-timestamp

→ If the number the curl command returns is higher than the one returned by the ssh command, the ThinClient is running an older version of X2Go-TCE and should be marked as requiring an update in whatever monitoring software you use.

→ This feature doesn't really make sense when you're netbooting, so it is only enabled when an updateurl= boot parameter is present - for local installations and writable portable media, it will help you keep track of update rollout status.

Note that you will have to provide an SSH public key using the pubkey= boot parameter for this to work.

Troubleshooting a booted X2Go-TCE image

You can see the X2Go login screen, but the screen size (resolution) is wrong

Determine the correct resolution for your screen and set boot parameter xorg-resolution=HRESxVRES accordingly, e.g. to xorg-resolution=1280×1024

The screen is entirely black (though you might notice an illuminated backlight in case of a TFT)

If the screen is entirely black, try pressing [Ctrl]+[Alt]+[F1] and see if that takes you to the text login screen.

You can see a text login screen with grey/white, green, and possibly red letters against a black background

If you end up at the text login, this means the X Server's autodetection failed. There's not much you can do from inside X2Go-TCE at this point. Make a note of the MAC address (the GREEN text), shut down the ThinClient and try to boot a different Linux distribution on it. Try, for example, KNOPPIX Live Linux, other Distribution's Live Images (a recent Fedora or Arch, maybe?).

If you can get X running in one of these, proceed as follows:

In the running Linux where you have a working X Server on that particular hardware:

Next steps:

The session itself works fine, but Audio is not working

First, check that the audio isn't simply muted (some cards/setups do this by default). Run pavucontrol inside the X2Go session. Check the settings on the tabs Output Devices and Configuration. If that is the case, you probably need to create a script on the server that raises the volume/toggles the mute setting upon user login.

If that doesn't help, please boot with additional boot parameter audioout=list and look at the output on /dev/tty8 (Hit Ctrl+Alt+F8) - it will give you a list of available audio output devices. This list also gets written to /tmp/audiolog on the ThinClient.

You might have to pick a different one from the list, by using boot parameter audioout= with a particular card/output value, like: audioout=“alsa_card.pci-0000_00_1b.0|output:hdmi-stereo” (you need to copy the proper value from the list generated on your particular thinclient).

If you need different settings for different manufacturers, you can try to tell them apart by MAC address and set separate pxe boot configuration files for them.

Support Tools available in X2Go-TCE

Remote Access to the ThinClient's local display (before any connection is made)

X2Go-TCE comes with x11vnc installed. If you want to see what's on the ThinClient's X11 screen, before a server connection has been established, proceed as follows:

To see what a user is doing once a connection has been established, connect to the X2GoServer yourself and use X2Go's built-in Desktop Sharing (session shadowing). Install package x2godesktopsharing on the server, if you haven't done so already - this will deliver way better performance. See below for more.

Remote Access to the ThinClient's running X2Go Session

Please see the Desktop Sharing (session shadowing) HowTo for details.

Determining the ThinClient's IP and/or MAC when there is no network connection

When you are unable to connect to the ThinClient, you might want to ascertain its MAC and/or IP address(es), to make sure you and the user you are trying to support are talking about the same machine. Tell the user to press [Ctrl]+[Alt]+[F1] and to read out

To return to the login screen, have the user press [Ctrl]+[Alt]+[F7] ([Alt]+[F7] should work, too), or, once you've successfully logged in over the network, issue the chvt 7 command.

Checking the ThinClient's local printer setup (when using the ''tcpprint'' boot parameter)

There are several ways to check whether a ThinClient has detected any local printers:

Checking the ThinClient's update status (when using local storage)

There are several ways to check a ThinClient's update status:


List of open ToDos/FIXMEs for this page

FIXME This page is missing a section/subpage that explains how to use the content of the tar file located in the build directory if no PXE/TFTP/HTTP server is present yet.

Basically, debian-live/live/filesystem.squashfs becomes (webroot)/x2go-tce/x2go-tce-filesystem.squashfs and everything from tftpboot/ goes into the TFTP root directory. After that, one should proceed as described above regarding creation of files and symlinks.

Sample contents of live-image-i386.netboot.tar:

drwxr-xr-x root/root         0 2016-12-15 23:46 debian-live/
drwxr-xr-x root/root         0 2016-12-15 23:54 debian-live/live/
-rw-r--r-- root/root 271536128 2016-12-15 23:50 debian-live/live/filesystem.squashfs
-rw-r--r-- root/root     11579 2016-12-15 23:52 debian-live/live/filesystem.packages
-rw-r--r-- root/root        74 2016-12-15 23:52 debian-live/live/filesystem.packages-remove
drwxr-xr-x root/root         0 2016-12-15 23:54 tftpboot/
drwxr-xr-x root/root         0 2016-12-15 23:54 tftpboot/live/
-rw-r--r-- root/root  31942749 2016-12-15 23:52 tftpboot/live/initrd.img
-rw-r--r-- root/root   2831760 2016-12-15 23:52 tftpboot/live/vmlinuz
drwxr-xr-x root/root         0 2015-04-28 14:01 tftpboot/pxelinux.cfg/
-rw-r--r-- root/root        57 2014-10-25 14:21 tftpboot/pxelinux.cfg/default
-rw-r--r-- root/root       351 2016-12-15 23:54 tftpboot/live.cfg
-rw-r--r-- root/root    116624 2015-08-19 15:17 tftpboot/ldlinux.c32
-rw-r--r-- root/root       270 2016-12-15 23:54 tftpboot/menu.cfg
-rw-r--r-- root/root     26188 2015-08-19 15:17 tftpboot/vesamenu.c32
-rw-r--r-- root/root       268 2016-12-15 23:54 tftpboot/install.cfg
-rw-r--r-- root/root       508 2016-12-15 23:54 tftpboot/stdmenu.cfg
-rw-r--r-- root/root     34739 2016-12-15 23:54 tftpboot/splash.png
-rw-r--r-- root/root     23480 2015-08-19 15:17 tftpboot/libutil.c32
-rw-r--r-- root/root       153 2016-12-15 23:54 tftpboot/advanced.cfg
-rw-r--r-- root/root    182552 2015-08-19 15:17 tftpboot/libcom32.c32
-rw-r--r-- root/root     42988 2015-08-19 15:17 tftpboot/pxelinux.0
-rw-r--r-- root/root    164096 2015-08-19 15:17 tftpboot/hdt.c32

FIXME This page is missing a section/subpage that explains how to speed up the netboot process using iPXE.

Basically:

apt-get install ipxe
cd /your-tftp-root
mkdir -p {bios,uefi}
ln -s /usr/lib/ipxe/undionly.kpxe ./bios/
ln -s /boot/ipxe.efi ./uefi/
FQDN=DNS-name-of-your-server-here
IP_OF_FQDN=`dig $FQDN +short`
cat <<EOF>x2go-tce-ipxe
#!ipxe
dhcp
kernel http://$FQDN/x2go-tce-vmlinuz EVERYTHING-FROM-THE-LINE-STARTING-WITH-APPEND-IN-THE-X2GO-TCE-SAMPLE-FILE-ABOVE
initrd http://$FQDN/x2go-tce-initrd.img
boot
EOF

After that, create a symlink/symlinks that point(s) from “default” or a part of the MAC or the entire MAC, or the UUID, or the hex-encoded IP to x2go-tce-ipxe.

Then add this to your dhcpd.conf

   if substring ( option vendor-class-identifier , 19,1 ) = "0" {
           filename "bios/undionly.kpxe";
   }
   else if substring ( option vendor-class-identifier , 19,1 ) = "7" {
           filename "uefi/ipxe.efi";
   }
   else {  
           log (info, concat ( "Unhandled vendor class Arch: ", substring ( option vendor-class-identifier , 19,1 )));
   }
   if exists user-class and option user-class = "iPXE" {
	set hwmac = concat (
	suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":",
	suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":",
	suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":",
	suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":",
	suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":",
	suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2)
	);

      filename = concat( "http://DNS-name-of-your-server-here/", hwmac );
   }

FIXME Document how to add second partition to USB media after dd'ing the iso-hybrid image, and how to add X2GoClient-Portable to it.

FIXME Document that using updateurl along with an rsync://FQDN/x2go-tce URL is the most efficient way to deploy updates. Note that the syntax is rsync://FQDN/x2go-tce, NOT rsync://FQDN::x2go-tce.

/etc/rsyncd.conf
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid

[x2go-tce]
    path = /var/www/x2go-tce
    # change this to the path where you intend to keep the images
    comment = X2Go TCE files
    uid = root
    gid = root
    read only = yes
    list = yes
    hosts allow = 192.168.0.0/255.255.0.0
    # change this to your local subnet(s)

FIXME Some of the optional steps above could be moved to a separate subpage to reduce clutter.

FIXME The steps for the build process could probably streamlined into an x2go-tcebuilder.deb Debian package

Ideas:

FIXME autodetection for SSH Private Keys might need some more bells and whistles.

FIXME Parsing the output of e.g.

udevadm info --query path /dev/sdb
/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/block/sdb
cat /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/serial

allows to determine the serial number of a USB device. Those SHOULD be unique, but sadly, they aren't (and sometimes, they are missing entirely). Therefore, a USB serial number can't be used for authentication, but it could be used for “weak” identification - so it could be used to set a default user name or a default session, or to download a particular sessions file. Authentification and “hard” identification could be implemented using OpenPGP cards, scdaemon and a script based on /usr/share/doc/scdaemon/examples/scd-event. For Status NOCARD, suspend the session (kill x2goclient or send a signal that means “suspend”, if available, or maybe sighup nxproxy), for status USABLE, run gpg –card-status 2>&1 | awk '$1==“Serial” && $2==“number” {print $4}' to determine the card's serial number, then act based on that (pull new sessions file or set default user, for example, and restart x2goclient).

FIXME Automount script currently expects a LUKS password in /etc/keys/keystick.key when it believes it has found an encrypted partition on USB media. This is a problem in general, as it should be trivial to sniff out this password using a rogue client. Such a password file would have to be saved as ./patch/includes.chroot/etc/keys/keystick.key (with the proper restrictive permissions) before starting the build. Adding a boot parameter instead of hardcoding it would allow for dynamic password files (by specifying an URI that points to a CGI script, for example - you could output a different password depending on the source IP range, thus locking media to a particular department, if your departments have different IP ranges), but on the other hand, would make it even easier to sniff out the password. It would only really make sense for Netboot installations, and also not for a MiniDesktop in any way, because you have to block the user from accessing the TCE's local environment/files. And you also have to make sure that people cannot boot rogue clients. This means a DHCP setup that is locked to known MAC addresses, and physically blocking access to the ThinClient and its network wiring - because the MAC is displayed during boot, and thus trivial to clone.

FIXME x2gocdmanager is currently not part of the image, but should become part of it. While optical media are on their way out, they still exist and thus we should support them. However, the script is hardcoded for X2Go-TCE-NFS and needs to be adapted to work with both TCEs.

FIXME pinentry-x2go and x2gosmartcardrules probably need further investigation to make smartcard authentication work.

FIXME Even though we set the hostname to localhost using the corresponding boot parameter, as recommended by Debian, changing the name via DHCP does not work for all image flavours. One way to fix this might be http://blog.schlomo.schapiro.org/2013/11/setting-hostname-from-dhcp-in-debian.html

FIXME When building a stretch TCE you need to add kernel parameters net.ifnames=0 biosdevname=0 to the image's kernel parameters, else you will receive error messages about the hostname script being unable to find eth0. For a jessie TCE, it is not required. This could be fixed for iso-hybrid and netboot in the buildscript, but it will only work if people are using the image 1:1 - as soon as they start using syslinux or grub manually (as actually recommended by us), they need to add these parameters themselves.

FIXME bg=, branding=, broker-url=, ldap=, ldap1=, ldap2=, session=, throttle=, are currently unsupported in MiniDesktop-Mode. This could be changed, given enough tuits. Probably the easiest way would be to have /lib/live/config/2900-x2go-thinclientconfig exist in the MiniDesktop branches as well, make it aware of which environment it is running in (TCE/TCE-MMD), and have it patch the appropriate files.

FIXME 2200-xserver-xorg-getxorgconf all scripts accepting URLs in boot parameters should be taught to understand file:/// URLs. Such files can be included in the image by placing them in the ./patch/includes.chroot/ directory (in a suitable subdirectory) and referencing them from there.

FIXME it would be cool if most of the TCE-specific boot parameters could be placed into a file that in turn can be specified as a boot parameter, to reduce clutter and boot parameter length. This could be aCGI script, even, thus making it possible to distribute different configs depending on the source IP of the ThinClient, rather than the MAC Address. Said file would then have to be sourced by the scripts, after they have extracted everything from /proc/cmdline. This will make adding the feature easier, by simply deciding that parameters from this file take precendence over boot parameters. One might argue that boot parameters should take precedence over the config file, but this sounds way more complicated to implement.

FIXME A smaller image size can be achieved by removing the following packages from the squashfs: libxapian30 libpcsclite1 libdbus-glib-1-2 libfuse2 libpipeline1 libusb-1.0-0 libxv1 xnest xserver-xephyr rdesktop freerdp-x11 traceroute screen net-tools less ntfs-3g fuse locales cifs-utils xterm libgssglue1 libntfs-3g871 libtalloc2 libtcl8.6 libtk8.6 libutempter0 libvncclient1 libvncserver1 libwbclient0 libxcb-xf86dri0 libxcb-xv0 samba-common tcl tcl8.6 tk tk8.6 xbitmaps nfs-common rpcbind atmel-firmware bluez-firmware dahdi-firmware-nonfree hdmi2usb-fx2-firmware iso-codes ixo-usb-jtag libc-l10n libnfsidmap2 libtirpc1 firmware* x11vnc* libfreerdp* libwinpr* libapparmor1 systemd apt-utils libapt-inst2.0 acpi-support-base* acpid* acpi-support* pm-utils* powermgmt-base* gnupg gnupg-agent whiptail vim* vim-common* vim-tiny* xxd* xinetd libcroco3* libcurl3* libexif12* libgdk-pixbuf2.0-0* libgdk-pixbuf2.0-common* libgif7* libid3tag0* libimlib2* libnghttp2-14* libobrender32v5* libobt2v5* libpango-1.0-0* libpangocairo-1.0-0* libpangoft2-1.0-0* libpangoxft-1.0-0* librsvg2-2* librtmp1* libssh2-1* libstartup-notification0* libxft2* libxss1* vim-runtime* xprintidle feh xdotool openbox rsync xserver-xorg-input-wacom* xserver-xorg-video-all* xserver-xorg-video-amdgpu* xserver-xorg-video-ati* xserver-xorg-video-nouveau* xserver-xorg-video-qxl* xserver-xorg-video-radeon* xserver-xorg-video-vmware* libdrm-amdgpu1* libdrm-nouveau2* libdrm-radeon1* libllvm3.9* libsensors4* libxatracker2* - check if this could be turned into a build parameter. Note that this makes only sense for a netboot image that uses X2Go sessions only, and no NTFS media (neither fixed disk nor USB). Also, this causes an X startup failure during boot that needs to be worked around (by touching /home/user/.xsession). Here's a script to do all of this automatically (needs to be run as root in the builddir:

stripimage.sh
#!/bin/bash -e
if [ $UID -ne 0 ] ; then
	echo "Must be root."
	exit 1
fi
unsquashfs x2go-tce-filesystem.squashfs
mount --bind /proc squashfs-root/proc
chroot squashfs-root apt purge -y acpi-support-base acpid acpi-support pm-utils powermgmt-base gnupg gnupg-agent whiptail vim vim-common vim-tiny xxd xinetd \
                                  libcroco3 libcurl3 libexif12 libgdk-pixbuf2.0-0 libgdk-pixbuf2.0-common libgif7 libid3tag0 libimlib2 libnghttp2-14 \
                                  libobrender32v5 libobt2v5 libpango-1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpangoxft-1.0-0 librsvg2-2 librtmp1 \
                                  libssh2-1 libstartup-notification0 libxft2 libxss1 vim-runtime rsync xserver-xorg-input-wacom xserver-xorg-video-all \
                                  xserver-xorg-video-amdgpu xserver-xorg-video-ati xserver-xorg-video-nouveau xserver-xorg-video-qxl \
                                  xserver-xorg-video-radeon xserver-xorg-video-vmware libdrm-amdgpu1 libdrm-nouveau2 libdrm-radeon1 libllvm3.9 libsensors4 \
                                  libxatracker2 xprintidle feh xdotool openbox libxapian30 libpipeline1 libnpth0 libksba8 libseccomp2 libsqlite3-0 libxdo3 \
                                  libnewt0.52 libslang2 keyutils libassuan0 libdatrie1 libevent-2.0-5 libthai-data libthai0 \
                                  pinentry-curses trickle libxapian30 libpcsclite1 libdbus-glib-1-2 libfuse2 libpipeline1 libusb-1.0-0 libxv1 xnest \
                                  xserver-xephyr rdesktop freerdp-x11 traceroute screen net-tools less ntfs-3g fuse locales cifs-utils xterm libgssglue1 \
                                  libntfs-3g871 libtalloc2 libtcl8.6 libtk8.6 libutempter0 libvncclient1 libvncserver1 libwbclient0 libxcb-xf86dri0 \
                                  libxcb-xv0 samba-common tcl tcl8.6 tk tk8.6 xbitmaps nfs-common rpcbind atmel-firmware bluez-firmware \
                                  dahdi-firmware-nonfree hdmi2usb-fx2-firmware iso-codes ixo-usb-jtag libc-l10n libnfsidmap2 libtirpc1 x11vnc x11vnc-data \
                                  libapparmor1 systemd apt-utils libapt-inst2.0 libfreerdp-cache1.1 libfreerdp-client1.1 libfreerdp-codec1.1 \
                                  libfreerdp-common1.1.0 libfreerdp-core1.1 libfreerdp-crypto1.1 libfreerdp-gdi1.1 libfreerdp-locale1.1 \
                                  libfreerdp-primitives1.1 libfreerdp-rail1.1 libfreerdp-utils1.1 libwinpr-crt0.1 libwinpr-crypto0.1 libwinpr-dsparse0.1 \
                                  libwinpr-environment0.1 libwinpr-file0.1 libwinpr-handle0.1 libwinpr-heap0.1 libwinpr-input0.1 libwinpr-interlocked0.1 \
                                  libwinpr-library0.1 libwinpr-path0.1 libwinpr-pool0.1 libwinpr-registry0.1 libwinpr-rpc0.1 libwinpr-sspi0.1 \
                                  libwinpr-synch0.1 libwinpr-sysinfo0.1 libwinpr-thread0.1 libwinpr-utils0.1 firmware-amd-graphics firmware-atheros \
                                  firmware-bnx2 firmware-bnx2x firmware-brcm80211 firmware-cavium firmware-crystalhd firmware-intel-sound \
                                  firmware-intelwimax firmware-ipw2x00 firmware-ivtv firmware-iwlwifi firmware-libertas firmware-linux firmware-linux-free \
                                  firmware-linux-nonfree firmware-misc-nonfree firmware-myricom firmware-netxen firmware-qlogic firmware-realtek \
                                  firmware-samsung firmware-siano firmware-ti-connectivity firmware-zd1211
chroot squashfs-root dpkg -P apt tasksel tasksel-data
rm squashfs-root/etc/X11/Xsession.d/60x11-openbox-start squashfs-root/etc/X11/Xsession.d/60x11-spawn-configure-slideshow-screensaver
(cd squashfs-root/usr/bin/ ; ln -sf ../../bin/false xsetwacom)
mkdir -p squashfs-root/home/user
touch squashfs-root/home/user/.xsession
umount squashfs-root/proc
if ! grep '^eval $THROTTLINGCOMMAND' squashfs-root/etc/X11/Xsession.d/61x11-start-x2goclient | grep -q -- ' --thinclient ' ; then
        sed -i -e 's#eval \$THROTTLINGCOMMAND x2goclient#eval \$THROTTLINGCOMMAND x2goclient --thinclient#g' \
            squashfs-root/etc/X11/Xsession.d/61x11-start-x2goclient
fi
if [ -f binary/live/filesystem.squashfs ] ; then
        mv binary/live/filesystem.squashfs binary/live/filesystem.squashfs.old
fi
mkdir -p binary/live
mksquashfs squashfs-root binary/live/filesystem.squashfs -comp xz -Xbcj x86 -b 1024K -Xdict-size 1024K -noappend
rm -rf squashfs-root
ln -f binary/live/filesystem.squashfs x2go-tce-filesystem-stripped.squashfs
(cd binary; echo live$'\n'live/filesystem.squashfs |cpio -o -H newc | gzip --fast) >./tce-filesystem-stripped.cpio.gz
cat ./x2go-tce-initrd.img ./tce-filesystem-stripped.cpio.gz >./x2go-tce-initrd-with-fs-stripped.img
rm ./tce-filesystem-stripped.cpio.gz

FIXME for MATE-MiniDesktop, it might make sense to teach the image how to do LDAP auth (preferably with LDAPS or LDAP+TLS) and use lightdm without the auto-login. That way, a local screensaver with locking functionality (prompting for the actual user's LDAP password) should be possible - and LDAP credential passthrough to X2GoClient should work, too (though that might require kerberos in addition to LDAP,we'll see).

FIXME Scripts triggered by if-up should check if a new download is really necessary.

List of closed ToDos/FIXMEs for this page

The live-config “builtin” command live-config.nottyautologin does not do the same as our nouser command. live-config.nottyautologin means “there's a login prompt, but you just need to enter username user and password live to login” - this is not what we want. We need a solution to entirely block user logons.