Skip to content

How I Access My Homelab Remotely

I use Apache Guacamole to access my homelab remotely, primarily when I need SSH access to one of my servers.

The setup combines Guacamole, SSH, Caddy, Cloudflare and two-factor authentication (2FA).

The result is a convenient remote-access system without exposing SSH directly to the Internet.

The Basic Idea

My remote access path looks like this:

flowchart LR
    A[My Computer] --> B[Cloudflare]
    B --> C[Caddy]
    C --> D[Guacamole]
    D --> E[SSH]
    E --> F[My Homelab Servers]

The important point is that SSH itself is not exposed to the Internet.

Only the Guacamole web interface is exposed through the reverse proxy.

Why I Use Guacamole

Apache Guacamole provides a browser-based interface for remote access.

I don't need an SSH client on the computer I am using. I simply open a web browser and connect to my Guacamole installation.

Once authenticated, Guacamole can establish SSH connections to my internal servers.

This is particularly useful when I am working from someone else's computer or when I simply want a convenient way to access my servers without setting up an SSH client.

My Remote Access Path

When I connect remotely, the traffic follows this path:

flowchart LR
    A[Remote Computer] -->|HTTPS| B[Cloudflare]
    B -->|HTTPS| C[Caddy Reverse Proxy]
    C --> D[Guacamole]
    D -->|SSH| E[Internal Server]

Each component has a specific job.

1. Cloudflare

Cloudflare provides the public-facing DNS and proxy for my domain.

My Guacamole installation is accessed through a subdomain.

The connection from my remote computer to Cloudflare is encrypted using HTTPS.

Cloudflare also provides an additional layer between the Internet and my home network.

2. Caddy

Caddy runs on my main infrastructure server and acts as my reverse proxy.

It receives the HTTPS request and forwards it to the Guacamole container running on another server.

The public-facing URL therefore does not expose the internal Docker port directly.

My Caddy configuration follows the same general pattern I use for my other services:

guacamole.example.com {
    reverse_proxy INTERNAL_SERVER:8562
}

The actual domain and internal address are specific to my homelab.

3. Guacamole

Guacamole runs as a Docker container.

My current deployment uses the jwetzell/guacamole image with the TOTP authentication extension enabled.

The relevant part of my Docker Compose configuration is:

services:
  guacamole:
    container_name: guacamole
    stop_grace_period: 60s
    image: jwetzell/guacamole
    restart: unless-stopped
    ports:
      - 8562:8080
    volumes:
      - ./guacamole:/config:rw
    environment:
      TZ: America/Santo_Domingo
      EXTENSIONS: "auth-totp"

This is my actual deployment rather than a generic Guacamole configuration.

The timezone shown above is specific to my own server and should be changed if you are following this example.

SSH Is Still Internal

One of the most important aspects of this arrangement is that I do not forward SSH ports from my router to the Internet.

My servers continue to listen for SSH connections on the internal network.

Guacamole connects to those servers from inside my network.

Conceptually:

flowchart TB
    A[Internet] --> B[Cloudflare]
    B --> C[Caddy]
    C --> D[Guacamole]
    D --> E[Internal Network]
    E --> F[SSH Server]

There is therefore no requirement for something like:

Internet
   |
   | TCP 22
   v
Router
   |
   v
SSH Server

That is a configuration I deliberately avoid.

Two-Factor Authentication

I have also enabled TOTP two-factor authentication for Guacamole.

The login process therefore requires more than just my Guacamole username and password.

The general authentication flow is:

flowchart LR
    A[Guacamole Login] --> B[Username + Password]
    B --> C[TOTP Code]
    C --> D[Authenticated]
    D --> E[SSH Connection]

This is particularly important because Guacamole is intentionally accessible from the Internet.

Even though the actual SSH services remain internal, the Guacamole login page itself is a public-facing service and should therefore be protected properly.

Why I Prefer This Arrangement

There are several reasons I prefer this approach.

No Direct Internet-Facing SSH

My SSH services are not directly exposed to the Internet.

