Idle memory separates these three servers more than any feature list does. In the Guacamole vs RustDesk vs MeshCentral test below, the RustDesk server pair (hbbs 1.1.16, measured October 2026 on Ubuntu 26.04) held 14.5 MiB of RAM. MeshCentral 1.3.1 held 284 MiB across two Node.js processes, and the Apache Guacamole stack held 650 MiB, of which 435 MiB was MySQL. The gap follows the architecture: RustDesk only brokers and relays connections, MeshCentral runs a device-management web app, and Guacamole renders RDP, SSH and VNC sessions inside your browser.
All three ran side by side on one 2-vCPU, 4 GB VM, and every number on this page comes from that box. This refresh replaces the March figures, adds the RustDesk 1.5.0 client changes (WebRTC, ID whitelist, recording options), the Server Pro tiers and prices, and the MeshCentral 1.3.1 security release. For full installs, see the Guacamole on Ubuntu guide and the RustDesk client and self-hosted server walkthrough.
1. Guacamole vs RustDesk vs MeshCentral: measured results
Each row pairs the current release of a server with what it cost on the test box. Versions come from the release page of each project on 24 October 2026; RAM, processes and ports come from the running VM.
| Metric | Apache Guacamole | RustDesk Server (OSS) | MeshCentral |
|---|---|---|---|
| Server version tested | 1.6.0 (released 2025-06-22) | hbbs/hbbr 1.1.16 (2026-07-20); current client 1.5.0 (2026-09-30), not run here | 1.3.1 (2026-10-23) |
| Idle RAM | 649.8 MiB (guacamole 194.3, MySQL 435.4, guacd 20.1) | 14.5 MiB (hbbs 10.7, hbbr 3.9) | 284.0 MiB RSS, 224.6 MiB PSS (two node processes) |
| Processes | 3 containers | 2 containers | 2 node processes (launcher + server) |
| Listening ports | 8080/tcp | 21115-21117/tcp, 21116/udp, 21118-21119/tcp (web client) | 443 + 80 (1025 + 1024 without bind privilege) |
| Disk | 2.6 GB of images (guacamole 1.12 GB, mysql 1.12 GB, guacd 377 MB) | 19 MB image | 341 MB node_modules + 142 MB data (agents) |
| Endpoint software | None (browser only) | RustDesk client on both ends | Mesh agent on managed devices |
| License | Apache-2.0 | AGPL-3.0 | Apache-2.0 |
In March this page listed roughly 50, 500 and 200 MB. The new measurements move all three. RustDesk is under a third of the old figure, and Guacamole is 150 MiB heavier because MySQL 8.4 alone takes 435 MiB at idle. MeshCentral comes in higher once the launcher process is counted. If you already run MySQL or PostgreSQL elsewhere, pointing Guacamole at it removes the largest single item in the table.
Our short verdict has not changed, but the reasons are sharper. Use RustDesk for helpdesk sessions to machines behind NAT, Guacamole for browser access to servers you can already reach over RDP, SSH or VNC, and MeshCentral when you manage a fleet and want an agent on every box. Section 8 breaks this down pair by pair.
2. How the numbers were taken
One VM ran all three servers at the same time: Ubuntu 26.04 LTS, 2 vCPU with the host CPU type, 4 GB RAM, Docker 29.1.3 and Node.js 22.22.1 from the Ubuntu archive. Each metric was taken the same way for every tool:
- Idle RAM, containers:
docker stats --no-stream, two rounds of three samples taken 60 seconds apart, with no sessions open. All six agreed within 0.4 MiB, so the table gives the last sample. - Idle RAM, MeshCentral: RSS from
psand PSS from/proc/<pid>/smaps_rollupfor both node processes, summed. PSS is lower because the two processes share library pages. - Ports:
ss -tulpnon the running services, not the documentation. - Disk:
docker imagesfor the container stacks anddu -shfor the MeshCentral directories.
The last of those samples, with both MeshCentral processes listed and no client connected:

