Goal of this article is to document the setup of a Guacamole HTML5 remote XFCE desktop via VNC on Ubuntu 24.04.x. The Guacamole setup is based on Ubuntu 20.04.x LTS - Guacamole HTML5 Remotedesktop Gateway installieren mit Apache Reverse Proxy (in german, written by Bernhard Linz)

Install the guacamole server

So, let’s assume we have a fresh Ubuntu 24.04.x installation on a remote machine with DNS name test.example.org running a ssh server. First, we become root:

sudo -i

Next, we install everything that is needed to run the Apache Tomcat server. We’ll need tomcat9, since tomcat10 (that is the default for Ubuntu 24.04) is not compatible with Guacamole. So we have to add the respective repostitory first.

add-apt-repository -y -s "deb http://archive.ubuntu.com/ubuntu/ jammy main universe"
apt install make libssh2-1-dev libtelnet-dev libpango1.0-dev libossp-uuid-dev libcairo2-dev libpng-dev libvncserver-dev libvorbis-dev  gcc libssh-dev libpulse-dev tomcat9 tomcat9-admin tomcat9-docs ghostscript libwebp-dev libavcodec-dev libavutil-dev libswscale-dev libjpeg-turbo8-dev libtool-bin libossp-uuid-dev libavformat-dev freerdp2-dev libwebsockets-dev libssl-dev

Now, on calling http://test.example.org:8080 we should see the standard Apache Tomcat “It works!” page.

As of July 2025, the current Guacamole version is 1.6.0, so we download the following files:

cd /usr/src
wget https://downloads.apache.org/guacamole/1.6.0/source/guacamole-server-1.6.0.tar.gz
wget https://downloads.apache.org/guacamole/1.6.0/binary/guacamole-1.6.0.war

So we have server source code and client binary.

Now we unpack the server code

tar xvzf guacamole-server-1.6.0.tar.gz

and compile it:

cd /usr/src/guacamole-server-1.6.0
./configure --with-systemd-dir=/etc/systemd/system

That should result in an output like this:

------------------------------------------------
guacamole-server version 1.6.0
------------------------------------------------

   Library status:

     freerdp ............. yes (2.x)
     pango ............... yes
     libavcodec .......... yes
     libavformat ......... yes
     libavutil ........... yes
     libssh2 ............. yes
     libssl .............. yes
     libswscale .......... yes
     libtelnet ........... yes
     libVNCServer ........ yes
     libvorbis ........... yes
     libpulse ............ yes
     libwebsockets ....... yes
     libwebp ............. yes
     wsock32 ............. no

   Protocol support:

      Kubernetes .... yes
      RDP ........... yes
      SSH ........... yes
      Telnet ........ yes
      VNC ........... yes

   Services / tools:

      guacd ...... yes
      guacenc .... yes
      guaclog .... yes

   FreeRDP plugins: /usr/lib/x86_64-linux-gnu/freerdp2
   Init scripts: no
   Systemd units: /etc/systemd/system

Type "make" to compile guacamole-server.

If that’s the case as all “yes”-entries are present, we can compile:

make
make install

Last we have to configure the dynamic linker run-time bindings:

ldconfig

Now we can start the systemd service that the installation has provided:

systemctl start guacd.service
systemctl status guacd.service

which should give us an output like

● guacd.service - Guacamole Server
     Loaded: loaded (/etc/systemd/system/guacd.service; disabled; vendor preset: enabled)
     Active: active (running) since Fri 2023-04-21 14:52:28 UTC; 6s ago
       Docs: man:guacd(8)
   Main PID: 47807 (guacd)
      Tasks: 1 (limit: 2233)
     Memory: 10.2M
        CPU: 10ms
     CGroup: /system.slice/guacd.service
             └─47807 /usr/local/sbin/guacd -f

Apr 21 14:52:28 test181 systemd[1]: Started Guacamole Server.
Apr 21 14:52:28 test181 guacd[47807]: Guacamole proxy daemon (guacd) version 1.5.1 started
Apr 21 14:52:28 test181 guacd[47807]: guacd[47807]: INFO:        Guacamole proxy daemon (guacd) version 1.5.1 started
Apr 21 14:52:28 test181 guacd[47807]: guacd[47807]: INFO:        Listening on host 127.0.0.1, port 4822
Apr 21 14:52:28 test181 guacd[47807]: Listening on host 127.0.0.1, port 4822

We stop the server in order to amend configurations:

systemctl stop guacd.service

First we create the directory

mkdir /etc/guacamole

There we create a file /etc/guacamole/guacamole.properties with the content

basic-user-mapping: /etc/guacamole/user-mapping.xml

For our purposes, this file reads like

<user-mapping>
        <!-- Per-user authentication and config information -->
        <!-- FIRST USER -->
        <authorize 
                username="test01"
                password="52c88bca7c5b3ab3e7ed8901ea1bc83f"
                encoding="md5">
                <!-- First authorized Remote connection -->
                <connection name="SSH Admin">
                        <protocol>ssh</protocol>
                        <param name="hostname">10.10.10.10</param>      
                        <param name="port">22</param>                    
                        <param name="username">test01</param>     
                        <param name="enable-sftp">true</param>
                </connection> 
                <!-- second authorized Remote connection -->
                <connection name="Terminal Server VNC">
                        <protocol>vnc</protocol>
                        <param name="hostname">127.0.0.1</param> 
                        <param name="port">5901</param>         
                        <param name="server-layout">de-de-qwertz</param>
                </connection>
        </authorize>
