Setup of a Guacamole HTML5 remote XFCE desktop via VNC for Ubuntu 24.04
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