Apache Guacamole is a clientless remote desktop gateway. It supports standard protocols like VNC, RDP, and SSH.
It is clientless because no plugins or client software are required.
Thanks to HTML5, once Guacamole is installed on a server, all you need to access your desktops is a web browser.
Below I’m going to discuss how to install Guacamole and it’s TOTP module (aka login with 2FA) on Ubuntu 24.04.3 LTS.
Understanding the pieces:
guacamole-server (aka guacd) = native daemon that speaks RDP/VNC/SSH, must be built from source.
guacamole web app = a .war deployed to Tomcat (we’ll use Tomcat 9).
Auth = we’ll use MariaDB (JDBC extension).
Guacamole 1.6.0 provides the WAR + JDBC extension prebuilt; only guacamole-server is compiled.
Packages & build dependencies
|
1 2 3 4 5 6 7 |
sudo apt update sudo apt install -y build-essential autoconf automake libtool-bin \ libcairo2-dev libjpeg-turbo8-dev libpng-dev uuid-dev libssl-dev \ libavcodec-dev libavformat-dev libavutil-dev libswscale-dev \ libpango1.0-dev libssh2-1-dev libtelnet-dev libvncserver-dev \ libwebsockets-dev libpulse-dev libvorbis-dev libwebp-dev \ freerdp3-dev wget curl fonts-dejavu-core |
Build and start guacd (guacamole-server 1.6.0)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
cd /usr/src sudo wget https://downloads.apache.org/guacamole/1.6.0/source/guacamole-server-1.6.0.tar.gz sudo tar xzf guacamole-server-1.6.0.tar.gz cd guacamole-server-1.6.0 # The systemd dir below is correct for Ubuntu; the FreeRDP flag keeps things lenient. sudo ./configure --with-systemd-dir=/etc/systemd/system --enable-allow-freerdp-snapshots sudo make -j"$(nproc)" sudo make install sudo ldconfig # Register and start the service sudo systemctl daemon-reload sudo systemctl enable --now guacd systemctl status guacd --no-pager |
Install Java and Tomcat 9 (not Tomcat 10)
Note: Guacamole 1.x targets the javax servlet APIs (Tomcat 9). Tomcat 10 switched to jakarta and isn’t supported yet.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# Java (LTS) sudo apt install -y openjdk-17-jdk # Create a dedicated tomcat user sudo useradd -m -U -d /opt/tomcat -s /bin/false tomcat # Download & install Tomcat 9 (set the latest 9.0.x available) TOMCAT_VER=9.0.108 cd /tmp wget https://dlcdn.apache.org/tomcat/tomcat-9/v${TOMCAT_VER}/bin/apache-tomcat-${TOMCAT_VER}.tar.gz sudo mkdir -p /opt/tomcat sudo tar xzf apache-tomcat-${TOMCAT_VER}.tar.gz -C /opt/tomcat --strip-components=1 sudo chown -R tomcat:tomcat /opt/tomcat # Tell Tomcat where GUACAMOLE_HOME lives sudo bash -c 'cat >/opt/tomcat/bin/setenv.sh <<EOF export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java)))) export GUACAMOLE_HOME=/etc/guacamole EOF' sudo chmod +x /opt/tomcat/bin/setenv.sh # Systemd unit for Tomcat 9 sudo tee /etc/systemd/system/tomcat.service >/dev/null <<'EOF' [Unit] Description=Apache Tomcat 9 After=network.target [Service] Type=forking User=tomcat Group=tomcat UMask=0007 Environment=CATALINA_BASE=/opt/tomcat Environment=CATALINA_HOME=/opt/tomcat Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid ExecStart=/opt/tomcat/bin/startup.sh ExecStop=/opt/tomcat/bin/shutdown.sh Restart=on-failure [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now tomcat systemctl status tomcat --no-pager |
Prepare GUACAMOLE_HOME and deploy the 1.6.0 WAR
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Config directories used by Guacamole/Tomcat sudo mkdir -p /etc/guacamole/{extensions,lib} # Basic properties so the webapp can reach guacd sudo tee /etc/guacamole/guacamole.properties >/dev/null <<'EOF' guacd-hostname: 127.0.0.1 guacd-port: 4822 EOF # Deploy the 1.6.0 web app sudo wget -O /opt/tomcat/webapps/guacamole.war \ https://downloads.apache.org/guacamole/1.6.0/binary/guacamole-1.6.0.war # Restart Tomcat to unpack the WAR sudo systemctl restart tomcat |
Install MariaDB and the JDBC auth extension
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# DB server sudo apt install -y mariadb-server # Create DB and user (change the password!) DB_PASS='ChangeMe_Secure!' sudo mysql -e "CREATE DATABASE guacamole_db DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;" sudo mysql -e "CREATE USER 'guacamole_user'@'localhost' IDENTIFIED BY '${DB_PASS}';" sudo mysql -e "GRANT ALL PRIVILEGES ON guacamole_db.* TO 'guacamole_user'@'localhost'; FLUSH PRIVILEGES;" # JDBC extension (MySQL/MariaDB flavor) cd /usr/src sudo wget https://downloads.apache.org/guacamole/1.6.0/binary/guacamole-auth-jdbc-1.6.0.tar.gz sudo tar xzf guacamole-auth-jdbc-1.6.0.tar.gz sudo cp guacamole-auth-jdbc-1.6.0/mysql/guacamole-auth-jdbc-mysql-1.6.0.jar /etc/guacamole/extensions/ # Initialize the schema cd guacamole-auth-jdbc-1.6.0/mysql sudo bash -lc "cat schema/*.sql | mysql -u root guacamole_db" # JDBC driver (Connector/J 8.4 LTS JAR) sudo wget -O /etc/guacamole/lib/mysql-connector-j-8.4.0.jar \ https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.4.0/mysql-connector-j-8.4.0.jar # Point Guacamole at the database sudo tee -a /etc/guacamole/guacamole.properties >/dev/null <<EOF # --- JDBC auth (MariaDB/MySQL) --- mysql-hostname: 127.0.0.1 mysql-port: 3306 mysql-database: guacamole_db mysql-username: guacamole_user mysql-password: ${DB_PASS} # Explicit driver class for Connector/J 8+ mysql-driver: com.mysql.cj.jdbc.Driver EOF # Bounce services sudo systemctl restart guacd tomcat |
Log in and secure it
-
rowse to:
http://<server>:8080/guacamole -
Default admin (created by the schema):
guacadmin/guacadmin→ change it immediately (Settings → Preferences), then create your own admin and deleteguacadmin.
Now, let’s install and the TOTP Module:
Download + verify (from Apache archive)
|
1 2 3 4 5 6 7 8 |
cd /tmp curl -fL -o guacamole-auth-totp-1.6.0.tar.gz \ https://archive.apache.org/dist/guacamole/1.6.0/binary/guacamole-auth-totp-1.6.0.tar.gz curl -fsSL -o guacamole-auth-totp-1.6.0.tar.gz.sha256 \ https://archive.apache.org/dist/guacamole/1.6.0/binary/guacamole-auth-totp-1.6.0.tar.gz.sha256 # must say: “guacamole-auth-totp-1.6.0.tar.gz: OK” sha256sum -c guacamole-auth-totp-1.6.0.tar.gz.sha256 |
Install the extension jar
|
1 2 3 4 5 |
tar -xzf guacamole-auth-totp-1.6.0.tar.gz sudo install -D -m 0644 guacamole-auth-totp-1.6.0/guacamole-auth-totp-1.6.0.jar \ /etc/guacamole/extensions/guacamole-auth-totp-1.6.0.jar ls -l /etc/guacamole/extensions |
Restart Tomcat (not guacd) and check logs
|
1 2 3 4 |
sudo systemctl restart tomcat # Confirm GUACAMOLE_HOME and TOTP load: grep -i 'GUACAMOLE_HOME is' /opt/tomcat/logs/catalina.out | tail -n1 egrep -i 'Extension "TOTP Authentication"|totp' /opt/tomcat/logs/catalina.out | tail -n2 |
If it loaded, you’ll see something like:
Extension “TOTP Authentication” (totp) loaded.
Enjoy!
