How to Access Remote Desktops Using Apache Guacamole
This article is intended for readers who want to create a custom Guacamole Client using guacamole-common-js and establish connections to their remote servers.
Join the DZone community and get the full member experience.
Join For FreeWhat Is Apache Guacamole?
Apache Guacamole is an open-source framework created by the Apache Foundation that provides an HTML5 application that acts as a remote desktop gateway to enable access to remote desktops via the RDP, SSH, and VNC protocols without the use of any other third-party software.
The Guacamole solution includes many individual components, such as libguac
, guacamole-common
, and guacamole-ext
. While these projects are beyond the scope of this article, we'll hone in on guacamole-common-js
within the Guacamole ecosystem.
What Is guacamole-common-js?
The Guacamole project provides a JavaScript API for interfacing with components designed to meet Guacamole specifications. The guacamole-common-js
API offers a JavaScript implementation of a Guacamole Client and tunneling mechanisms to transfer protocol data from JavaScript to the server side of the application. The server side typically runs a machine with guacd
or the Guacamole Daemon. The guacamole-common-js
library provides mouse and keyboard abstraction objects to translate JavaScript mouse and keyboard events into data that Guacamole can easily digest.
Using guacamole-common-js to Create a Custom Guacamole Client
Prerequisites: Install guacamole-common-js via any package manager of your choice. In this example, we will use npm
.
npm i guacamole-common-js
Step 1: Create a Guacamole Tunnel
Creating a Guacamole Tunnel allows you to stream data effortlessly between the server and your client.
const Guacamole = require('guacamole-common-js')
let tunnel = new Guacamole.Tunnel("path/to/your/tunnel");
You can pass additional parameters to your server via the tunnel URL using query parameters. For example, your tunnel URL can look like path/to/your/tunnel?param1=value1¶m2=value2
.
Step 2: Use the Tunnel Object to Create a Guacamole Client
You can create a Guacamole Client object by passing the Tunnel object you just created to the Guacamole.Client
constructor.
let guacClient = new Guacamole.Client(tunnel)
Step 3: Call the Connect Function to Establish the Connection
So, we have the Guacamole Tunnel instance and the Guacamole Client instance. These are all we need to establish a connection to our remote machine.
guacClient.connect()
Just one thing to remember: The Guacamole.Tunnel
object passed into the Guacamole.Client
constructor must not already be connected. This is because, internally, the guacClient.connect()
method will call the tunnel.connect()
method, and if the tunnel is already connected, this operation will fail.
Now, the astute amongst you will find that you still don't see the contents of your remote machine on your client. That's because we're still missing one crucial step.
Step 4: Get the Guacamole Display and Attach It to the DOM
Once you have established the connection by calling guacClient.connect()
, you can view the remote machine's display by attaching the Guacamole display (an HTMLDivElement
) to the DOM. Let's see how we can do that.
Imagine you have an HTML page where you wish to show the display of your remote machine.
<html>
<body id="guacCanvas">
</body>
</html>
Next, let's get the HTMLDivElement
, which needs to be displayed to the user from the guacClient
.
// Get the display element from the guacClient
let displayElement = guacClient.getDisplay().getElement();
// Get the element from the DOM and attach the displayElement to it
let guacCanvas = document.getElementById('guacCanvas');
// Attach the displayElement to the canvas
guacCanvas.appendChild(displayElement);
Et voila! You now see the contents of your remote machine on your DOM. But wait, something isn't right. Your keyboard input does nothing, and neither does your mouse. How do we address that?
Step 5: Configure Keyboard and Mouse Events
To configure keyboard and mouse events, you need to set up the input handlers provided by guacamole-common-js
.
Let's first look at how we can configure mouse events.
let mouse = new Guacamole.Mouse(guacElement)
// Primarily you need to handle 3 events. onmousedown, onmouseup, onmousemove.
// The high level idea is to send the current state of the mouse to guacamole
// whenever the mouse moves, the mouse gets clicked or unclicked.
const sendMouseState = (mouseState) => {
guacClient.sendMouseState(mouseState);
}
// Essentially sending mouse state for all the individual events
mouse.onmousedown = mouse.onmouseup = mouse.onmousemove = sendMouseState;
Keyboard configuration is even simpler because there are just two events that need to be configured.
let keyboard = new Guacamole.Keyboard(guacElement);
// you need to pass in the HTMLElement here where you want the keyboard events to
// be passed into Guacamole. For example, if you pass in the document object instead
// of guacElement, you'll send all the events in the entire DOM to Guacamole, which may
// or may not be something you want. If you don't have any other UI elements in your
// DOM, you should be fine sending document, but if you have other UI elements in addition
// to your guacCanvas, you'd be better off passing just the guacCanvas.
// You need to configure 2 events. onkeyup and onkeydown
keyboard.onkeydown = (keysym: number) => {
guacClient.sendKeyEvent(1, keysym); // Send keydown event to the remote server
};
keyboard.onkeyup = (keysym: number) => {
guacClient.sendKeyEvent(0, keysym); // Send keyup event to the remote server
};
Step 6: Configure Touch Events (Optional)
Optionally, you can also configure your client for touch inputs, but it will be translated to Guacamole.Mouse
events.
let touch = new Guacamole.Touch(guacCanvas);
// You need to configure 3 events here ontouchstart, ontouchend, ontouchmove
touch.onmousedown = touch.onmouseup = touch.onmousemove =
(touchState) => guacClient.sendMouseState(touchState);
const handleTouchEvent = (event) => {
event.preventDefault();
let touchState = touch.getMouseState(event);
guacClient.sendMouseState(touchState);
}
touch.ontouchstart = touch.ontouchend = touch.ontouchmove = handleTouchEvent;
As you can see, we're translating touch events into Guacamole mouse events, and this step is entirely optional. You need to configure touch events only if you intend to use your custom client on a touchscreen device.
Step 7: Disconnect From Your Remote Machine
Finally, we've reached the last step, which is disconnecting from your remote machine, and it is as simple as calling a method on your client.
guacClient.disconnect();
Conclusion
To summarize, Apache Guacamole is a powerful and versatile open-source framework that offers a seamless way to access remote desktops through the RDP, SSH, or VNC protocols. The guacamole-common-js
library allows developers to create custom Guacamole clients that can interface with other Guacamole components like guacamole-common
, guaclib
, and guacamole-ext
.
By following the steps outlined in this article, you can set up a basic custom guacamole client that can connect to your remote servers and handle keyboard, mouse, and touch events.
Opinions expressed by DZone contributors are their own.
Comments