Guacamole - zbrewer/homelab GitHub Wiki

Apache Guacamole is a clientless (operates completely in the browser) solution for remote desktop connections. This, along with its wide array of supported protocols (RDP, VNC, SSH, etc.) make it a good tool for remote management and some work. That being said, other solutions may work better for other types of remote access, such as gaming.

Installation

Guacamole can be installed on Docker using Docker Compose. See the guacamole-docker-compose GitHub project for additional documentation and examples.

Start off by creating a new guacamole directory to house the new Docker Compose stack. Inside of this directory, create a new directory called init that will be used to hold the database initialization script.

$ mkdir -p guacamole/init
$ cd guacamole
$ docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --postgresql > ./init/initdb.sql

Now place the docker-compose.yaml file for the Guacamole stack in this guacamole directory and run it with $ docker compose up -d. This will create the database, all other directories, and start the stack.

Once it is running, navigate to http://<docker-ip>:8080/guacamole to visit the UI and login. The default username is guacadmin and the default password (which should be changed immediately) is also guacadmin.

OAuth2/OpenID Connect Authentication

I'm using Authentik as my identity management system and for SSO. This can be setup to work with Guacamole per the instructions on the Authentik website. That being said, there are a couple important things to note first.

As the instructions point out, you should pre-create your Authentik user in the Guacamole database before enabling OpenID login for Guacamole. Do this using the default admin user (guacadmin) and give this new user access to all permissions and to any existing connections. It is important to make sure that the username in Guacamole is the email address of the user in Authentik in order for the user to get mapped correctly. If, for some reason, permissions are not set correctly, comment out the OPENID environment variables in the Guacamole docker-compose.yml and restart the stack. This will re-enable local login so that you can login as the guacadmin user and make changes as necessary.

The rest of the setup is relatively straightforward although it should be noted that any authority or other mismatches (such as the expected issuer having a trailing / but the actual issuer not having one) will cause a redirect loop. Looking at the logs of the Guacamole container can generally provide useful information about what is going wrong. As an example, the below are the environment variables I added to my Guacamole config:

OPENID_AUTHORIZATION_ENDPOINT: https://authentik.brew.foo/application/o/authorize/
OPENID_CLIENT_ID: <redacted>
OPENID_ISSUER: https://authentik.brew.foo/application/o/guacamole/
OPENID_JWKS_ENDPOINT: https://authentik.brew.foo/application/o/guacamole/jwks/
OPENID_REDIRECT_URI: https://guacamole.brew.foo/guacamole/

Use

Windows

RDP must first be enabled on the host machine and appropriate ports opened on any firewalls. Once that is done, add a new connection to Guacamole.

The connection Name can be whatever you want it to be (descriptive name) but the Protocol should be RDP. Then, under the Parameters section, set the Hostname to the IP address of the remote computer and the port to the port in use (3389 by default).

Then, under Authentication, set the Security mode to NLA and check the Ignore server certificate box. Finally, in this same section, set the Username and Domain (leaving the Password blank will cause Guacamole to prompt for it at connection time).

The Username should either be the email address associated with the Microsoft Account used to login or the local username if using a local account. The Domain should be MicrosoftAccount if using a Microsoft Account or the comouter's hostname (in all caps) if using a local account.

There are several important caveats to make note of. First, the "Home" edition of Windows doesn't support remote connections so a higher SKU like Pro or Education is needed. Second, make sure the user that will be used is listed as allowing remote connections in the Windows settings on the host. Third, if the remote user is the same as the local user, the remote connection will "take over" and the local connection will change to the lock screen; however, all running applications will remain open. This leads to a seamless transition. On the other hand, if a new user is signed in remotely, the local user will be notified and, if they accept, will be signed out so the remote user can be signed in instead.

Finally, if using a Microsoft Account and the password isn't being accepted, make sure that it has been used to log in to the computer since the last time it was changed online. This can be done by just unlocking the computer with the password (as opposed to the PIN) from the lock screen. This will cause it to be cached locally and accepted for RDP connections.

VNC (Linux)

First, the Linux machine must be setup as a VNC server by following a guide such as this one. There are plenty of guides on the internet so I won't reiterate the steps here but I will mention a couple key points

  1. Don't use the -localhost flag with the vncserver expecting to be able to connect over an SSH tunnel - this isn't supported by Guacamole.
  2. Ensure that the vncserver is started as a systemd service, otherwise you will need to connect some other way (such as SSH) first in order to start the server.
  3. In Ubuntu specifically, Firefox is installed as a snap by default which doesn't work right without a Display Manager and some other pieces. To get around this (assuming something like xfce is being used for VNC), you can either follow a guide to install the Firefox DEB package or use a different browser.
  4. Follow a guide like this one to setup the VNC server with Gnome. The important bits are to install the packages gnome-panel gnome-settings-daemon metacity nautilus gnome-terminal xserver-xorg-core and to set the contents of the ~/.vnc/xstartup to the following:
#!/bin/bash
#xrdb $HOME/.Xresources
#startxfce4 &

unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS

