Apache Guacamole: Session recordings and playback in-browser
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
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