Guacamole for remote access to your machines

Tags: #<Tag:0x00007f616c321020> #<Tag:0x00007f616c320f58>

EDIT: Corrected the steps in the Ansible script that install the TOTP extension.

In response to MobaXtrem Terminal - software recommendation and because I needed to learn about Apache Guacamole anyway, I decided to take the plunge and install and play with it. This post has my notes and hopefully enough information advanced users of OH can follow to set up remote access to their machines behind an HTTP proxy.

What is it?

Apache Guacamole is a free and open source server that you run on your LAN and connects to the machines on your LAN (VNC, RDP, SSH, and some others) and exposes them through an HTML5 web app. So imagine bringing up the terminal for your openHAB server through the browser.

One of the key features is that it is clientless. You don’t have to install anything on your LAN machines except for the Guacamole service. If it’s already configured with SSH, VNC or RDP, Guacamole can connect to it with no additional changes.

The home page:

Each entry in that list is a separate computer, with one computer supporting a VNC and an SSH connection.

Pros:

  • all you need to access your machines is a web browser
  • doesn’t require anything to be installed on the LAN machines you connect to (you only need the Guacamole services and your LAN machines configured with SSH, VNC, or RDP which is probably already the case)
  • for VNC, it’s way faster and more responsive than tunneling VNC through SSH\
  • supports lots of different two factor authentication mechanisms
  • free and open source
  • supports SFTP making it easy to transfer files between machines

Cons:

  • installation is kind of a pain, even when using Docker
  • if the network connection is iffy, it’s all but unusable
  • copy & paste is awkward

Installation

Installing Guacamole is somewhat of a pain. I’ve included here my Ansible role that installs Guacamole using Docker. I already had a PostgreSQL server set up for NextCloud so I’ve reused that container for Guacamole as well. MySQL is also supported if you prefer.

Guacamole consists of three different services:

  1. guacd: this is the part that actually connects to your LAN machines
  2. Guacamole: this serves up the HTML5 user interface
  3. database: I’m using PostgreSQL

I’m running all three using Docker.

One of the gotchas is that there is an SQL script you need to generate by executing a script in the Guacamole container and execute on the database container which makes the whole thing a little awkward to get set up correctly.

Here’s the Ansible role I wrote. I’m already running PostgreSQL so pulling and starting that is missing from the role. I can post that if you need it.

---

- name: Create guacamole user
  user:
    comment: 'Guacamole Server'
    createhome: yes
    name: guacamole
    shell: /usr/sbin/nologin
    state: present
    system: yes
    uid: "{{ guacamole_uid }}"
  become: true

- name: Start guacd
  docker_container:
    detach: True
#    exposed_ports:
#      - 4822
    image: guacamole/guacd
    log_driver: syslog
    name: guacd
    env:
      GUACD_LOG_LEVEL: "debug"
#    published_ports:
#      - "4822:4822"
    pull: True
    restart: True
    restart_policy: always
    user: 986:986

- name: Install psycopg2
  pip:
    name: psycopg2-binary

- name: Create postgres database
  postgresql_db:
    login_host: medusa.koshak.net
    login_password: "{{ share_pass }}"
    login_user: postgres
    name: guacamole_db

- name: Create guacamole_user for guacamole_db
  postgresql_user:
    db: guacamole_db
    login_host: medusa.koshak.net
    login_password: "{{ share_pass }}"
    login_user: postgres
    name: guacamole_user
    password: "{{ share_pass }}"

- name: Give guacamole_user permissions on tables
  postgresql_privs:
    database: guacamole_db
    grant_option: yes
    login_host: medusa.koshak.net
    login_password: "{{ share_pass }}"
    login_user: postgres
    objs: ALL_IN_SCHEMA
    privs: SELECT,INSERT,UPDATE,DELETE
    roles: guacamole_user
    schema: public
    state: present
    type: table

