Apache Guacamole: Session recordings and playback in-browser

Kenneth KOFFI
4 min readJun 24, 2023

--

Photo by Jakob Owens on Unsplash

Note: A new version of this article is available. Please check it out if you have Apache Guacamole version ≥ 1.5.3 installed.

Otherwise, keep reading this one.

Since the version 1.5.0, Apache Guacamole finally supports a long-wanted feature: playback of session recordings directly within the web application.

Prior to that version, a CLI tool guacenc was required to translate session recordings to a normal video stream before playing. But this new feature makes things so much easier. A View button is now available in the connection history to play your graphical session recordings directly from the browser.

Read below about how to enable and use it for a Docker based installation of Guacamole. If you don’t have Guacamole installed yet, check out my step-by-step Apache Guacamole: manual installation with docker-compose blog post. This current writing is relying on it.

Configuration

To make that view button appears, the guacamole-history-recording-storage extension is needed. You need to download the extension version which match with your Guacamole version. Check out the Guacamole releases page.

Install the recording storage extension

Based on the previous article, your ${HOME}/docker-stack/guacamole folder architecture looks as follows:

.
|-- data
|-- docker-compose.yml
|-- drive
|-- init
`-- record

We need to create a new folder in that directory to store the extension

mkdir -p ${HOME}/docker-stack/guacamole/guacamole_home/extensions/

Since my Guacamole version is 1.5.0, I’m going to download the guacamole-history-recording-storage-1.5.0 and store it under the folder created previously.

wget -O /tmp/guacamole-history-recording-storage-1.5.0.tar.gz https://archive.apache.org/dist/guacamole/1.5.0/binary/guacamole-history-recording-storage-1.5.0.tar.gz && tar -xf /tmp/guacamole-history-recording-storage-1.5.0.tar.gz -C ${HOME}/docker-stack/guacamole/guacamole_home/extensions/ --strip-components=1

The execution of the command above results into the folder structure below:

${HOME}/docker-stack/guacamole/guacamole_home/
`-- extensions
|-- LICENSE
|-- NOTICE
`-- guacamole-history-recording-storage-1.5.0.jar

As you can see, the guacamole-history-recording-storage extension is a .jar which must be placed into the .../guacamole_home/extensions folder.

Create record directory

After the extension installation, we need to create the directory where all the sessions records will be stored.

mkdir ${HOME}/docker-stack/guacamole/record

That folder requires some specific permissions:

- The guacd service can write to the directory.

- The servlet container (typically Tomcat) can read from the directory, as well as read any files that are placed within the directory.

In order to meet these requirements, we need to get the UID of the guacamole_backend container:

root@instance:/# docker exec -it guacamole_backend id
uid=1000(guacd) gid=1000(guacd) groups=1000(guacd)

And the GID of the guacamole_frontend container:

root@instance:/# docker exec -it guacamole_frontend id
uid=1001(guacamole) gid=1001(guacamole) groups=1001(guacamole)

Then we modify the permissions and ownerships :

sudo chown -R 1000:1001 ${HOME}/docker-stack/guacamole/record
sudo chmod -R 2750 ${HOME}/docker-stack/guacamole/record

Update docker-compose

We need to edit the ${HOME}/docker-stack/guacamole/docker-compose.yml file we created in the previous blog post. The record folder should be mounted as a volume to the containers.

  • guacd service

We need to mount the ./record directory to ./record:/var/lib/guacamole/recordings:rw like below:

[...]

# services
services:
# guacd
guacd:
[...]
volumes:
- ./drive:/drive:rw
- ./record:/var/lib/guacamole/recordings:rw

[...]
  • guacamole service

We need to update the guacamole service like below:

[...]

# guacamole
guacamole:
[...]
environment:
[...]
GUACAMOLE_HOME: '/opt/guacamole_home'
[...]
volumes:
- ./guacamole_home:/opt/guacamole_home
- ./record:/var/lib/guacamole/recordings:ro
- ./drive:/drive:rw

What changed?

We introduced a new environment variable GUACAMOLE_HOME. We also added the volumes ./record:/var/lib/guacamole/recordings:ro and ./guacamole_home:/opt/guacamole_home

The complete version of the docker-compose.yml file can be found as an annex at the end of this article.

Now let’s apply these changes:

docker compose -f ${HOME}/docker-stack/guacamole/docker-compose.yml up -d

Testing

Edit the “Screen Recording” section of one of your existing connection settings. Enter the special value ${HISTORY_PATH}/${HISTORY_UUID} in the “Recording path” input box.

Check the “Automatically create recording path” box.

Demo

Apache guacamole demo session recordings in-browser playback

Thank you for reading this article all the way to the end! I hope you found the information and insights shared here to be valuable and interesting. Get in touch with me on LinkedIn.

I appreciate your support and look forward to sharing more content with you in the future. Until next time!

This post also appears on my personal Blog.

Annex

The complete docker-compose.yml file:

version: '3.9'

# networks
# create a network 'guacamole_net' in mode 'bridged'
networks:
guacamole_net:
driver: bridge
haproxy_net:
external: true

# services
services:
# guacd
guacd:
container_name: guacamole_backend
image: guacamole/guacd:1.5.0
networks:
guacamole_net:
restart: always
volumes:
- ./drive:/drive:rw
- ./record:/var/lib/guacamole/recordings:rw

# postgres
postgres:
container_name: guacamole_database
environment:
PGDATA: /var/lib/postgresql/data/guacamole
POSTGRES_DB: guacamole_db
POSTGRES_PASSWORD: '${POSTGRES_PASSWORD}'
POSTGRES_USER: '${POSTGRES_USER}'
image: postgres:13.4
networks:
guacamole_net:
restart: always
volumes:
- ./init:/docker-entrypoint-initdb.d:ro
- ./data:/var/lib/postgresql/data:rw

# guacamole
guacamole:
container_name: guacamole_frontend
depends_on:
- guacd
- postgres
environment:
GUACAMOLE_HOME: '/opt/guacamole_home'
GUACD_HOSTNAME: guacd
POSTGRES_DATABASE: guacamole_db
POSTGRES_HOSTNAME: postgres
POSTGRES_PASSWORD: '${POSTGRES_PASSWORD}'
POSTGRES_USER: '${POSTGRES_USER}'
POSTGRESQL_AUTO_CREATE_ACCOUNTS: true
image: guacamole/guacamole:1.5.0
links:
- guacd
networks:
- guacamole_net
- haproxy_net
restart: always
volumes:
- ./guacamole_home:/opt/guacamole_home
- ./record:/var/lib/guacamole/recordings:ro
- ./drive:/drive:rw

--

--

Kenneth KOFFI

Administrateur systèmes avec une appétence pour le Cloud et le DevOps