Both MeshCentral lines matter. Process 3473 is the launcher that restarts the server if it crashes, and process 3485 is the server itself at 212 MiB RSS. Counting only the second process would understate MeshCentral by a quarter. All of these are idle figures. Open sessions add to them, and this lab did not measure load.
Error: “Fatal glibc error: CPU does not support x86-64-v2”
The first Guacamole start failed. The guacamole and guacd containers came up, the web page answered HTTP 200, and the MySQL container went into a restart loop with exit code 127:
sudo docker logs guac-mysql 2>&1 | tail -2
Every restart printed the same line:
Fatal glibc error: CPU does not support x86-64-v2
Fatal glibc error: CPU does not support x86-64-v2
The VM was a Proxmox clone with the default kvm64 CPU type, which hides the instructions the mysql:8.4 image is built for. kvm64 is the default for qm and the API, while the Proxmox web UI has defaulted to x86-64-v2-AES since PVE 8. Setting the CPU type to host (or x86-64-v2-AES) fixed it after a stop and start from Proxmox; a reboot from inside the guest keeps the old QEMU process and does not apply the change. On the next start MySQL 8.4.13 reported “ready for connections”. The trap is that the login page still loads while the database is down, and logging in returns “Unexpected internal error”. Check docker compose ps before you debug Guacamole itself. RustDesk, the only other stack started before the CPU change, ran on kvm64 without complaint.
3. Feature comparison: protocols, auth, NAT and recording
Feature rows below come from current project documentation and release notes, cross-checked against what the lab install exposed. Rows marked Pro apply to RustDesk Server Pro, which we did not run.
| Category | Apache Guacamole 1.6.0 | RustDesk Server 1.1.16, client 1.5.0 (release notes) | MeshCentral 1.3.1 |
|---|---|---|---|
| Architecture | Gateway: browser to guacd to target | P2P with relay fallback | Agents call home to a web server |
| Protocols | RDP, SSH, VNC, Telnet, Kubernetes | RustDesk protocol; WebRTC transport added in 1.5.0 | Agent desktop/terminal/files, Web-RDP, Web-SSH, Web-VNC, Intel AMT |
| Client needed | Browser only | Native app on both sides | Browser for admins, agent on endpoints |
| Web admin UI | Connection manager | None in OSS; web console in Pro | Full management dashboard |
| Authentication | Database, LDAP, TOTP, Duo, SAML, OpenID Connect | Device ID + password; OIDC and LDAP in Pro Basic | Local accounts, LDAP, OIDC, TOTP 2FA |
| NAT traversal | No, the server must reach the target | Yes, hole punching plus relay | Yes, outbound agent connection |
| Session recording | Built in | Client-side recording; 1.5.0 adds hidden-button and service save-directory options | Built in (sessionRecording in config.json) |
| Multi-user / RBAC | Users, groups, connection groups | Pro only (users, groups, access control) | Users, user groups, device-group rights |
| Out-of-band | No | No | Intel AMT |
| Mobile | Browser | Native Android and iOS apps | Browser |
| Install used here | Docker Compose, 3 containers | Docker Compose, 2 containers | npm, single app |
Two rows read differently from the March table. RustDesk is no longer listed as “no recording”: the client has recorded sessions locally since well before 1.5.0, and 1.5.0 lets an admin hide the record button while auto-recording outgoing sessions. The MeshCentral row now names its browser-based Web-RDP, Web-SSH and Web-VNC actions, which are long-standing documented features rather than new ones, so MeshCentral overlaps with Guacamole more than a plain “remote desktop agent” label suggests.
4. RustDesk: what client 1.5.0 and server 1.1.16 changed
Server 1.1.16 is a security and correctness release, and it is the one to run. Its release notes list three fixes. Unauthenticated UDP punch-hole requests could be abused for reflection and amplification, and peers offline for 24.9 to 49.7 days were reported online because of an i32 overflow. The bundled mio crate also moved from 0.8.5 to 0.8.11. A public hbbs on 1.1.15 or older can be abused as a UDP reflector, so upgrade it even if nothing else looks wrong.
We ran the official Docker Compose layout with host networking. This is the exact compose.yml from the test box:
services:
hbbs:
container_name: hbbs
image: rustdesk/rustdesk-server:latest
command: hbbs
volumes:
- ./data:/root
network_mode: "host"
depends_on:
- hbbr
restart: unless-stopped
hbbr:
container_name: hbbr
image: rustdesk/rustdesk-server:latest
command: hbbr
volumes:
- ./data:/root
network_mode: "host"
restart: unless-stopped
Start it, then ask the running container for its version and confirm the listeners:
sudo docker compose up -d
sudo docker exec hbbs hbbs --version
sudo ss -tulpn | grep -E "2111[5-9]"
The latest tag resolved to 1.1.16, and hbbs owns 21115, 21116 (TCP and UDP) and 21118 while hbbr owns 21117 and 21119:
hbbs 1.1.16
udp UNCONN 0 0 *:21116 *:* users:(("hbbs",pid=34894,fd=8))
tcp LISTEN 0 128 *:21115 *:* users:(("hbbs",pid=34894,fd=10))
tcp LISTEN 0 128 *:21116 *:* users:(("hbbs",pid=34894,fd=9))
tcp LISTEN 0 128 *:21117 *:* users:(("hbbr",pid=34847,fd=9))
tcp LISTEN 0 128 *:21118 *:* users:(("hbbs",pid=34894,fd=12))
tcp LISTEN 0 128 *:21119 *:* users:(("hbbr",pid=34847,fd=10))
Ports 21118 and 21119 are WebSocket listeners for the web client, and they open by default. The RustDesk docs warn that hbbs and hbbr trust X-Real-IP and X-Forwarded-For on those ports without validation, so keep them closed in the firewall unless a reverse proxy sits in front. Upgrading an existing install is docker compose pull followed by docker compose up -d, and the key pair in ./data survives, so clients keep working.
Client 1.5.0 (30 September 2026) is the bigger change for users. These are the additions that affect a self-hosted deployment, taken from the release changelog and the linked pull requests:
- WebRTC transport: ICE, DTLS and an SCTP data channel raced alongside the existing hole punching, IPv6 and relay paths. The client falls back to the old transports when the peer or server has no WebRTC support. Server Pro 1.8.7 lists WebRTC support; the OSS 1.1.16 notes do not, so expect classic punching and relay against an OSS server.
- ID whitelist: a new security setting that accepts incoming sessions only from listed RustDesk IDs (wildcards allowed), next to the existing IP whitelist.
- Recording options: hide the record button while auto-recording outgoing sessions, and set a save directory for recordings made by the Windows service.
- Kx v1: a versioned key exchange bound to the handshake transcript; legacy peers still connect with the old scheme.
Clipboard sync between connected sessions and HDR tone mapping also landed in 1.5.0. We did not run a client-to-server session in this lab, so the client rows above are release-note facts, not measurements. The client install, pointing it at your own hbbs with the public key, and the UFW rules are covered in the RustDesk on Ubuntu guide.
5. RustDesk Server Pro 1.8.7: tiers and pricing
Server Pro is a separate, closed-source licensed server with a web console on port 21114. We have not run it, so this section is from the RustDesk pricing page and the 1.8.7 release notes as of 24 October 2026. Every paid plan is billed annually, and there is no monthly option.
| Plan | Price (billed annually) | Login users | Managed devices | What it adds |
|---|---|---|---|---|
| Free (OSS) | $0 | n/a | n/a | Online status, community support |
| Individual | $11.88/month | 1 | 20 | Web console, 2FA, address book, audit log, change ID, access control, centralized settings, distributed relays |
| Basic | $23.88/month | 10 | 100 | Everything in Individual plus OIDC (SSO), LDAP, cross-group access, custom client generator |
| Customized | From $23.88/month | +$1.20 each | +$0.12 each | Everything in Basic, sized to your counts |
| Customized V2 | From $23.88/month | +$1.20 each | +$0.12 each | Basic features with a cap on concurrent connections, +$24 per concurrent connection |
Pricing works out to $142.56 a year for Individual and $286.56 for Basic. The tier that matters for most teams is Basic, because SSO and LDAP stop at that line, and those two features are what the OSS server lacks most. The browser-based web client is included in Pro only on plans where users Γ 10 + devices reaches 400 or more, which rules out both fixed tiers. Pro 1.8.7 (1 October 2026) adds WebRTC support and fixes an LDAP and OIDC login prompt for accounts that share an email address.
6. Apache Guacamole: still 1.6.0, still the heaviest
Guacamole has had no release since 1.6.0 on 22 June 2025, which added faster rendering, better Docker support, batch connection import and Duo v4. Its release archive still lists 1.6.0 as current. Nothing in this comparison moved for Guacamole except its memory figure, and that moved because the database did.
The 1.6.0 images read database settings from environment variables, so the stack is one file plus a schema dump. This is the corrected Compose file from the test box; change both passwords before you use it:
services:
guacd:
image: guacamole/guacd:1.6.0
container_name: guacd
restart: unless-stopped
mysql:
image: mysql:8.4
container_name: guac-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ChangeMeRoot123
MYSQL_DATABASE: guacamole_db
MYSQL_USER: guacamole_user
MYSQL_PASSWORD: ChangeMeGuac123
volumes:
- ./initdb:/docker-entrypoint-initdb.d:ro
- ./mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uguacamole_user", "-pChangeMeGuac123"]
interval: 10s
timeout: 5s
retries: 12
start_period: 30s
guacamole:
image: guacamole/guacamole:1.6.0
container_name: guacamole
restart: unless-stopped
depends_on:
guacd:
condition: service_started
mysql:
condition: service_healthy
environment:
GUACD_HOSTNAME: guacd
MYSQL_HOSTNAME: mysql
MYSQL_DATABASE: guacamole_db
MYSQL_USERNAME: guacamole_user
MYSQL_PASSWORD: ChangeMeGuac123
ports:
- "8080:8080"
Generate the schema from the image itself, so it always matches the webapp version, then start the stack from the same directory:
mkdir -p initdb
sudo docker run --rm guacamole/guacamole:1.6.0 /opt/guacamole/bin/initdb.sh --mysql > initdb/initdb.sql
sudo docker compose up -d
The dump was 669 lines. Our first version of this file used MYSQL_USER for the guacamole service and had no healthcheck, and the RAM figures in section 1 come from that run. It worked, but the webapp logged that MYSQL_USER is deprecated in favor of MYSQL_USERNAME, and because it started before MySQL finished importing the schema, the first login failed with “Communications link failure” until a docker compose restart guacamole. With the file above on a fresh database, docker compose up -d waited 16 seconds for MySQL to report healthy, the first login worked, and the deprecation warning was gone. The healthcheck uses -h 127.0.0.1 on purpose: the temporary server MySQL runs during first init has networking disabled, so a TCP ping cannot pass early. Compose only honours that ordering on docker compose up; after a host reboot, Docker restarts the containers by restart policy with no ordering, so restart the guacamole container if a login fails right after boot.
The webapp answers at http://10.0.1.50:8080/guacamole/, and the bare / path returns a Tomcat 404 unless you set WEBAPP_CONTEXT=ROOT. The schema creates a guacadmin user with the password guacadmin, so change it or replace that account on first login.

