How to install Apache Guacamole with Docker and MySQL
I've been using jwetzell/guacamole
docker image for quite some time now and mostly been happy with it. But I would like to start using the official Guac image as I prefer to use official images in case development of a custom image gets dropped in the future.
The reason why I started with the custom image was simple - I had issues with running the official image and I couldn't figure out what I was doing wrong. So, I decided to tackle this project again and I was intent on making it work this time.
Finally, with some tweaking, I was able to make it work.
So, let's start with the easy part, docker-compose file:
version: "3"
services:
# daemon
bastion-dmn:
image: guacamole/guacd
container_name: bastion-dmn
restart: unless-stopped
volumes:
- "/etc/localtime:/etc/localtime:ro"
- /path/to/docker/dir/drive:/drive:rw
- /path/to/docker/dir/record:/record:rw
networks:
other:
# mysql
bastion-db:
container_name: bastion-db
image: mariadb:10.9.5
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_DATABASE: 'guacamole_db'
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- '/path/to/docker/dir/db-data:/var/lib/mysql'
networks:
other:
restart: always
# guacamole
bastion-fe:
container_name: acceess-fe
depends_on:
- bastion-dmn
- bastion-db
environment:
GUACD_HOSTNAME: bastion-dmn
MYSQL_DATABASE: guacamole_db
MYSQL_HOSTNAME: bastion-db
MYSQL_PASSWORD: '${MYSQL_PASSWORD}'
MYSQL_USER: '${MYSQL_USER}'
image: guacamole/guacamole:latest
links:
- bastion-dmn
restart: always
volumes:
- /path/to/docker/dir/drive:/drive:rw
labels:
- traefik.enable=true
- traefik.http.services.bastion.loadbalancer.server.port=8080
- "traefik.http.routers.bastion.rule=Host(`bastion.domain.com`)"
- traefik.http.routers.bastion.tls.certresolver=zero
- traefik.http.routers.bastion.entrypoints=websecure
- traefik.http.routers.bastion.middlewares=guac-addprefix
- "traefik.http.middlewares.guac-addprefix.addprefix.prefix=/guacamole"
networks:
external:
other:
networks:
external:
external: true
other:
external: true
A few things here. I'm using two networks - one called external
and the other one called other
. I'm used to placing dockers to different networks, even though both are considered external, just because I like to separate things that will be exposed to the Internet (such as guacamole
container) from the ones that are staying local (guacd
and mysql
).
Also, I'm using previously configured traefik
to provide reverse proxy to the container and from there I'm mapping port 8080
to be intercepted by traefik
and provide access to it. I'm also providing SSL certificates to the container via previously configured certresolver
called zero
which uses ZeroSSL
.
Another thing that I've added is a traefik middleware
called guac-addprefix
and adding it to the router bastion
. This allows me to access the frontend by using the bastion.domain.com
in URL instead of using bastion.domain.com/guacamole
.
Everything else is more or less standard, except for a few variables (MYSQL_PASSWORD
and MYSQL_USER
) that are defined in the .env
file.
Main issue I was having before was the fact that, if I remember correctly, I never initialized the database before I deployed the containers.
Hopefully I'm not missing any steps here, but this is how I did it this time and was actually successful.
First things first, we need to create an initial database. The easiest way to do it is this:
docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql
This will create a file called initdb.sql
that we will use inside of a container to populate the database.
Next, let's start the database container only:
docker compose up -d bastion-db
Next, we will copy the previously created database file to the container itself:
docker cp initdb.sql bastion-db:/guac_db.sql
We could've mapped a directory to bastion-db
and create the initial db there, but this works as well.
Then, we enter the container:
docker exec -it bastion-db bash
Because we initialized the container with user, database and root password, all of it should already be created in MySQL
, but if not, you can always create them manually. First, enter MySQL
as root
user:
mysql -u root -p
Make modifications to the database (you can change the user and the password variabls to your liking):
ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';
CREATE DATABASE guacamole_db;
CREATE USER 'guacamole_user'@'%' IDENTIFIED BY 'password';
GRANT SELECT,INSERT,UPDATE,DELETE ON guacamole_db.* TO 'guacamole_user'@'%';
FLUSH PRIVILEGES;
Remember, if you make changes to the database, you will most likely need to change some of the environment variables in your docker-compose
file. Exit MySQL
with quit
command after you're done.
Finally, populate the initial database with the proper tables:
cat guac_db.sql | mysql -u root -p guacamole_db
If you want, you can check if the tables have been created:
mysql -u admin -p
I changed the guacamole_user
to admin
so I use that to log into MySQL
. Once in, check status of the guacamole_db
:
use guacamole_db;
show tables;
Result should be something like this:
+---------------------------------------+
| Tables_in_guacamole_db |
+---------------------------------------+
| guacamole_connection |
| guacamole_connection_attribute |
| guacamole_connection_group |
| guacamole_connection_group_attribute |
| guacamole_connection_group_permission |
| guacamole_connection_history |
| guacamole_connection_parameter |
| guacamole_connection_permission |
| guacamole_entity |
| guacamole_sharing_profile |
| guacamole_sharing_profile_attribute |
| guacamole_sharing_profile_parameter |
| guacamole_sharing_profile_permission |
| guacamole_system_permission |
| guacamole_user |
| guacamole_user_attribute |
| guacamole_user_group |
| guacamole_user_group_attribute |
| guacamole_user_group_member |
| guacamole_user_group_permission |
| guacamole_user_history |
| guacamole_user_password_history |
| guacamole_user_permission |
+---------------------------------------+
23 rows in set (0.000 sec)
If everything is OK, quit MySQL
with quit
command and then use exit
to exit the container itself.
Finally, it's time to start the rest of the containers. Run docker compose up -d
or docker-compose up -d
, depending on the version you're running and it should pull the rest of the containers and start them. Your new Apache Guacamole should now be available at https://bastion.domain.com
, and if you have traefik
properly set up, it should pull an SSL cert for you as well. Don't forget that you also need a working DNS server in your own network to resolve this new host.
Member discussion