Apache Guacamole: Session recordings and playback in-browser — version 2

Kenneth KOFFI
3 min readNov 23, 2023

--

Photo by Denise Jans on Unsplash

Assuming you’ve installed Apache Guacamole as per my manual installation blog post, this article guides you through enabling graphical session recording playback in the browser.

Create record directory

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 frontend (guacamole/guacd) container can write to the directory.
  • The backend (guacamole/guacamole) container 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 installation blog post:

  • The record folder should be mounted as a volume to both the guacamole_backend container and the guacamole_frontend container.
  • We must set the RECORDING_SEARCH_PATH environment variable

So the complete version of the new ${HOME}/docker-stack/guacamole/docker-compose.yml file be like:

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.3
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:15.0
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:
GUACD_HOSTNAME: guacd
POSTGRESQL_DATABASE: guacamole_db
POSTGRESQL_HOSTNAME: postgres
POSTGRESQL_PASSWORD: '${POSTGRES_PASSWORD}'
POSTGRESQL_USER: '${POSTGRES_USER}'
POSTGRESQL_AUTO_CREATE_ACCOUNTS: true
RECORDING_SEARCH_PATH: '/var/lib/guacamole/recordings'
image: guacamole/guacamole:1.5.3
links:
- guacd
networks:
- guacamole_net
- haproxy_net
restart: always
volumes:
- ./drive:/drive:rw
- ./record:/var/lib/guacamole/recordings:ro

What changed?

Check out the output of the diff command:

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.3
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:15.0
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:
GUACD_HOSTNAME: guacd
POSTGRESQL_DATABASE: guacamole_db
POSTGRESQL_HOSTNAME: postgres
POSTGRESQL_PASSWORD: '${POSTGRES_PASSWORD}'
POSTGRESQL_USER: '${POSTGRES_USER}'
POSTGRESQL_AUTO_CREATE_ACCOUNTS: true
+ RECORDING_SEARCH_PATH: '/var/lib/guacamole/recordings'
image: guacamole/guacamole:1.5.3
links:
- guacd
networks:
- guacamole_net
- haproxy_net
restart: always
volumes:
- ./drive:/drive:rw
+ - ./record:/var/lib/guacamole/recordings:ro

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 session playback demo video

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.

--

--

Kenneth KOFFI

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