Apache Guacamole is a web-accessible remote desktop gateway that supports RDP, VNC, and text-based connections via SSH and telnet.

Quick introduction[edit | edit source]

The Guacamole server contains two parts: The web application itself running on Tomcat, and the guacamole proxy service (guacd) that connects to the remote desktop endpoints. Under the hood, the RDP/VNC/SSH connection data from guacd is sent to the Guacamole server using the Guacamole protocol which is then relayed back to the user and rendered using Guacamole's HTML5 based client. As a result, the client is unaware of the underlying protocol (which actually poses several limitations which will be covered later).

Limitations[edit | edit source]

Guacamole's documentation doesn't list limitations clearly and these are the limitations that I've encountered after playing with it for a short period.

  • Guacamole must connect to a VNC enabled desktop either anonymously or with pre-defined credentials. You cannot have Guacamole 'login' for a user using their Guacamole credentials.
  • RDP works like VNC but with NLA support for RDP (I haven't tested this) which would allow the user to enter their RDP credentials when connecting. There is no way to make Guacamole pass credentials to RDP however, so you can't make Guacamole work like a VDI using a pool of desktops.
  • In VNC, sessions cannot be 'resized' on the fly. Guacamole's protocol doesn't seem to support it.
  • In VNC, copy/paste clipboard data cannot be copied out of a remote desktop; it can only be copied in. This works if I use x11vnc as the VNC server rather than the Gnome built-in screen sharing feature.
  • VNC based connections are extremely slow. Using x11vnc is slightly better than vino, but there's easily 1-2 second delays on my local instance all hosted on the same hypervisor and accessed via a local gigabit LAN connection.
  • VNC connection settings hard code authentication credentials. You cannot 'login' as a user on the remote desktop

Setup[edit | edit source]

You can either install Guacamole directly on a server or use the prebuilt Docker containers. Review the documentation at:

Setup Guacamole using Docker Compose[edit | edit source]

The easiest way to set up Guacamole is with the following docker-compose.yml stack. I am using Traefik as the reverse proxy which handles SSL termination and strips the /guacamole from the URI path, but is completely optional. If you don't use Traefik, simply remove the Traefik network and labels and serve port 8080.

First, create the following docker-compose.yml file.

version: '3.3'

    image: guacamole/guacd
    restart: unless-stopped
      - /volumes/guacamole/guacd/drive:/drive:rw
      - /volumes/guacamole/guacd/record:/record:rw
      - internal

    image: guacamole/guacamole
    restart: unless-stopped
      - guacd
      - db
      GUACD_HOSTNAME: guacd
      MYSQL_DATABASE: guacamole
      MYSQL_USER: guacamole
      MYSQL_PASSWORD: 41e930486c6de5ebda96  <-- change me
      - "8080"
      - traefik.enable=true
      - traefik.docker.network=traefik
      - traefik.http.middlewares.guacamole-prefix.addprefix.prefix=/guacamole
      - traefik.http.middlewares.guacamole-https-redirect.redirectscheme.scheme=https
      # http
      - traefik.http.routers.guacamole.entrypoints=http
      - traefik.http.routers.guacamole.rule=Host(`guacamole.steamr.com`)
      - traefik.http.routers.guacamole.service=guacamole-https
      - traefik.http.routers.guacamole.middlewares=guacamole-https-redirect
      # https
      - traefik.http.routers.guacamole-https.entrypoints=https
      - traefik.http.routers.guacamole-https.rule=Host(`guacamole.steamr.com`)
      - traefik.http.routers.guacamole-https.tls=true
      - traefik.http.routers.guacamole-https.service=guacamole-https
      - traefik.http.services.guacamole-https.loadbalancer.server.port=8080
      - traefik.http.routers.guacamole-https.middlewares=guacamole-prefix
      - internal
      - traefik

    image: mariadb:latest
      MYSQL_ROOT_PASSWORD: 41e930486c6de5ebda96  <-- change me
      MYSQL_USER: guacamole
      MYSQL_PASSWORD: 41e930486c6de5ebda96  <-- change me
      MYSQL_DATABASE: guacamole
    restart: unless-stopped
      # To obtain this file, run: docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql
      - /volumes/guacamole/initdb.sql:/initdb.sql
      - /volumes/guacamole/db:/var/lib/mysql/:rw
      - internal

    name: traefik
    external: true

Next, bring the container stack up:

# docker-compose pull
# docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > /volumes/guacamole/initdb.sql
# docker-compose up -d

Set up the database:

## Figure out which container is your database and then load the initial database
# docker ps | grep guacamole
# docker exec -ti $DB_CONTAINER_ID bash
root@db # mysql -u root -p$MYSQL_ROOT_PASSWORD $MYSQL_DATABASE < /initdb.sql
Guacamole Login
Guacamole Login

You should be able to reach the Guacamole server and see a login page. If not, restart the Guacamole container and try again. If you see an error message, you likely misconfigured the database connection or didn't populate the Guacamole database properly.

Login using the following credentials:

  • Username: guacadmin
  • Password: guacadmin

When setting up a new connection, enter 'guacd' as the Guacamole proxy hostname, 4822 as the port, and 'none' for encryption.

Setting up a VNC connection[edit | edit source]

Log in as an administrator and navigate to 'Settings', then 'Connections'. Click on 'New Connection'. Specify the following:

  1. guacd: If using the Docker compose stack above, the hostname would just be 'guacd' on port 4822 without encryption
  2. parameters: The hostname to your VNC server. Port is typically 5900. I leave all other fields blank. I use X11vnc as my VNC server which starts up with my login.
  3. Audio: The 'Audio server name' should point to a PulseAudio service. To make this work, you will have to tweak PulseAudio to allow remote connections via TCP. Edit /etc/pulse/default.pa and uncomment out the line 'load-module module-native-protocol-tcp'. Add the following arguments to the module such that the final linke looks like this: load-module module-native-protocol-tcp auth-ip-acl= auth-anonymous=1. Restart PulseAudio (killall pulseaudio should work and it should be restarted automatically or just reboot). Verify it's working by running ss -lntp | grep 4713.

Using Guacamole[edit | edit source]

Review the documentation at https://guacamole.apache.org/doc/gug/using-guacamole.html.

Alt + Ctrl + Shift is used to bring up or hide the Guacamole menu sidebar.

Tasks[edit | edit source]

Changing the default /guacamole URI path[edit | edit source]

The default URI path for Guacamole is /guacamole (Eg. http://server:8080/guacamole). You may wish to change it so that Guacamole is served on the root path (/).

The official Docker image[edit | edit source]

If using the Guacamole Docker image, restart the container with an environment variable WEBAPP_CONTEXT=ROOT.

Direct install on a server[edit | edit source]

If using Guacamole on a server directly, you will need to rename the guacamole Tomcat war file:

  1. Navigate to /var/lib/tomcat8/webapps/ and delete the guacamole directory.
  2. Rename the guacamole.war file to ROOT.war.
  3. Restart Tomcat

Traefik reverse proxy[edit | edit source]

If you're using Traefik as the reverse proxy, you can create a middleware that adds the /guacamole prefix transparently. Use the following configs with Traefik v2.


Troubleshooting[edit | edit source]

Incorrect VNC sessions screen size[edit | edit source]

I encountered an issue with x11vnc where the screen size is about 10-15 times taller than it should be. The contents of the extraneous areas appear to be bits and pieces of other windows and overlays. The cause of this was that x11vnc was started with the ncache option which is used to expand the framebuffer for caching windows and window contents. This however requires a VNC client that supports this option which Guacamole's proxy (guacd) doesn't seem to support.

To fix this issue, re-run x11vnc with the -noncache option.