Skip to content

Remotely accessing the Unraid GUI with Guacamole and VNC Web Browser

Written: 2018-06-12














So.. you've finished installing and setting up all your docker containers, plugins ect. Radarr is doing its thing, Plex is chugging away... everything is just peachy! And now you want to be able to access the unraid GUI outside your network.

The safest method you can do this is by setting up a VPN. You can do that by installing the OpenVPN container but that won't give you access if your server or the docker service crashes. So setting up the VPN on the router ect is much more recommended. BUT you're not always in a situation where you can connect to a VPN. For example your work computer. Be it you don't have the administrator rights to change your network settings or your company policy forbids it.. This is where Apache Guacamole is useful. By installing Apache Guacamole, centos-xfce-vncFirefox vnc and letsencrypt we can gain access to the unraid GUI externally. And by setting up fail2ban and geo-block we can protect our self from bruteforce attempts at gaining access!

Guacamole Installation

Apache Guacamole

I use the jasonbean/guacamole container. Nothing special you need to think about. Add your custom port and select your appdata location. The defaultusername and password is**guacadmin Note:** It isn't mentioned in the documentation but if you are installing the container using docker run or compose you need to add -e 'OPT_MYSQL'='Y'

Firefox VNC Web Browser

Search for VNC Web Browser in community applications and you will find a template bycheesemarathon for the consol/centos-xfce-vnc container. I have found that using the VNC Web Browser Container gives me constant connection errors and have switched to the Firefox container (jlesage/firefox) instead. Install the container and add your VNC Password if you want. Take note of the VNC port as you will need that later. Use the VNC_PASSWORD variable described here Do not add SSL in the container settings as it looks like Guacamole doesn't support VNC with encryption.

Let's Encrypt

To access all this we'll use the linuxserver/swag container from linuxserver. _This container sets up an Nginx web serverand reverse proxy with php support and a built-in letsencrypt client that automates free SSL server certificate generation and renewal processes. It also contains fail2ban for intrusion prevention.

Before we start you need to acquire a domain. You can do that onduckdnsor any other domain service.

I’m using I’m very happy with that.

If you have a dynamic ip-address you can setup thecaptinsano DDclientcontainer and have that update yoursynthetic record. If you don't want to pay for a custom domain, using the duckdns container will work just fine.

Forward your domain to your public IP address. After you've done that add your different ANAME/CNAME records e.g or