[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources

export XKL_XMODMAP_DISABLE=1
export XDG_CURRENT_DESKTOP="GNOME-Flashback:Unity"
export XDG_MENU_PREFIX="gnome-flashback-"

gnome-session --session=gnome-flashback-metacity --disable-acceleration-check &

Once the server is set up, make sure the correct port is allowed through your firewall, if applicable. This will typically be 5900 for the local session (the one displayed on the physical/virtual display), 5901 for the first virtual session, 5902 for the second virtual session, etc. This should have been determined while setting up the server.

Next, create a new connection in Guacamole specifying the host (IP address), port, username (the Linux user under which you set up the VNC server and expect to log in), and the password set up during the vncserver setup process. Note that this is not the Linux user's password. At this point, you should be able to save the settings and connect successfully.

SSH

SSH connection setup in Guacamole is fairly straightforward with one important caveat around using public/private key pairs. Guacamole only supports RSA keys and the OpenSSH format. Keys can be generated on Linux in this format using the ssh-keygen -t rsa -b 4096 -m PEM command. Alternatively, on Windows, PuTTYgen can be used to generate a public/private key pair. The public key can be copied directly from the tool for use on the SSH server; however, the private key for Guacamole will need to be exported by going to Conversions > Export OpenSSH Key and selecting a save location. This key can then be opened in a text editor and copied (in its entirety) into the key field in Guacamole. Ensure that the username for the SSH user is set as well and the key password (under the field in which the key was entered). The other password is for use with password authentication.

Wake-on-LAN (WoL)

Guacamole can send wake-on-lan magic packets to wake up sleeping computers before trying to connect. This allows you to use power-saving features but still connect remotely at any time.

Prerequisites

In order to set this up, first configure the BIOS of the target computer to enable WoL and then set this functionality up in the target machine's operating system. Many guides exist online discussing how to do this so I won't go into detail here.

With that done, test the WoL configuration by sending a magic packet from another computer (Linux example given). Put the target to sleep and then run the following commands to install and use wakeonlan. This must be done from the same network segment (VLAN) as it relies on broadcast traffic.

$ sudo apt-get update && sudo apt-get install wakeonlan
$ wakeonlan <target_mac_address>

If the target computer successfully wakes up, its WoL functionality is configured correctly.

WoL in Guacamole

With the target computer set up for WoL functionality and tested, Guacamole can now be configured.

Log in to Guacamole as an administrator and then go to Settings > Connections and click on the connection you would like to configure with WoL. Scroll down to the WoL section at the bottom of the connection settings page and tick the Send WoL packet box. Then fill in the MAC address of the target computer and set the UDP port for WoL packet to 9. This is the "Discard Protocol" port meaning that it shouldn't be used by anything else and has lead to it becoming an unofficial WoL port.

Next, set the Host boot wait time to something reasonable. This is the wait time (in seconds) between waking up the computer and trying to connect. It allows the computer some time to wake up but setting a long timeout causes the user to have to wait and can be annoying. Setting this may require some trial and error but, if in doubt, set it to something relatively large (like 30 seconds).

Finally, if the Guacamole server and the target to be woken up are on the same network segment (VLAN), set the Broadcast address for WoL packet to 255.255.255.255. Save the configuration, put the target computer to sleep, and try to connect from Guacamole. This should cause the target to wake up and Guacamole to establish a connection.

If, on the other hand, the Guacamole server and computer to be woken up are on different network segments (VLANs) then use the target's IP address as the Broadcast address for WoL packet. Add a firewall rule allowing the Guacamole server to send UDP traffic to the target on port 9 - this will let the WoL packet through. Also configure the router/DHCP server so the target computer has an IP reservation and tell it to create a static ARP table entry.

Now, with those things done, save all configurations and test Guacamole's WoL in the same way described above.

A little explanation about why this works:

At their simplest, WoL packets are L2 broadcast and therefore can't be routed (L3). Guacamole supports sending these packets as L3 traffic so that routers can deal with them and they can (potentially) be forwarded.

The broadcast address used above, 255.255.255.255, is the "limited" broadcast address meaning that it isn't forwarded by routers at all. This is because broadcast addresses are the highest address on the subnet so the limited address would be the highest address on 0.0.0.0/0. This would mean that it would be broadcast to all IP addresses. Rather than doing that, it instead has the specific meaning to not forward broadcast traffic so that it remains on the current network segment only.

In contrast, a "directed" broadcast address specifies the subnet to which traffic should be sent. Once again, this is the largest address in the subnet. For example, if the subnet is 10.0.0.0\16 then the directed broadcast address is 10.0.255.255 since the parts not masked out are maxed out. Similarly the broadcast address for 192.168.1.0\24 is 192.168.1.255. By default, most routers still don't forward this traffic from a different subnet but some may have the option to do so. If they do, the directed broadcast address can be used instead of the machine's specific IP address for the Broadcast address for WoL packet field in the instructions above. Note that the firewall will still have to be configured to let this traffic through and it will cause the WoL packet to be sent to every computer on the target's subnet.

On the other hand, using the computer's IP address as done above ensures that the packet is routable since it is a normal UDP packet being sent to a normal IP address (as far as the router is concerned). The only wrinkle is that, since the target computer is off/sleeping, it no longer has an L3 network connection (IP) and therefore its entry in the router's ARP table may expire (this table tells the router what MAC address is associated with each IP). As a result, the router doesn't know where the computer is (the MAC address for that IP) and therefore where to send the packet. This is solvable by giving the target an IP reservation (so it doesn't change) and then setting a static ARP table entry. This prevents it from expiring so the router can direct the packet instead.

See this post about broadcast traffic for more information and this Reddit post for inspiring the strategy here.

⚠️ **GitHub.com Fallback** ⚠️