In this article I'll show you how to setup a reverse ssh tunnel to a EC2 instance in AWS running Guacamole. There are many articles on setting up Guacamole servers and connecting to devices that are on the same local network, but I didn’t see any discussing ssh tunnels and how to connect devices on NATed or firewalled networks to a cloud server. Let's get started.
Create a Guacamole AWS EC2 Instance
The first thing we need to do is create our EC2 instance in AWS(Note: If you don’t have an AWS account you can register for a free one here). Login to AWS, and go to your EC2 Dashboard and from the dashboard click Launch instance. Enter a server name (I’m using ‘guacamole-server’), and now on the Application and OS Images(Amazon Machine Image) search for 'guacamole'. Click on the AWS Marketplace AMIs, and select the image titled: Apache Guacamole packaged by Bitnami . You can choose another Guacamole AMI but some of the steps might be a little different.
In addition, please take note of the Bitnami documentation link. I used the vendor recommended instance type: t3a.small.
Our next step is to create a key pair so we can log in to our instance with SSH. Click "Create new key pair" with the following options:
- Key pair name: guacamole-server-key
- Key pair type: RSA
- Private key format: .pem (note: you can convert your key pair for Putty later with Puttygen).
When you create the new key, it will automatically download to your local machine. Once you have the server working, you can configure more advanced security settings, for now leave the default setting. On the 'Configure storage' page, I set the storage capacity for the instance to 30 GB.
Launch your instance and then locate its Public IPv4 address by clicking on the instance itself.
Let's connect to our EC2 instance using PuTTY and create a private key using PuTTYgen for authentication. If you haven't already done so, download PuTTygen. Open PuTTYgen and click on 'Load' to select the downloaded key file (guacamole-server-key). Save the private key file by clicking on 'Save private key' (do not click on 'Generate') and name it 'guacamole-server-key.ppk'.
If you don’t have putty download click here, we will use it to connect to the EC2 instance. For the hostname, you'll want to put
Open the session and you should be connected to our Guacamole Server.
Next we need to grab the guacamole server website login information. Go to your EC2 instance and click on Actions > Monitor and troubleshoot > Get system log
Scroll up in the log a bit and you will find the guacadmin user id and password that will allow you to log into the guacamole web interface. You can test the password by opening a web browser and going to your ec2 instance public ip.
Before we begin configuring our client machine, let's configure a user account for our SSH tunnel. The name of my client machine is bokeh07, so that's what I'll name the account on my EC2 instance. You can set up additional keys for each account on your Guacamole server, but that's not within the scope of this article, so we're going to just copy the key used on the Bitnami account.
sudo adduser new_user --disabled-password
cp /home/bitnami/.ssh/authorized_keys /home/new_user/.ssh/
chown -R new_user:new_user /home/new_user/.ssh
Finally we need to enable GatewayPorts in the SSHD configuration file (/etc/ssh/sshd_config) and restart services:
To restart services:
sudo service ssh restart
Setting up the client reverse ssh tunnel
For a client I’m using a Debian based Linux machine; the big thing is you want to make sure you have OpenSSH installed. Now we need to copy the guacamole-server-key.pem we downloaded to where your ssh keys are stored, mine are in /etc/ssh . Let’s run a quick test to make sure we can connect to the guacamole server.
ssh -i /etc/ssh/guacamole-server-key.pem new_user
To create a ssh tunnel to our guacamole instance we will use the following command:
ssh -N -R <remote port>:localhost:22 <EC2 instance public DNS> -i /etc/ssh/guacamole-server-key.pem
Here's what each part of the command means:
- ssh: This is the command to initiate a secure shell connection.
- -N: This tells ssh not to execute a remote command. We only want to set up a tunnel.
- -R: This sets up a reverse tunnel. It forwards traffic from a remote port to a local port.
- <remote port>: This is the port on the EC2 instance that you want to forward traffic to.
- localhost:22: This specifies the local port to forward traffic from. In this case, we want to forward traffic from the local port 22 (SSH).
- <EC2 instance public DNS>: This is the public DNS of your EC2 instance.
Once you run this command, any traffic that is sent to <remote port> on the EC2 instance will be forwarded to port 22 on your client machine. You can see the tunnel is established by running a netstat on ec2 instance, I’m using port 7777 and you can see it listening in the screenshot below.
Now we need to build persistence for the ssh tunnel, that way if the client is rebooted or the tunnel drops for some reason it will re-establish automatically. To do this we'll create a service with the following command:
sudo nano /etc/systemd/system/reverse-ssh-tunnel.service
Paste the following code into the file:
Description=SSH Reverse Tunnel After=network-online.target
ExecStart=/usr/bin/ssh -N -i /path/to/private/key.pem -R <remote-port>:localhost:22 <your-ec2-instance-ip>
The [Unit] section defines metadata about the unit, such as its description and dependencies. In this case, the unit is named "SSH Reverse Tunnel" and it is set to start after the network is online (After=network-online.target).
The [Service] section specifies the properties of the service, including the user who will run it (User=<your-username>), the command to run (ExecStart=/usr/bin/ssh -N -i /path/to/private/key.pem -R <remote-port>:localhost:22 <your-ec2-instance-ip>), and the restart behavior (Restart=always and RestartSec=10). The command runs an SSH connection with reverse port forwarding, which forwards traffic from the specified remote port to the local port 22 (SSH) on the specified EC2 instance.
The [Install] section specifies the target for installation (WantedBy=multi-user.target), which determines when the service will be started or stopped. In this case, the service will be started when the system enters the multi-user mode, which is the default run level for most Linux-based systems.
Now we need to reload the ‘systemd’ daemon by running the following command:
sudo systemctl daemon-reload
Start the reverse-ssh-tunnel service by running the following command:
sudo systemctl start reverse-ssh-tunnel
Check the status of the service by running the following command:
sudo systemctl status reverse-ssh-tunnel
You can also verify the tunnel is up with netstat on our guacamole instance.
Connecting Guacamole to the SSH Tunnel
In this final section we'll connect the Guacamole server to the ssh tunnel. Login to your Guacamole instance with a web browser using the Public IP of your instance and the user id and password we copied from the log file earlier. Navigate to guacadmin > Settings > Connections > New Connection and give the connection a Name and select protocol SSH. I’ll just put screenshots of my guacamole config because it’s pretty self explanatory.
Next scroll to the bottom of the page and Save. Then navigate to guacadmin > home and click on the new connection.
Note: I had an issue connecting Guacamole to one of my client machines, the ssh handshake was failing because the client was using a newer version of ssh. To correct the problem I added HostKeyAlgorithms +ssh-rsa at the end of my sshd config file ( /etc/ssh/sshd_config ). If you need to update the ssh configuration file be sure to restart the service ( systemctl restart ssh.service ).
That’s all I have for this post but if you have any questions feel free to shoot me a note at