Create Your Own Azure Bastion with Guacamole and Save $100+ a month

Microsoft Azure provides Azure Bastion service which is a jump server so you can securely access your virtual machines via its Azure Portal web interface without exposing SSH or RDP port. Here is its architecture:

This service is great except it costs $0.19 per hour. Combining with other components then this may costs you almost $150 a month. Bad news is you can’t stop it unless you delete it.

This post, I will show you how I create my own jump server on Ubuntu VM to replace Azure Bastion using Apache Guacamole which is an open source tool which provide similar functionalities (I wonder that Azure Bastion may be even built on top of it). The VM can be a small one that may costs only a few tens bucks per month.

Apache Guacamole

From its website, Apache Guacamole is a clientless remote desktop gateway that supports standard protocols like VNC, RDP, and SSH. Clientless means your clients don’t need to install anything but just use a web browser to remotely access your fleet of VMs.

The Guacamole comprises of two main components:

  • Guacamole Server which provides guacd which is like a proxy server for the client to connect to the remote server.
  • Guacamole Client which is a servelet container that user will log in and via web browser.

For more information about Guacamole, visit its architecture page.

As my disclaimer, installation is not simple as there are several components you need to install and configure before it is good enough to use. There may be simpler ways to deploy e.g. using Docker image or using this Helm chart but I haven’t tried them yet. Because of cost is my concern so I’d like to deploy on a small VM that may not run a Kubernetes cluster (and may be I just prefer to learn it in hard way :P).

Network Topology

You use Azure Bastion or a jump server because you want to secure your VMs behind so having the right network design is needed. Here it mine:

In my virtual network (VNet), I split into two subnets:

  1. snet-gateway where I will deploy Guacamole on a Ubuntu VM which has a public IP so its web interface can be reached from the Internet.
  2. snet-default where I will deploy my backend pool of VM and enable remote access via Guacamole only.

For the sake of security, you should configure Network Security Group (NSG) of your snet-gateway to limit inbound and outbound connections to/from Ubuntu VM in the same way as you do for AzureBastionSubnet. But in this example, I just associate NSG to the VM directly.

Once you setup your network then create the VMs. In this example, I create the following two VMs:

  1. vm-win10 in the snet-default which is the machine I will remote access to.
  2. vm-ubuntu1804 in the snet-gateway where I will install Guacamole and use it as a jump server. I choose B2s size which cost around $39 per month but, of course, you can change its size later.

Install Guacamole Server

Once your Ubuntu Server 18.04 is created then log in via SSH. You may need to expose SSH port publicly for now. You can change SSH port to something than 22 to make it more secure. See how to do it in my previous blog.

From its documentation, there’s no executable binary available for Guacamole server and you need to build it from source (unless you deploy from Docker image).

First you need to install build tools and all required dependencies for the build process. Missing some of them may result in missing features or build failure.

Next, download source codes and extract.

Configure the build and start the build.

Once done, install and start the service.

At this point, the Guacamole server (guacd) service should be up and running. Inspect by executing systemctl status guacd --no-pager.

Install Guacamole Client

Unlike the server, we don’t need to build it (but you can if you want). So we will download the WAR file and install on Tomcat server then expose it through nginx via HTTPS.

Install Tomcat

First, we need Tomcat to run the WAR file. Use this script to install it.

Configure Tomcat and start the service.

Now the Tomcat service should be up and running. Inspect by executing systemctl status tomcat.service --no-pager.

Add Guacamole Client Servlet

Download and add the WAR file to the Tomcat.

You may try to access the client at http://<your-server>:8080/ by either open or forward the port and you should see the Guacamole's login screen (but you can't login now).

In case you see Tomcat instead of Guacamole, restart Tomcat using command sudo systemctl restart tomcat and try again.

Install nginx and certbot

We will use nginx as a proxy and certbot to get a certificate from Let’s Encrypt.

Configure certbot with a domain and an email address and integrate with nginx.

Edit the file /etc/nginx/sites-enabled/default and replace the following section:

with this one:

This will set nginx as a proxy to your servlet. You don’t need to configure to redirect HTTP to HTTPS as that is already done by certbot.

Test the configuration and restart nginx.

Now you should be able to access Guacamole ay https://<your-server>/

Configure User and Connections

We will create a user with two connections in the user-mapping.xml file so we can test logging on.

Create the file /etc/guacamole/user-mapping.xml an put below content. Create the directory /etc/guacamole first if it does not exist.

The first connection is SSH to local server itself while the second one is RDP to Windows 10 VM. Don’t forget to update the username and password.

Restart Tomcat and test logging in and making the connections.

If everything is configured properly, you should be able to connect to your VMs via either SSH and RDP. However, you cannot change anything on the web GUI the configuration is static in the file user-mapping.xml

To make it editable via the web GUI, we need to install a database. In this example, I will use MySQL but Guacamole also supports other databases e.g. MariaDB, PostgreSQL. You can check for more information in this documentation page.

Install MySQL

Let’s install MySQL.

Check MySQL service status by executing systemctl status mysql --no-pager.

After install the MySQL, we also need to install the Guacamole extension and library so it knows how to talk to the database.

Configure Database

Next, we need to create a database and a user. In this example, I will create the database named guacamole_db and the user named guacamole_user. Please note the password must meet complexity criteria.

Then run the provides scripts to create schema and the Guacamole default user guacadmin.

Lastly, you need to configure Guacamole client so it can connect to the database by creating file /etc/guacamole/ and put the following content.

If you configure the user-mapping.xml file before then you may no longer need that so remove it.

Restart Tomcat and test logging in again using default username and password i.e. guacadmin.

Now, you should be able to make changes in the Settings. It is recommended you create a new user and then remove the guacadmin as soon as possible.

Enable Two-Factor Authentication

If you want you can optionally install TOTP module to enable two-factor authentication to add more security to your VM pool. Just download the extension and restart Tomcat.

Now, when you try logging in again, it will ask you to setup an authenticator and require you to input in every time you log in.


If you don’t want to perform all above steps one by one, you may leverage bash scripts I created in this repository.

Use at your own risk!

Originally published at on April 30, 2021.