That means I don't need to open TCP port 22 on my router just so that I can administer my servers remotely.

Browser-Based Access

I can access my servers from a normal web browser.

I don't need to install PuTTY, Windows Terminal, an SSH client or any other software on the remote computer.

One Entry Point

Guacamole gives me a single place from which I can access my various servers.

Instead of remembering different public addresses and ports, I connect to Guacamole and select the server I want.

Works Well With My Existing Infrastructure

Guacamole fits naturally into the architecture I already use.

I already have:

  • Cloudflare handling my public DNS and proxying
  • Caddy handling reverse proxying
  • Docker running my applications
  • SSH providing administration access to my Linux servers
  • ntfy providing notifications for many of my homelab services

Guacamole simply becomes the controlled entry point for remote administration.

My Overall Architecture

Putting everything together, my remote-access architecture looks like this:

flowchart TB
    A[Remote Computer]
    B[Cloudflare]
    C[Caddy]
    D[Guacamole]
    E[Internal Network]
    F[micropc]
    G[micro2pc]
    H[minipc]

    A -->|HTTPS| B
    B --> C
    C --> D
    D -->|SSH| E
    E --> F
    E --> G
    E --> H

The Internet-facing portion ends at Guacamole.

From Guacamole onwards, the connections are made to my internal servers.

Security Considerations

Remote administration deserves more care than an ordinary web application.

My approach is based on several layers rather than relying on one security mechanism.

HTTPS

The Guacamole interface is accessed over HTTPS through Caddy and Cloudflare.

Strong Authentication

Guacamole requires a username and password.

Two-Factor Authentication

TOTP provides an additional authentication factor.

No Public SSH

I don't expose SSH directly through my router.

Reverse Proxy

Caddy provides the public-facing entry point rather than exposing the Guacamole Docker port directly to the Internet.

Cloudflare

Cloudflare provides another layer between the public Internet and my homelab.

None of these measures should be regarded as making a service automatically secure. Keeping Guacamole, its container image, the operating system and the reverse proxy up to date is still important.

What Happens When I Need to Access a Server

In practice, the process is quite simple.

  1. I open a browser on the computer I am using.
  2. I connect to my Guacamole URL.
  3. I authenticate with my username and password.
  4. I enter my TOTP code.
  5. Guacamole presents my available connections.
  6. I select the server I want to administer.
  7. Guacamole establishes an SSH connection to that server.
  8. I get an SSH terminal directly in my browser.

The whole process feels much like connecting to a normal web application.

The difference is that the web application is providing me with an SSH session to my own servers.

Advanced Example — My Actual Deployment

The following is provided as a reference rather than as a universal Docker Compose configuration.

It is based on my own homelab deployment:

services:
  guacamole:
    container_name: guacamole
    stop_grace_period: 60s
    image: jwetzell/guacamole
    restart: unless-stopped
    ports:
      - 8562:8080
    volumes:
      - ./guacamole:/config:rw
    environment:
      TZ: America/Santo_Domingo
      EXTENSIONS: "auth-totp"

The important things to notice are:

  • Guacamole runs in Docker.
  • The container listens on port 8080.
  • I publish it on host port 8562.
  • Configuration is stored outside the container.
  • The TOTP authentication extension is enabled.
  • Caddy provides the public reverse-proxy entry point.

Your own paths, ports, timezone and reverse-proxy configuration will probably be different.

Final Thoughts

For my homelab, Guacamole provides a useful compromise between security and convenience.

I can administer my servers remotely without exposing SSH directly to the Internet, while still getting the convenience of a browser-based SSH client.

The complete chain is:

flowchart LR
    A[Me] --> B[Browser]
    B -->|HTTPS| C[Cloudflare]
    C --> D[Caddy]
    D --> E[Guacamole]
    E -->|SSH| F[Homelab Servers]

For me, the key principle is simple:

Expose the minimum necessary service to the Internet, protect that service with multiple layers of authentication and encryption, and keep the actual administration services such as SSH inside the trusted network.