</user-mapping>

Of course we have to amend hostname, username, and password for our system.

The password hash can be created by

echo -n 'secretPassword' | md5sum

Finally, we have to append the Guacamole home to the environment:

echo GUACAMOLE_HOME="/etc/guacamole" >> /etc/environment

It makes sense to reboot at this point.

Now we enable the Guacamole service for automated start:

systemctl enable guacd.service

Next, we install the client:

cp /usr/src/guacamole-1.6.0.war /var/lib/tomcat9/webapps/guacamole.war

Then we have to link the property directory to the place where it is expected:

ln -s /etc/guacamole /usr/share/tomcat9/.guacamole

To speed up the tomcat restart, we have to create the following file

touch /usr/share/tomcat9/bin/setenv.sh
chmod +x /usr/share/tomcat9/bin/setenv.sh

with this content:

#!/bin/sh
export CATALINA_OPTS="$CATALINA_OPTS -Djava.security.egd=file:/dev/./urandom"

Now we can start the guacamole server:

systemctl start guacd.service

If we now browse to

http://test.example.org:8080/guacamole/

we should be offered a login and then the connection options “SSH Admin” and “Terminal Server VNC”.

The SSH connection should work already (if not, you did probably not reboot), for the VNC we need to prepare some more things, as follows.

Install the VNC server

Let’s assume that we have a user test01 as our (sudo-enabled) standard user for the machine we just prepared, and that we are now logged in as that user.

We install the needed stuff:

sudo apt install -y xfce4 xfce4-goodies tigervnc-standalone-server tigervnc-xorg-extension autocutsel xfonts-base xfonts-100dpi xfonts-75dpi

Then we create a vnc password for our (non-root) user:

vncpasswd

Next, we have to create the vnc startup file in our user home directory and make it executable:

cd
mkdir .vnc
touch ~/.vnc/xstartup
chmod 755 ~/.vnc/xstartup

The contents of this file is

#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus
exec startxfce4 

For starting the VNC server on boot, we change to root again with sudo -i and create a service file /etc/systemd/system/vncserver@.service, as suggested by Install Xfce VNC remote desktop on Ubuntu.

[Unit]
Description=Remote desktop service (VNC)
After=syslog.target network.target

[Service]
Type=simple
User=test01
PAMName=login
PIDFile=/home/%u/.vnc/%H%i.pid
ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill :%i > /dev/null 2>&1 || :'
ExecStart=/usr/bin/vncserver :%i -geometry 1440x900 -alwaysshared -fg
ExecStop=/usr/bin/vncserver -kill :%i

[Install]
WantedBy=multi-user.target

In the Service section, we replace test01 by the username of our local user.

To enable the service by default, we make the service available at boot time by

cd /etc/systemd/system/multi-user.target.wants/
ln -s /etc/systemd/system/vncserver@.service ./vncserver@1.service

Time for a last reboot!

Then, we should be able to login to http://test.example.com:8080/guacamole with the credentials we stored in /etc/guacamole/user-mapping.xml, click on “Terminal Server VNC”, type in the VNC password we have defined before, and see a virtual XFCE screen in our browser.

That’s it! Now we have set up a Guacamole HTML5 remote XFCE desktop via VNC for Ubuntu 24.04.

For security reasons, it makes also sense to map the Tomcat (http port 8080) via Apache or nginx reverse proxy to https, as described in the linked article. The reverse proxy config for Apache should look like this

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerAdmin root@localhost

        ProxyPass / http://10.10.10.10:8080/guacamole/ flushpackets=on
        ProxyPassReverse / http://10.10.10.10:8080/guacamole/
        ProxyPassReverseCookiePath /guacamole /
        <Location /websocket-tunnel>
                Order allow,deny
                Allow from all
                ProxyPass ws://10.10.10.10:8080/guacamole/websocket-tunnel
                ProxyPassReverse ws://10.10.10.10:8080/guacamole/websocket-tunnel
        </Location>
        SetEnvIf Request_URI "^/tunnel" dontlog
        CustomLog  /var/log/apache2/guac.log common env=!dontlog

        ErrorLog ${APACHE_LOG_DIR}/error.log

ServerName test.example.com
SSLCertificateFile /etc/letsencrypt/live/test.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/test.example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

with IP addresses and urls amended for our real host.

For security reasons, it makes absolutely sense to add a 2FA as described in the already mentioned (german) article by Bernhard Linz. For DUO 2FA, the guacamole.properties must contain the entries

##Duo Security
duo-api-hostname: api-abcdef.duosecurity.com
duo-client-id: 71AB20ED12022941C91B
duo-client-secret: eyGPfDI1rJmQVpnuXvyixt7Ndzc0n98Zl1zSPHPb
duo-redirect-uri: https://test.example.com

with the appropriate data from the DUO website and our url.

Addena:

1

If you have a virtual server at a provider like Netcup which provides a VNC console to the machine, after the last reboot you’ll end up in a graphical login screen that produces a deadlock. To avoid being locked out you can change the default boot target:

sudo systemctl set-default multi-user.target

After a reboot you’ll see the console login again.

2

In order to start applications like Firefox etc from the command line, append the following to the .bashrc file:

XAUTHORITY=$HOME/.Xauthority
export XAUTHORITY