Setting Up Online Virtual Desktop Using Apache Guacamole

Author

Bas Machielsen

Published

January 26, 2026

Introduction

This guide explains how to set up a Google Cloud Virtual Machine (Ubuntu) to serve as a remote desktop. We will use Apache Guacamole (running in Docker) as the clientless gateway. This allows you to access your desktop via a standard web browser without installing a VNC client on your local machine.

1. Set-Up Google Cloud Virtual Machine

  1. Create an Instance: Go to Google Cloud Console -> Compute Engine -> VM Instances -> Create Instance.
  2. OS Selection: Choose something like Ubuntu 24.04 LTS (x86/64).
  3. Disk Size: Crucial: The default 10 GB is often too small for a Desktop Environment + Docker images. Change the Boot Disk to Standard Persistent Disk 25 GB (or higher).
  4. Firewall: Check “Allow HTTP traffic” and “Allow HTTPS traffic”.
  5. Networking: By default, this is true, but under Networking -> Network interfaces, check whether you have an External IP (Ephemeral is fine for testing, Static is better for long-term use).

Once created, click SSH to connect to your terminal.

2. Install Desktop Environment (GUI)

A standard server image does not have a Graphical User Interface. VNC needs a GUI to display. We will use XFCE because it is lightweight and performs well over remote connections.

sudo apt update
sudo apt install -y xfce4 xfce4-goodies

Note: If prompted to select a display manager, you can choose lightdm or gdm3. Since we are running headless via VNC, this matters less, but lightdm is standard for XFCE.

3. Install Docker & Guacamole

We will run Guacamole using Docker to avoid complex manual dependency configuration (Tomcat, Java, etc.).

3.1 Install Docker Engine

sudo apt install -y docker.io docker-compose
sudo systemctl start docker
sudo systemctl enable docker
# Add your user to the docker group to run without sudo (optional but recommended)
sudo usermod -aG docker $USER

(You may need to log out and log back in for the group change to take effect).

3.2 Setup Guacamole Docker Container

We will use the boschkundendienst wrapper, which simplifies the database and SSL setup.

# Clone the repository
git clone "https://github.com/boschkundendienst/guacamole-docker-compose.git"

# Enter directory
cd guacamole-docker-compose

# Prepare the setup (Generates SSL self-signed certs and DB init scripts)
./prepare.sh

# Start the container in detached mode
sudo docker-compose up -d

3.3 Verify Guacamole is Running

Wait about 30 seconds for the database to initialize. You can check the status:

sudo docker ps

You should see containers for guacamole, guacd, and postgres.

4. Install and Configure TigerVNC (Manual Mode)

4.1 Install VNC and Clipboard Tool

We install TigerVNC for the server and autocutsel. autocutsel is required to synchronize the clipboard between the Linux server (X11) and the VNC protocol.

sudo apt install -y tigervnc-standalone-server tigervnc-common autocutsel

4.2 Initial Password Setup

Run the server once to generate the configuration files and set your password.

vncserver
  1. It will ask for a password (remember this for Step 6).
  2. It will ask for a view-only password (answer n).

4.3 Configure the Startup Script (Crucial Step)