@ = root domain ( and points to my external ip
www = sub domain 
grafana = sub domain
TTL: (Time to Live) How often a copy of the record stored in cache must be updated or discarded.

SWAG Installation

  1. Container Port: 80- Choose your desired host port. e.g**81** (You can't set this to 80 as the unRAID web GUI uses that. )
  2. Container Port: 443-Set this to 444 or something else (On update 6.4 unraid will use port 443 if you setup https and it’s better to be ahead of time so it won’t cause any issues)
  3. Enter you email
  4. Add your domain e.g
  5. Add your different sub domains e.g **guacamole,guac** ect
  6. Validation: Select your validation type. http will work in most cases (Unless your ISP blocks port 80)
  7. _Container Path: /config_Install the container config to your desired location. I recommend using an SSD.

Next is port forwarding. This is done on your router and you need to forward port 80 and 443 to the ports you chose in step 1 and 2. So if your servers IP is and you have chosen that the container is on port 81, you need to forward all traffic on port 80 to port 81 on IP And do the same for port 443 to 444. If you're unsure how to do this on your router check out:

Next go to https://yourserverip:444 or http://yourserverip:81 If you now see the Nginx welcome page, it works. Also test if redirects you to the nginx welcome page.

Note: TTL differs from each provider, some has a minimum 60 minutes before DNS propagates and others have 1 minute. So it might take a while before works.

Configuring Apache Guacamole

Browse to the Apache guacamole container and login.You can add a new admin user if you want. The default username and password is guacadmin

Go to Settings and click on Connections Click on New Connection Give the connection a name. I just called it Firefox. And Location is ROOT and Protocol is VNC Set your Maximum number of connections, I use 3

Scroll down to Parameters - Network. Add your Hostname: Your Unraid IP Add your Port: This is the VNC port to the**Firefox** container (default is 7914) For Authentication input the password you set for the**Firefox**container. Click Save

You can now test the connection you have created. Click on your user name and select the connection. You should now be presented with the desktop of the VNC Web Browser container.

Tip: If you want to go back to settings just press ctrl + shift + alt to open the side menu. Here you can also copy text that you have copied within the VNC connection!

Here you can open Firefox and go to your unraid IP and log in.

Windows 10 VM with RDP

You can also easily add your Windows VM using RDP, this will also let you mount your shares so you can manage your files like you would at home. This is how I added my Windows 10 Pro VM:

The 3389 port is the RDP port.

Configuring Nginx

Go to your letsencrypt appdata location.

Find the nginx folder and then edit the file called default or add a new **.conf** file in the site-conf folder.

I recommend usingnotepad++

If you want to use this on a subdomain I recommend creating a **guacamole.conf** file instead and adding the nginx config to that.

Below is an nginx config that will giveyou A+ ratings and

**server_name;**This is where you will add your domain name e.g proxy_pass;**This is your IP and port to the**Apache Guacamole container

READ THE COMMENT ON add_header X-Frame-Options AND add_header Content-Security-Policy IF YOU USE THIS ON A SUBDOMAIN YOU WANT TO IFRAME!

server {
listen 80;
return 301 https://$server_name$request_uri;

server {
listen 443 ssl http2;

## READ THE COMMENT ON add_header X-Frame-Options AND add_header Content-Security-Policy IF YOU USE THIS ON A SUBDOMAIN YOU WANT TO IFRAME!

## Certificates from LE container placement
ssl_certificate /config/keys/letsencrypt/fullchain.pem;
ssl_certificate_key /config/keys/letsencrypt/privkey.pem;

## Strong Security recommended settings per
ssl_dhparam /config/nginx/dhparams.pem; # Bit value: 4096
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
ssl_session_timeout  10m;

## NOTE: The add_header Content-Security-Policy won't work with duckdns since you don't own the root domain. Just buy a domain. It's cheap
## Settings to add strong security profile (A+ on

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none; #SET THIS TO index IF YOU WANT GOOGLE TO INDEX YOU SITE!
add_header Content-Security-Policy "frame-ancestors https://*.DOMAIN.COM https://DOMAIN.COM https://$server_name"; #Add your domains you want to enable iframing on
add_header X-Frame-Options "allow-from https://DOMAIN.COM https://$server_name"; #Add your domains you want to enable iframing on. https://$server_name = in this server block
add_header Referrer-Policy "strict-origin-when-cross-origin";

add_header Feature-Policy "geolocation none;midi none;notifications none;push none;sync-xhr none;microphone none;camera none;magnetometer none;gyroscope none;speaker self;vibrate none;fullscreen self;payment none;";

proxy_cookie_path / "/; HTTPOnly; Secure"; ##NOTE: This may cause issues with unifi. Remove HTTPOnly; or create another ssl config for unifi.
more_set_headers "Server: Classified";
more_clear_headers 'X-Powered-By';

location / {
    proxy_buffering off;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_http_version 1.1;
    proxy_no_cache $cookie_session;


Configuring fail2ban

From github: Fail2Ban scans log files like**/var/log/auth.log**and bans IP addresses conducting too many failed login attempts. It does this by updating system firewall rules to reject new connections from those IP addresses, for a configurable amount of time. Fail2Ban comes out-of-the-box ready to read many standard log files, such as those for sshd and Apache, and is easily configured to read any log file of your choosing, for any error you wish.

Luckily Fail2ban comes preinstalled with your letsencrypt container, so you only need to add the filter and edit the jail.local file!

For this to work we need the letsencrypt container to be able to see the catalina.out**file in the **Apache Guacamole container.

  • Open the letsencrypt container settings.
  • Add a path from the letsencrypt container to the Apache Guacamole container.

    • Name: guacamole fail2ban
    • Container path: /guacamole or whatever you prefer
    • Host path: Your path to the**Apache Guacamole /log** folder e.g **/AppData/ApacheGuacamole/log/tomcat8**
    • Access mode: Read only
    • Description: fail2ban path intoguacamole /log folder


Go to thefail2ban folder inside the letsencrypt appdata folder and edit the jail.local file. For my config I have set the bantime to 86400 seconds (24h) The findtime is 600 seconds and maxretry is 3 At the end of the jail.local file add the following:


enabled = true
port = http,https
filter = guacamole-auth
logpath = /guacamole/catalina.out
ignoreip =
  • The ignore IP is so that fail2ban won’t ban your local IP. Check out you are wondering what your CIDRnotation is. Most often it will be /24 (netmask To find your netmask run ipconfig /all on windows or ifconfig | grep netmask on linux.

  • The logpath is the container path you created in step 2. And catalina.out the Guacamole log.

Now, there is already a filter(guacamole.conf) for Guacamole in the filter.d folder inside the fail2ban folder. But that filter won't work unless we make a change to it. Copy the guacamole.conf file and rename it guacamole-auth.conf In the guacamole-auth.conf file change:

failregex = ^.*\nWARNING: Authentication attempt from <HOST> for user "[^"]*" failed\.$


failregex = \bAuthentication attempt from \[<HOST>(?:,.*)?\] for user ".*" failed\.

Restart the letsencrypt container.

If you get the error below in the fail2ban.log file you can comment the 3 date pattern lines in the guacamole-auth.conf file.

2018-06-12 21:36:49,121 fail2ban.filter \[351\]: ERROR Error during seek to start time in "/guacamole/catalina.out"
2018-06-12 21:36:49,121 fail2ban.filterpoll \[351\]: ERROR Caught unhandled exception in main cycle: TypeError('an integer is required',)

Comment these lines by adding # in front.

#datepattern = ^%%b %%d, %%ExY %%I:%%M:%%S %%p

Remember to restart the container anytime you make a change in the conf file.


The fail2ban.log file should output something like this:

2018-06-12 21:39:07,529 fail2ban.jail \[350\]: INFO Jail 'guacamole-auth' started
2018-06-12 21:39:30,779 fail2ban.filter \[350\]: INFO \[guacamole-auth\] Ignore by ip
2018-06-12 21:39:44,801 fail2ban.filter \[350\]: INFO \[guacamole-auth\] Found - 2018-06-12 21:39:44
2018-06-12 21:39:57,420 fail2ban.filter \[350\]: INFO \[guacamole-auth\] Found - 2018-06-12 21:39:57
2018-06-12 21:40:00,025 fail2ban.filter \[350\]: INFO \[guacamole-auth\] Found - 2018-06-12 21:39:59
2018-06-12 21:40:00,196 fail2ban.actions \[350\]: NOTICE \[guacamole-auth\] Ban


If you managed to ban yourself or a friend banned themself you can do this to unban. Bash into the container with: docker exec -it letsencrypt bash Enter fail2ban interactive mode: fail2ban-client -i Check the status of the jail: status guacamole-auth

fail2ban> status guacamole-auth
Status for the jail: guacamole-auth
|- Filter
| |- Currently failed: 0
| |- Total failed: 3
| `- File list: /guacamole/catalina.out
`- Actions
|- Currently banned: 1
|- Total banned: 1
`- Banned IP list:

unban with: set guacamole-auth unbanip If you already know the IP you want to unban you can just type this: docker exec -it letsencrypt fail2ban-client set guacamole-auth unbanip

Adding geo-blocking

Blocking countries with GeoLite2 in nginx using the swag/letsencrypt docker container


You can test if it worked with a VPN or do a performance test from a location that is blocked here

Optional: Organizr

Another security layer is using Organizr to block access to your by having you to log into Organizr first! And you can even add a fail2ban filter on the Organizr login form!By using server authentication you will be shown a 401 Unauthorized page unless you log in first.

Optional: Basic http auth

Another security layer is using basic http auth. Linuxservers swag container is already be pre configured to ban failed http auths with fail2ban!


For any questions you can find me here


Last update: December 19, 2021