Migrating and Upgrading Apache Guacamole to Docker

UPDATED: I have created an all-in-one (AIO) version that includes nginx using TLS.

Apache Guacamole is a client-less remote desktop gateway. I use it in order to access my lab when traditional methods are not available. Guacamole does not use agents or fancy plugins, you only need an HTML5 supported browser and you can access your desktop or server in the cloud.

I started with version 0.9.14 of Guacamole. When version 1.0 was released, I decided to move away from Chase Wright’s all-in-one script and roll my own micro-services docker setup. This blog post covers the steps I took to deploy a containerized guacamole setup.


Docker CE
Docker Compose

The first step was to get a backup and secure it somewhere safe:

mysqldump -u root -p --add-drop-table guacamole_db > guacamole_db.sql

We also need to get the database initialization schema. The database backup we just made is from version 0.9.14 so I wrote a script to get that version of the initialization schema from the guacamole repositories, but you can also use docker and the correct tag:

sudo docker run --rm guacamole/guacamole:0.9.14 /opt/guacamole/bin/initdb.sh --mysql > v0.9.14-initdb.sql

In addition to the initialization schema we will also need the applicable upgrade schema. If you are using a version of guacamole older than 0.9.14 then also copy the intermediate upgrades scripts.

wget -q https://archive.apache.org/dist/guacamole/1.0.0/binary/guacamole-auth-jdbc-1.0.0.tar.gz
tar xf guacamole-auth-jdbc-1.0.0.tar.gz
cp guacamole-auth-jdbc-1.0.0/mysql/schema/upgrade/upgrade-pre-1.0.0.sql .

At this point you should have a backup of the database, the initialization schema, and the upgrade schema(s).

Next create the persistent volume for your database:

sudo docker volume create db
mech@labs(~):$ sudo docker volume ls
local               db

Pull and launch the database docker image:

sudo docker run -e MYSQL_ROOT_PASSWORD=ladybug --name db -h db --mount source=db,target=/var/lib/mysql -d --rm mariadb:10.0

Verify the image is running (the output is abbreviated):

mech@labs(~):$ docker ps -l
CONTAINER ID    IMAGE             PORTS        NAMES
bbcf0a744087    mariadb:10.0      3306/tcp     db

Copy the backup database, the schema initialization file, and the applicable schema upgrade script(s) to the database container:

mech@labs(~):$ ls *.sql
guacamole_db.sql  upgrade-pre-1.0.0.sql  v0.9.14-initdb.sql
mech@labs(~):$ for i in *.sql; do sudo docker cp $i db:/tmp ; done

Enter the database container and configure the database:

sudo docker exec -it db bash
roo@db:/# mysql -u root -p
Enter password:
MariaDB [(none)]> show databases;
| Database           |
| information_schema |
| mysql              |
| performance_schema |
3 rows in set (0.00 sec)
MariaDB [(none)]> create database guacamole_db;
MariaDB [(none)]> show databases;
| Database           |
| guacamole_db       |
| information_schema |
| mysql              |
| performance_schema |
4 rows in set (0.00 sec)
MariaDB [(none)]> use guacamole_db;
MariaDB [guacamole_db]> system ls /tmp
guacamole_db.sql  upgrade-pre-1.0.0.sql  v0.9.14-initdb.sql

The following steps MUST be done in order:

1. Load the initialization schema.
2. Load the backup (mysqldump).
3. Load the schema upgrade script(s).

Note: If you have multiple upgrade schemas, they must be loaded individually and sequentially.

MariaDB [guacamole_db]> source /tmp/v0.9.14-initdb.sql
MariaDB [guacamole_db]> source /tmp/guacamole_db.sql
MariaDB [guacamole_db]> source /tmp/upgrade-pre-1.0.0.sql

Exit and stop the container.

sudo docker stop db

Create a project directory and support files:

mkdir guacamole && cd guacamole
touch mysql-root guacamole-user
touch .env docker-compose.yml