We must kill the current instance and edit the startup script to load XFCE and the clipboard tool.

  1. Kill the running instance:

    vncserver -kill :1
  2. Backup the original startup script:

    mv ~/.vnc/xstartup ~/.vnc/xstartup.bak
  3. Create a new startup script:

    nano ~/.vnc/xstartup
  4. Paste the following content. This ensures a common clipboard and launches the XFCE desktop:

    #!/bin/sh
    #Clean up the X authority file if it exists
    rm -f /home/bas/.Xauthority*
    #Set up the environment
    export XAUTHORITY=$HOME/.Xauthority
    export PATH=$PATH:$HOME/bin
    #Uncomment the following two lines for normal desktop preferences
    unset SESSION_MANAGER
    unset DBUS_SESSION_BUS_ADDRESS
    #Start the window manager
    exec startxfce4

    Other, more simple version:

    #!/bin/sh
    
    # 1. Start Clipboard Sync
    # This runs in the background (-fork) to keep clipboard synced
    autocutsel -fork
    
    # 2. Load X Resources (colors, fonts)
    [ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
    xsetroot -solid grey
    
    # 3. Launch the Desktop Environment
    export XKL_XMODMAP_DISABLE=1
    /etc/X11/Xsession
    startxfce4 &
  5. Make the script executable: bash chmod +x ~/.vnc/xstartup

4.4 Start VNC Manually

Now start the server with your desired resolution.

vncserver :1 -geometry 1920x1080 -depth 24 -localhost no

Understanding the flags:

  • :1: This creates the display on port 5901 (5900 + 1).
  • -localhost no: This allows connections from outside the loopback interface. However, since we are using Google Cloud Firewall, this is safe as long as we don’t open port 5901 in the firewall. Guacamole (running in Docker on the same machine) will connect to it via the internal network IP or Docker bridge.

5. Firewall Rules & Security

5.1 Google Cloud Firewall

You need to open ports so you can access the Guacamole Web Interface.

Do NOT open port 5901. Keeping 5901 closed means no one can bypass Guacamole to hack your VNC password directly. Guacamole will talk to VNC locally.

Run this in your Google Cloud Shell or add it via the Networking Console:l

# Allow Guacamole HTTPS (8443) and HTTP (8080)
gcloud compute firewall-rules create allow-guacamole \
    --allow tcp:8443,tcp:8080 \
    --source-ranges 0.0.0.0/0 \
    --target-tags http-server,https-server

(Make sure your VM has the network tags http-server and https-server applied, or just apply the rule to all instances).

6. Configure Connection in Guacamole

6.1 Log In

  1. Open your browser to https://<YOUR_VM_EXTERNAL_IP>:8443/. (Make sure you use https, not http)
  2. Warning: You will see a “Potential Security Risk” warning because the SSL certificate is self-signed. Click “Advanced” -> “Proceed anyway”.
  3. Default Credentials:
    • User: guacadmin
    • Pass: guacadmin

(Change this password immediately in Settings -> Preferences).

6.2 Add Connection

  1. Go to Settings (top right) -> Connections -> New Connection.
  2. Edit Connection:
    • Name: My Cloud Desktop
    • Protocol: VNC
  3. Parameters -> Network:
    • Hostname: 172.17.0.1
      • Why? Because Guacamole is running inside a Docker container. It cannot see localhost of the main server easily. 172.17.0.1 is usually the default IP of the “Docker Host” from inside the container.
      • Alternative: Use the Internal IP of your Google Cloud VM (found in the VM details page, starts with 10.x.x.x).
    • Port: 5901
  4. Parameters -> Authentication:
    • Password: [The VNC password you set in step 4.2]
  5. Save the connection.

6.3 Connect

Go back to the Home screen and click on “My Cloud Desktop”. You should see your XFCE desktop.

7. Common Operations (Cheat Sheet)

How to Stop/Start Manually

If you reboot the VM, VNC will stop. To use it again:

  1. SSH into the server.
  2. Clean up old locks (if it crashed):
rm /tmp/.X1-lock
rm /tmp/.X11-unix/X1
  1. Start Server:
vncserver :1 -geometry 1920x1080 -depth 24 -localhost no
  1. Stop Server:
vncserver -kill :1

How to use the Clipboard

  1. Browser to Remote: Copy text on your local computer. Open the Guacamole menu (Ctrl+Alt+Shift). Paste it into the clipboard text area manually IF it doesn’t sync automatically. (With autocutsel installed, direct Ctrl+V inside the remote desktop usually works).
  2. Remote to Browser: Highlight text in the remote Linux terminal. It should automatically appear in your local computer’s clipboard.

8. Automated Startup With systemctl

Here is the specific section for installing TigerVNC and configuring it to run automatically via systemctl (Systemd), including the integrated xstartup script.

8. Install and Configure TigerVNC (Systemd Auto-Start)

8.1 Install VNC and Clipboard Tool

First, install the server and the clipboard utility.

sudo apt install -y tigervnc-standalone-server tigervnc-common autocutsel

8.2 Initial Setup (Password Creation)

You must run the server manually once to set the password and create the configuration directory.

vncserver
  1. Enter your desired password.
  2. Choose n for the view-only password.
  3. Immediately kill the server (we only needed it to generate the config folder): bash vncserver -kill :1

8.3 Configure the xstartup Script

Create the file that tells VNC how to launch the desktop and clipboard sync.

nano ~/.vnc/xstartup

Paste the integrated version we discussed:

#!/bin/sh

# 1. Cleanup & Auth
rm -f $HOME/.Xauthority*
export XAUTHORITY=$HOME/.Xauthority

# 2. Environment Setup
export PATH=$PATH:$HOME/bin
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS

# 3. Clipboard Support (Runs in background)
autocutsel -fork

# 4. Launch Desktop
exec startxfce4

Crucial Step: Make the script executable.

chmod +x ~/.vnc/xstartup

8.4 Create the Systemd Service File

Now we create a system service so Ubuntu manages the VNC server.

sudo nano /etc/systemd/system/vncserver@.service

Paste the following configuration. Important: You must replace YOUR_USERNAME with your actual Linux username (e.g., bas).

[Unit]
Description=Start TigerVNC server at startup
After=syslog.target network.target

[Service]
Type=forking
User=YOUR_USERNAME
Group=YOUR_USERNAME
WorkingDirectory=/home/YOUR_USERNAME

# The PID file allows systemd to track the specific process
PIDFile=/home/YOUR_USERNAME/.vnc/%H:%i.pid

# Clean up any existing lock files before starting to prevent errors
ExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1

# Start the VNC server
# -localhost no: Allows Guacamole (Docker) to connect from outside localhost
# :%i: This variable is replaced by the number we use in systemctl (e.g., 1)
ExecStart=/usr/bin/vncserver -depth 24 -geometry 1920x1080 -localhost no :%i

# Clean stop command
ExecStop=/usr/bin/vncserver -kill :%i

[Install]
WantedBy=multi-user.target

8.5 Enable and Start the Service

Now we tell systemd to load the new file and start the server on display :1 (port 5901).

# 1. Reload systemd to see the new file
sudo systemctl daemon-reload

# 2. Enable the service so it runs on boot
sudo systemctl enable vncserver@1.service

# 3. Start the service immediately
sudo systemctl start vncserver@1.service

4.6 Verification

Check if the service is running correctly:

sudo systemctl status vncserver@1.service

If it is active (running), you can now proceed to configure the Guacamole connection (Step 6 in the original notes) using port 5901.

Misc. Notes - Delete Later

sudo nano /etc/systemd/system/vncserver@.service

Put this in it:

[Unit]
Description=Start TigerVNC server at startup
After=syslog.target network.target

[Service]
Type=forking
User=YOUR_USERNAME
Group=YOUR_USERNAME
WorkingDirectory=/home/YOUR_USERNAME
PIDFile=/home/YOUR_USERNAME/.vnc/%H:%i.pid
ExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1
ExecStart=/usr/bin/vncserver -depth 24 -geometry 1920x1080 :%i
ExecStop=/usr/bin/vncserver -kill :%i

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable vncserver@1.service
sudo systemctl start vncserver@1.service

# Open VNC port (5901 for display :1)
sudo ufw allow 5901