Guacamole’s strength is still zero endpoint software. Credentials live on the server, users never see target IPs or passwords, and recordings are built in, which is why it fits audited access to datacenter and cloud hosts. Its weakness is also unchanged: it connects to machines it can reach and cannot punch through NAT, so remote laptops need a VPN first. For the connection setup, see configuring Guacamole for RDP, SSH and VNC, and for MFA, the Active Directory and Duo integration.
7. MeshCentral 1.3.1: security release and a new agent download
MeshCentral moved from 1.1.58 to 1.3.1 since March, and the last step is urgent. The 1.3.1 release (23 October 2026) is marked as a security update for an active exploit that was taking control of MeshCentral servers and their remote clients. If you run any older version on a public address, upgrade it or take it offline today. The release notes give no CVE number.
Installing it takes one npm package. We used a plain user account and Node.js 22 from the Ubuntu archive, where npm is a separate package (sudo apt install nodejs npm):
mkdir -p ~/meshcentral && cd ~/meshcentral
npm install meshcentral
node node_modules/meshcentral
npm added 181 packages in 18 seconds. The plain package name resolves to the npm latest tag (1.3.1); the stable tag still pointed at 1.1.59 on 24 October, so do not install meshcentral@stable until it moves past 1.3.1. The first start then generated its certificates and pulled the agent binaries from GitHub, which is the 1.3.0 change (certificate, code-signing and one agent-loading line trimmed):
MeshCentral HTTP redirection server running on port 1024.
Generating certificates, may take a few minutes...
MeshCentral v1.3.1, LAN mode.
Downloading 31 default agent files (119 MiB) from GitHub releases...
Default agent downloads are still running. Starting without them; they load when they finish.
Server has no users, next new account will be site administrator.
WARNING: MeshCentral is running without permissions to use ports below 1025.
Use setcap to grant access to lower ports, or read installation guide.
sudo setcap 'cap_net_bind_service=+ep' `which node`
WARNING: Server running without permissions to use ports below 1025.
MeshCentral HTTPS server running on port 1025.
Default agent files loaded.
Two details from that log correct the old version of this page. An unprivileged MeshCentral listens on 1025 (HTTPS) and 1024 (HTTP redirect), not 4430. After sudo setcap 'cap_net_bind_service=+ep' /usr/bin/node and a restart it moved to 443 and 80. That capability applies to every Node.js script any user runs, and it is lost when apt upgrades the nodejs package, after which MeshCentral quietly drops back to 1024 and 1025. A systemd unit with AmbientCapabilities=CAP_NET_BIND_SERVICE is the cleaner long-term setup. The server also needs outbound HTTPS to GitHub on first start, and the downloaded agents are why meshcentral-data weighed 142 MB. On an air-gapped server, stage those agent files first or the agent installers will be missing.
After the restart, the login page answers on 443:

