开源远程桌面网关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

标签