开源远程桌面网关GUACAMOLE
一、概述
Apache Guacamole 是一款基于浏览器的开源远程桌面网关,纯 Web 访问,无需客户端,支持 RDP、VNC、SSH、Telnet 等主流远程协议
架构分为前端(guacamole-client) 和后端代理(guacd) 两部分,二者分离部署、分工协作
二、guacamole-client(前端 / 客户端)
1、作用
- 运行在 Web 容器(Tomcat、Nginx+Jetty 等),提供Web 访问界面
- 接收浏览器请求、用户登录、权限校验、会话管理
- 不直接连接远程主机,所有远程连接请求转发给
guacd处理 - 协议转换:把浏览器 WebSocket 流量转为 Guacamole 私有协议,和 guacd 通信
2、核心组件
- 网页 UI:纯 HTML5,任意现代浏览器打开即可远程桌面 / 终端
- 认证模块:支持本地账号、LDAP、数据库、CAS、TOTP 二次验证等
- 连接管理:保存远程主机地址、端口、账号、协议、参数等配置
3、特点
- 无客户端、跨平台、跨终端(电脑 / 平板 / 手机)
- 可做统一远程运维入口,集中管理大量服务器 / Windows 主机
三、guacd(Guacamole Daemon 守护进程)
1、定位
- Guacamole 的后端代理服务,是整个远程连接的真正执行者,独立后台进程
2、核心作用
- 监听前端
guacamole-client的连接请求(默认 TCP 4822 端口) - 解析请求,主动发起 RDP/VNC/SSH/Telnet 到目标远程主机
- 完成协议编解码、画面渲染、键鼠 / 剪贴板 / 文件传输转发
- 隔离前端与内网主机:外网只访问 Web 前端,
guacd在内网对接设备,提升安全
3、关键特性
- 多线程:支持并发多个远程会话,每个会话独立线程
- 资源代理:剪贴板共享、文件上传下载、音频、打印机、串口等都由它中转
- 轻量、高性能,一般部署在内网运维区
4、端口与运行
- 默认监听端口:4822/TCP
- 运行模式:后台守护进程,日志独立输出
- 依赖系统库:
libguac、RDP/VNC/SSH 相关协议库
四、整体通信流程(最简链路)
- 浏览器 → 访问 Guacamole Web 前端(client)
- client 鉴权通过 → 通过 4822 端口 连接
guacd - guacd → 根据配置,使用 RDP/SSH/VNC 连接目标服务器 / 主机
- 远程主机画面、键鼠操作反向原路回传至浏览器
五、部署(Docker方式)
1、首先下载三个镜像
docker pull guacamole/guacd:latest
docker pull guacamole/guacamole:latest
docker pull postgres:15-alpine
2、生成数据库初始化 SQL,本例子使用postgresql
docker run --rm guacamole/guacamole:latest /opt/guacamole/bin/initdb.sh --postgresql > initdb.sql
3、编辑docker-compose.yml文件,自己设置postgresql账号密码,内容如下:
services:
postgres:
image: postgres:15-alpine
container_name: guacamole-postgres
restart: unless-stopped
environment:
POSTGRES_DB: guacamole_db
POSTGRES_USER: guacamole_user
POSTGRES_PASSWORD: guacamole_pass
volumes:
- pgdata:/var/lib/postgresql/data
- ./initdb.sql:/docker-entrypoint-initdb.d/initdb.sql:ro
guacd:
image: guacamole/guacd:latest
container_name: guacamole-guacd
restart: unless-stopped
volumes:
- /usr/share/fonts:/usr/share/fonts:ro
environment:
GUAC_ENCODING: UTF-8
LANG: zh_CN.UTF-8
LC_ALL: zh_CN.UTF-8
ulimits:
nproc:
soft: 65535
hard: 65535
nofile:
soft: 65535
hard: 65535
guacamole:
image: guacamole/guacamole:latest
container_name: guacamole-web
restart: unless-stopped
ports:
- "8080:8080"
environment:
GUACD_HOSTNAME: guacd
POSTGRESQL_HOSTNAME: postgres
POSTGRESQL_DATABASE: guacamole_db
POSTGRESQL_USER: guacamole_user
POSTGRESQL_PASSWORD: guacamole_pass
depends_on:
- guacd
- postgres
volumes:
pgdata:
- volumes: 挂载本地字体到容器中,否则中文乱码
- environment: 设置字符集
- ulimits: 设置打开文件树
4、把initdb.sql 和docker-compose.yml放在同一目录下,然后启动
docker-compose up -d
注:如果postgresql是单独部署的,那就要单独把initdb.sql执行下,然后在environment里配置pg地址即可
5、输入http://IP:8080/guacamole 打开页面,输入账号密码登录
默认账号/密码:guacadmin / guacadmin