The first account created becomes the site administrator, so create it yourself right after the first start instead of leaving the page open on a public address. After that login, MeshCentral opens on an empty My Devices page and asks for a device group, which is where agent installers are generated:

The capture shows the classic UI. The learning curve is the real cost of MeshCentral. Device groups, agent install modes, relay settings and per-group rights all need decisions before the first agent goes out. After that, you still push the agent to every endpoint with SCCM, Ansible or by hand.
8. Which to run: MeshCentral vs RustDesk vs Guacamole
Each pair below comes down to one architectural difference, and the measured numbers above tell you what that difference costs on a server.
MeshCentral vs RustDesk
Both reach machines behind NAT, so the question is management. RustDesk is a remote-control tool: a user reads out an ID, a technician connects, and the OSS server keeps no users, groups or audit trail. MeshCentral keeps a permanent inventory of enrolled devices with terminal, file transfer, power control and recordings from one dashboard. Pick RustDesk for ad-hoc support at 14.5 MiB of server RAM, and MeshCentral when you own the machines and want them listed even when nobody is connected. RustDesk Pro Basic at $23.88 a month narrows the gap with users, LDAP and OIDC, but it still has no Intel AMT or hardware inventory.
RustDesk vs Guacamole
These solve opposite problems. Guacamole needs nothing on the target beyond RDP, SSH or VNC, but the Guacamole server must be able to reach it. RustDesk needs its client on the target, but the target can sit behind any NAT. For servers in a datacenter or VPC, Guacamole is the better fit and its 650 MiB is a fair price for browser access and central credentials. For laptops at home and on mobile networks, RustDesk wins, and no amount of Guacamole configuration replaces hole punching.
Guacamole vs MeshCentral
MeshCentral’s Web-RDP, Web-SSH and Web-VNC actions overlap with Guacamole, and MeshCentral can even reach agentless machines through a “local devices, no agent” device group. Guacamole stays the cleaner choice when agentless access is the whole job (appliances, customer servers, network gear over SSH), because it brings central credentials, connection sharing and recording without the device-management layer. Pick MeshCentral when you can install agents and also want inventory and out-of-band control. The three also coexist: on this VM they ran together at about 950 MiB combined, with the whole guest reporting 1,352 MiB used out of 3,910 MiB. From those numbers a 2 GB server should hold all three at idle, though we only measured the 4 GB guest, and a busy Guacamole would leave little room, so we would size a shared box at 4 GB.
If Guacamole is your pick, the Docker Compose deployment guide covers TLS and a reverse proxy, and the Rocky Linux and AlmaLinux install covers a native build with SELinux enforcing.