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:
- guacd: this is the part that actually connects to your LAN machines
- Guacamole: this serves up the HTML5 user interface
- 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.