Accessing Computer Labs Remotely

Reading time ~11 minutes

Accessing Computer Labs Remotely

Accessing Computer Labs Remotely

1. Introduction

With COVID-19 pandemic, most of the schools and universities around the world have to do the teaching from home. In such conditions, being able to access computer labs remotely might be quite useful. In this article we will see how to achieve this with Guacamole, WireGuard VPN, and a VPS on the cloud.

We would like to build something like this:


Figure 1: Accessing computer labs through Guacamole

Students can use a normal web browser to access Guacamole, which is installed on a VPS on the cloud, and from Guacamole they can access any of the workstations in the labs.

They can login on the computer labs with the same username and password that they would normally login if they accessed them physically. Besides this, they also need a username and password for accessing the Guacamole interface. Policies on Guacamole can also restrict which workstations from the labs they can access.

Computer labs are private LANs located behind a firewall. They don't have public IPs and normally cannot be accessed from the internet. However they can access the Guacamole server (which is located on the cloud and has a public IP), and we can create a WireGuard tunnel between them and the server. Through this tunnel, Guacamole can access each of them. Students, who can access Guacamole through its public IP, can also access each computer through Guacamole.

2. Deployment diagram

Let's use a deployment diagram to understand better what we are going to build. The details in it are just an example which may help to understand easier the explanation of the setup:


Figure 2: A diagram with more details

In the VPS we have a Guacamole container and a WireGuard container which are located on the same Docker virtual network. HTTP requests go to guacamole through wsproxy, which is another container that serves as a reverse HTTP proxy.