- name: Give guacamole_user permissions on sequences
  postgresql_privs:
    database: guacamole_db
    grant_option: yes
    login_host: medusa.koshak.net
    login_password: "{{ share_pass }}"
    login_user: postgres
    objs: ALL_IN_SCHEMA
    privs: SELECT,USAGE
    roles: guacamole_user
    schema: public
    state: present
    type: sequence

- name: Create initdb.sql script
  shell: docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --postgres > /tmp/initdb.sql
  args:
    creates: /tmp/initdb.sql

- name: Create the databases from initdb.sql
  shell: docker exec -i postgres psql -d guacamole_db guacamole_user < /tmp/initdb.sql

- name: Create Guacamole folder
  file:
    path: /mnt/guacamole/extensions
    state: directory
    owner: guacamole
    group: guacamole
    mode: u=rwx,g=rwx,o=rwx
  become: true

- name: Download the TOTP extension
  get_url:
    url: http://apache.org/dyn/closer.cgi?action=download&filename=guacamole/1.1.0/binary/guacamole-auth-totp-1.1.0.tar.gz
    dest: /tmp/guacamole-auth-totp.tar.gz
    mode: u=rwx,g=rwx,o=rwx

- name: Extract the TOTP extension
  unarchive:
    src: /tmp/guacamole-auth-totp.tar.gz
    dest: /tmp
    remote_src: true
  become: yes
  become_user: guacamole

- name: Copy the extracted jar file
  copy:
    src: /tmp/guacamole-auth-totp-1.1.0/guacamole-auth-totp-1.1.0.jar
    dest: /mnt/guacamole/extensions/guacamole-auth-totp-1.1.0.jar
    mode: u=rw,g=rw,o=rw
    remote_src: true
  become: yes
  become_user: guacamole

- name: Start guacamole
  docker_container:
    detach: True
    exposed_ports:
      - 8080
    image: guacamole/guacamole
    links:
      - "guacd:guacd"
    log_driver: syslog
    name: guacamole
    env:
      GUACAMOLE_HOME: /etc/guacamole
      POSTGRES_HOSTNAME: 10.10.1.126
      POSTGRES_PORT: "5432"
      POSTGRES_DATABASE: guacamole_db
      POSTGRES_USER: guacamole_user
      POSTGRES_PASSWORD: "{{ share_pass }}"
    published_ports:
      - "9999:8080"
    pull: True
    restart: True
    restart_policy: always
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
      - /etc/hosts:/etc/hosts:ro
      - /mnt/guacamole:/etc/guacamole:rw

The above creates a user to run Guacamole under, though I found only guacd can use it. I need to figure out how to make it work. Then it starts guacd which is really simple. Just pull the image and start the container. Then we create the database and user for Guacamole and give the new user the right permissions.

The next task pulls the Guacamole Docker Image and runs the script that generates the SQL script that will initialize the database followed by executing that script on PostgreSQL. I was able to cheat a bit because my PostgreSQL is running on the same machine as I’m deploying Guacamole. So I executed the scrip right on the Docker container.

Finally, I download and deploy the TOTP extension (untested) and deploy the Guacamole container.

Configuration

Configuration is pretty easy but there are a lot of options so I suggest reading the Guacamole docs. I have one VM running a desktop version of Ubuntu with VNC configured and the rest of my VMs and RPis are headless with only terminal access. I configured a connection for each.

There is a place to enter the host keys or you can mount a known-hosts file to the container. If you supply neither than Guacamole will not check the host keys on SSH/SFTP connections.

Reverse Proxy

I’m using pfSense with HAProxy which I documented at Remote Access: pfSense + HAProxy + LetsEncrypt. The Guacamole docs have a full configuration for nginx and Apache as well if that’s what you are using.

Hopefully this is enough to get you started. If not ask questions.

Warnings

I do not recommend exposing anything on your LAN directly to the Internet, even through a reverse proxy, unless you are knowledgeable and experienced at configuring and monitoring these systems fro attack and responding when they become attacked.

4 Likes

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.