Warning: The following instructions employ credentials in clear-text on the file system. The use of docker secrets without a docker swarm is a workaround for development and testing. I would not recommend using this configuration in production without the proper mechanisms to protect the credentials. I am using this in a lab environment and have made some risk decisions specific to my use case. Credentials using environment variables are also easily leaked using docker inspect for any user with admin access to the docker command.

Edit the guacamole-user file so that it contains the password for the database user guacamole_user. Then edit the mysql-root file so it has the MySQL root user password.

The .env file is used to set environment variables that are referenced in the docker-compose.yml. If you look at line 46 below we are using the environment variable ${MYSQL_PASSWORD}. In order for docker compose to assign a value to this variable you will need to edit the .env file so it has a matching key=value pair. For instance:  MYSQL_PASSWORD=cyb3rsecr3t

Note: The guacamole docker image does not support using secrets with the MYSQL_PASSWORD environment variable

This docker compose file will pull, launch and link mariadb, guacd, and guacamole:

## Guacamole 20190318
# @c0demech
version: "3.1"
# Configure MariaDB with persistent storage
    image: mariadb:10.0
    hostname: db
    restart: always
      MYSQL_ROOT_PASSWORD_FILE: '/run/secrets/mysql-root'
      MYSQL_DATABASE: 'guacamole_db'
      MYSQL_USER: 'guacamole_user'
      MYSQL_PASSWORD: '/run/secrets/guacamole-user'
    container_name: db 
      - "db:/var/lib/mysql"
      - mysql-root
      - guacamole-user
# Configure proxy daemon
    image: guacamole/guacd:1.0.0
    container_name: guacd
    restart: always
# Configure and link Guacamole to db and proxy
# expose port 8080 to host.
    image: guacamole/guacamole:1.0.0
    container_name: guacamole
    restart: always
      - 8080:8080
      - guacd
      - database
      GUACD_HOSTNAME: guacd
      MYSQL_DATABASE: guacamole_db
      MYSQL_USER: guacamole_user
      - guacamole-user
    file: mysql-root
    file: guacamole-user
# This volume has to be created before docker-compose up
    external: true

We need to constrain the permissions of our sensitive files:

mech@labs(guacamole):$ pwd
mech@labs(guacamole):$ ls -A
docker-compose.yml  .env  guacamole-user  mysql-root
mech@labs(guacamole):$ chmod 600 .env
mech@labs(guacamole):$ chmod 600 *

Remember to stop the previous running version of our database, guacd and guacamole. Once that is complete, run the following command:

mech@labs(guacamole):$ sudo /usr/local/bin/docker-compose up -d
Creating network "guacamole_default" with the default driver
Creating db    ... done
Creating guacd ... done
Creating guacamole ... done

Finally, we check to see if our containers are running:

mech@labs(guacamole):$ sudo docker container ps
CONTAINER ID        IMAGE                       PORTS                    NAMES
72004c94f178        guacamole/guacamole:1.0.0>8080/tcp   guacamole
d32546a0c1eb        guacamole/guacd:1.0.0       4822/tcp                 guacd
8148f6916235        mariadb:10.0                3306/tcp                 db

Browse to your guacamole web address using port 8080 or adjust accordingly if you have a reverse proxy. Login with your credentials an if everything went well, remember to disable the startup of the old services. It is worth mentioning that I did not have to modify my reverse proxy. This is because port 8080 is exposed to the host by the guacamole container.

If you want to also use an apache or nginx docker container with this setup, it is fairly easy to adapt my docker-compose.yml above.

Thanks for reading.

2 thoughts on “Migrating and Upgrading Apache Guacamole to Docker”

    • @reedog117, I usually check the release notes to see if there are any special caveats such as upgrading the database schema, then I create a backup of my database followed by changing the version number in the docker-compose.yml for guacd and guacamole.

      image: guacamole/guacd:1.0.0
      image: guacamole/guacamole:1.0.0

      image: guacamole/guacd:1.1.0
      image: guacamole/guacamole:1.1.0

      This is one of the major reasons I switched to using containers and created my guacamole-docker-compose repo on GitHub.


Start a discussion or ask a question.

This site uses Akismet to reduce spam. Learn how your comment data is processed.