There are WireGuard connections (tunnels) between the wireguard container and wg-client-1, and between wireguard and wg-client-2. There is no direct connection between guacamole and any of the computer labs. However we can add routes on guacamole so that the networks of the labs ( and are routed via the wireguard container. At the same time, we also need to add routes on the workstations of the labs so that the routes to the Docker LAN ( go via the WG clients ( and

The docker containers are managed with docker-scripts. The reverse HTTP proxy container (wsproxy) forwards the requests to the corresponding container according to the domain, gets automatically a free LetsEncrypt SSL certificate for each domain, and also redirects automatically all HTTP requests to HTTPS.

The steps to make this setup would be like this:

  1. Install Docker and docker-scripts on the VPS.
  2. Install docker-scripts containers wsproxy, guacamole and wireguard.
  3. On the wireguard container generate configurations for each client.
  4. Move WireGuard configurations to each client and start up the WG interfaces.
  5. Make sure that the guacamole container has proper routes to LANs of the labs, that go via the wireguard container.
  6. Make sure that each workstation on the labs has proper routes to guacamole, that go via the WG clients.
  7. Finally, create connections on guacamole for each workstation, create users, groups, etc.

3. Make installations on the VPS

3.1. Install docker and docker-scripts

  1. Install Docker:

    curl -fsSL -o
    sudo sh
  2. Install docker-scripts:

    apt install git make m4
    git clone /opt/docker-scripts/ds
    cd /opt/docker-scripts/ds/
    make install

3.2. Install wsproxy and guacamole

  1. Install wsproxy:

    ds pull wsproxy
    ds init wsproxy @wsproxy
    cd /var/ds/wsproxy/
    ds make
  2. Install guacamole:

    ds pull guacamole
    ds init guacamole @guacamole
    cd /var/ds/guacamole/
    # make sure to change at least the DOMAIN and the admin PASS
    ds make

    For more details about installing and using Guacamole see also:

3.3. Install wireguard

  1. Get the scripts and initialize a directory for the container:

    ds pull wireguard
    ds init wireguard @wireguard
    cd /var/ds/wireguard/
  2. Edit and make sure to comment out NETWORK and SUBNET:

    # NETWORK=wgnet
    # SUBNET=''

    These are used to tell docker-scripts in which Docker network to attach the container (the network will be created if it doesn't exist). In this case we want the wireguard container to be on the same network as the other containers (guacamole and wsproxy). We are commenting these settings so that the default docker-scripts network is used (

  3. Make sure to change these settings as well:


    Here, is the IP of the WG interface on the wireguard container and is the subnet of the docker virtual LAN where the containers are attached. WG clients will route the traffic to these networks through the WG interface.

    ALLOW_INTERNET_ACCESS is set to no because we don't want the workstations to access the internet through the wireguard server, and CLIENT_TO_CLIENT is set to no because we don't want the workstations to be able to ping (access) each-other.

    The last setting tells the clients to send a keep-connection-alive package every 25 seconds. This prevents the NAT sessions from expiring and makes sure that each workstation can be accessed from guacamole at any time.

    For more details about these settings and their meanings see also the WireGuard Usecases.

  4. Finally run ds make to build, create and configure the container.

    ds make

4. Setup WireGuard clients

  1. On the server, add configurations for each WG client:

    cd /var/ds/wireguard/
    ds client add wg-client-1
    ds client add wg-client-2
    ds client ls
    ls clients/

    On the command ds client add, besides the name and the WireGuard IP of the client, we also give the network (LAN) where this client is going to be a router for the WG traffic. This tells the WG server to allow and forward the traffic coming from these IPs:

    cat wg0.conf | grep -E '^|AllowedIPs.*'
  2. Transfer configuration files to the clients. This can be done with copy/paste, using scp, etc.

    You can also share these configuration files like this:

    ds client ls
    ds share
    ds share www wg-client-1
    ds share www wg-client-2
    ls www/

    Then, on each client you can get the configuration file like this:

    wget --no-check-certificate -O wg-client-1.conf \
  3. On each client, test the connection to the wireguard server. Assuming that you are using Debian/Ubuntu, you have to install first the wireguard package, like this:

    apt install wireguard

    Note: If the client is a RaspberryPi, then you also have to install raspberrypi-kernel-headers and reboot:

    apt install raspberrypi-kernel-headers

    Now start up the WG interface and test that it works:

    wg-quick up ./wg-client-1.conf
    ip addr
    wg-quick down ./wg-client-1.conf
  4. On each client, make the WG interface to start up automatically, as a service:

    mv wg-client-1.conf /etc/wireguard/wg0.conf
    systemctl enable wg-quick@wg0
    systemctl start wg-quick@wg0
    systemctl status wg-quick@wg0
    ip addr

5. Add additional routes on Guacamole

If we try to ping from guacamole to WG clients it will fail:

cd /var/ds/guacamole/
ds shell
apt install iputils-ping traceroute

You will notice that the route to the wg-client-1 ( is not passing via wireguard ( To fix this we need to add a route like this:

ip route add to via

However this one fails too, because the wireguard container has not been created with the capability to administrate the network stack. We need to use the docker option --cap-add net_admin when we create the container.

To fix this and some other issues, let's customize this instance of wireguard container by creating the file like this:

cd /var/ds/guacamole/
cat <<'EOF' >
cmd_make() {
    ds build
    ds create --cap-add net_admin
    ds config

    ds inject

    ds exec apt install --yes dnsutils
    ds exec apt install --yes iputils-ping traceroute

This is going to override the command ds make with a customized one. Usually ds make is just a shortcut for ds build; ds create; ds config, but now we are also using an extra option (--cap-add net_admin) with ds create, we are running the configuration script, and we are installing some extra packages.

Now let's make the container again:

ds make

The script installs a systemd service inside the container that runs each time that the container is started, checks whether the script scripts/ exists and is executable, and if so, runs it.

We can use the script scripts/ to add extra routes once the container starts, like this:

cd /var/ds/guacamole/
cat <<'EOF' > scripts/
wireguard_ip=$(dig wireguard +short)
ip route add to via $wireguard_ip
ip route add to via $wireguard_ip
ip route add to via $wireguard_ip
chmod +x scripts/

Notice that we added routes not only for the WG clients but also for the LAB1 and LAB2 LANs ( and The command dig that is needed to get the IP of wireguard has been installed on the container by the package dnsutils.

Let's see whether it works:

ds restart
ds shell
ip route

If you try to ping from wg-client-1 and wg-client-2 to guacamole ( it should also work. This is because we have included in the setting ROUTED_NETWORKS on wireguard, and this in turn includes it in the configuration of each client, at the setting AllowedIPs (check /etc/wireguard/wg0.conf on the clients). This setting makes the command wg-quick up to automatically add a route to this network when the WG interface goes up. So we don't need to add it manually

6. Add additional routes on each workstation

If we go to any of the non-WG workstations of LAB1 or LAB2 (for example lab1-wks or lab2-wks) and try to ping to guacamole (ping, it will fail. A traceroute command shows that the route to guacamole is not going via the WG client (wg-client-1 or wg-client2). So, we need to fix this by adding a route like this on each workstation of LAB1 or LAB2:

ip route add to via   # on LAB1 workstations
### or
ip route add to via   # on LAB2 workstations

After this, we will be able to ping guacamole from each workstation, and also from guacamole we will be able to ping to each workstation of LAB1 or LAB2 (for example: ping or ping This is because we have already added the routes to and on scripts/ on the guacamole container.

Note: For a working example of this usecase see this testing script:

You can try it like this:

git clone
cd wireguard/testing/
apt install highlight expect

7. Setup Guacamole

The last thing is to go to the guacamole container and use the command ds guac to add servers, users and connections to each workstation. For example:

ds guac

# add a user for each lab
ds guac user add lab1 pass1
ds guac user add lab2 pass2

# add a server for each workstation on lab1
ds guac server add
ds guac server add
ds guac server add
ds guac server add

# add a server for each workstation on lab2
ds guac server add
ds guac server add
ds guac server add
ds guac server add

# allow user 'lab1' to connect to the workstations on lab1
ds guac user connect lab1
ds guac user connect lab1
ds guac user connect lab1
ds guac user connect lab1

# allow user 'lab2' to connect to the workstations on lab2
ds guac user connect lab2
ds guac user connect lab2
ds guac user connect lab2
ds guac user connect lab2

Then the students that login in guacamole with the username and password of LAB1 (lab1/pass1) will be able to connect to any of the workstations of the LAB1, and if they login with the username lab2 will be able to connect to any workstation on LAB2.

However, before accessing a workstation, they will also need to use the username and password that they normally use when they access it physically. So, they usually need two pairs of username/password, one for accessing the Guacamole interface, which allows them to connect to certain workstations, and another pair that is needed to login to a workstation.

Of course, the setup above is just an example and there are other ways to organize users, groups and workstations, to do authentication and login, etc. For more details see:

Note: The example above with ds guac assumes that the workstations are Linux systems that can be accessed through Guacamole by SSH or RDP. You can install xrdp on Debian/Ubuntu with: apt install xrdp.

8. Conclusion

With Guacamole and WireGuard VPN (installed on a VPN on cloud) it is possible to setup network connections that allow accessing computers in a private LAN remotely and safely. If we use Docker and docker-scripts for installing Guacamole and WireGuard this setup is easy. This kind of remote access could be useful for educational institutions, as well as for other organizations and companies.

Date: 2020-11-05

Author: Dashamir Hoxha

Created: 2020-11-07 Sat 05:23


OpenPGP Web Key Directory

OpenPGP Web Key DirectoryOpenPGP Web Key DirectoryTable of Contents1. Introduction2. How WKD works3. Building a WKD3.1. Create the direct...… Continue reading

SMTP Server with LDAP Authentication

Published on April 17, 2021

Using WireGuard VPN

Published on November 09, 2020