6、配置连接主机,我这里先创建了连接组,来区分系统类型,如图:

7、然后点击新建连接,输入连接的机器名字、协议,位置就是刚才的组,连接数自定义,如图:

网络位置,填写真正需要连接的主机IP、端口,会话超时时间,认证位置,填写用户名和私钥,如果使用密码认证也可以,页面默认私钥是明文的,因此在服务器上生成私钥的时候要加密,然后在口令位置,输入加密私钥的时候使用的密码,如下:
ssh-keygen -t rsa -f id_rsa -N "强密码" #给私钥加密

注:这个私钥是哪个私钥? 私钥和公钥是配对出现的,因此这个私钥不要用目标机器的私钥,可以是guacamole宿主机生成的私钥和公钥也行,或者任意一台机器生成的私钥和公钥都行,私钥填写到guacamole页面中,公钥内容放到要连接的远程机器的username/.ssh/authorized_keys中即可,私钥跟公钥配对,跟哪个机器无关,不绑定机器的任何信息
SFTP位置,选择开启,设置个上传文件的目录,如图:

主要的就这些,其余配置根据需要自行配置就行
8、点击账户,首页回到页面,可以看到机器信息,如图:


9、点击即可连接机器,如图:

10、默认情况下连接后是全屏的,不能回到主界面了,此时可以按ctrl + alt + shift,如图:

点击上面下拉列表即可回到主界面中,同时可以看到下面的设备位置,就是上一步设置的SFTP的目录,点击设备名,进入到/tmp目录下,此时就可以上传和下载文件了

配置代理
如果要通过Nginx反代到guacamole,推荐配置如下:
server {
listen 443 ssl;
server_name guacamole.xxx.com;
location /guacamole/ {
proxy_pass http://192.168.51.56:8080/guacamole/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
client_max_body_size 500M;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
Nginx 默认会缓存响应,但是 Guacamole 是实时流,因此建议关闭缓存:
proxy_buffering off;
proxy_cache off;
检查Nginx是否配置WebSocket Upgrade(最重要)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1; #WebSocket 的握手需要 HTTP/1.1 的 Upgrade 机制
为什么要配置这个websocket upgrade ? 要先了解下WebSocket是什么
Guacamole 和 WebSocket 什么关系?
浏览器里面访问guacamole,然后连接到服务器,这就是一个实时双向通信的过程,请求和响应数据流如下:
鼠标移动
↓
浏览器
↓
Guacamole
↓
guacd
↓
目标服务器
Linux桌面或者终端变化
↓
guacd
↓
Guacamole
↓
浏览器显示
所以 Guacamole 需要一种方式,让浏览器和 Guacamole 服务器一直保持连接,这个就是WebSocket
Guacamole 的通信结构,浏览器直接通过guacamole的端口请求,这一段通常使用WebSocket,如下:
浏览器
|
|
| WebSocket
|
↓
Guacamole Web
|
|
| Guacamole Protocol
|
↓
guacd
|
|
↓
Linux SSH
Windows RDP
如果不使用websocket,那么浏览器就要不断给guacamole发送请求,等返回,再发请求,虽然可以工作,但是效率很低,会导致卡顿、键盘延迟、资源损耗增加,这就是为什么Nginx不配置Websocket upgrade出现的情况,如果Nginx不配置websocket upgrade,请求如下:
浏览器
|
| WebSocket
↓
Nginx
|
| ???
↓
Guacamole
浏览器说:我要WebSocket
Nginx转给Guacamole:普通HTTP请求
Guacamole: 好的,那我用HTTP tunnel吧,虽然能用,但是很卡
测试:先看下直接通过浏览器请求guacamole页面,F12可以看到目前使用的是websocket,如下:

如果Nginx代理guacamole,没有配置websocket upgrade,再次请求,可以看到如图:

说明:浏览器确实在尝试建立 WebSocket,但是Nginx没有配置支持websocket,因此WebSocket 握手没有完成,服务器没有返回标准的 101 Switching Protocols 响应,此时guacamole会走普通的http tunnel,就会导致页面很卡,因此nginx配置中一定要配置websocket upgrade,同时配置
proxy_http_version 1.1;
因为 WebSocket 的握手需要 HTTP/1.1 的 Upgrade 机制,而 Nginx 默认代理后端使用 HTTP/1.0,所以必须指定 proxy_http_version 1.1
备注:
guacamole-guacd默认是apline镜像打包的,默认情况下进入容器中是普通用户,执行命令没权限,如果要用root用户进入,可执行如下命令:
docker exec -it --user root guacamole-guacd /bin/sh


