# What is Apache Guacamole and how does it work?
[TOC]
## 什麼是 Guacamole?
最高戰略目標 : 可以讓使用者從任何地方遠端存取一台或多台桌面,而且不需要事先在使用者的設備中安裝任何插件,甚至手機或平板電腦也可以使用,只需要有網站瀏覽器,並且可以透過網路連到 Guacamole Server 就可以了,有支援 VNC, RDP, SSH ...等。
## Guacamole 架構與核心運作
Guacamole 並非一個獨立的 Web 應用,它由許多部分組成。

1. **使用者以瀏覽器連線 Guacamole 伺服器:** 使用者在瀏覽器中進入 Guacamole 伺服器的網址(通常是 Web 介面),與 Guacamole 伺服器建立起一個 HTTP/HTTPS 連線,準備開始遠端桌面會話。
2. **Guacamole 伺服器傳送 Guacamole Client:** Guacamole 伺服器內建的 Web 伺服器會將前端的 **Guacamole 客戶端**(以 JavaScript 撰寫)傳送到使用者的瀏覽器上。這個 JavaScript 應用程式就是使用者在瀏覽器中操作的介面。
3. **建立 Guacamole 通訊協定的通道:** 當瀏覽器端的 JavaScript 客戶端載入完成後,它會透過 HTTP 或 WebSocket 與 Guacamole 伺服器建立持續連線,並使用 **Guacamole 通訊協定**來通信。Guacamole 通訊協定是一種由 Guacamole 定義的通訊協定,用於在瀏覽器客戶端和伺服器之間傳輸遠端桌面的畫面更新和使用者輸入等事件資料。
4. **Web 應用轉發請求給 guacd:** Guacamole 伺服器上的 Web 應用程式收到來自瀏覽器端的 Guacamole 通訊協定數據後,並不直接解讀為特定遠端桌面的指令,而是將這些協定訊息轉發給後端的 **guacd**(Guacamole 的原生代理服務)。可以理解為 Web 應用程式建立了一個**通道**,將瀏覽器客戶端的請求交給 guacd 去處理。
5. **guacd 依協定連接遠端桌面:** guacd 收到從 Web 應用轉來的指令後,會解析其中包含的連線參數,根據使用者請求的協定類型,替使用者與實際的遠端桌面伺服器建立連線。例如,如果使用者要連的是 Windows 主機桌面,guacd 就會使用 **RDP 協定**跟該主機溝通;若是 Linux 主機且啟用 VNC,guacd 就改用 **VNC 協定**連線,或者透過 **SSH** 建立遠端終端會話。**guacd** 負責所有與遠端伺服器之間的底層通訊,將使用者的操作轉換成遠端桌面協定所需的訊息發送出去,並接收遠端主機回傳的畫面更新。
6. **遠端畫面與操作結果回傳:** 當 guacd 與遠端桌面伺服器建立好連線後,遠端桌面的**畫面影像**資料會即時地透過 **Guacamole 通訊協定**傳輸回 Guacamole 伺服器的 Web 應用程式。同時,使用者在瀏覽器中對遠端桌面的任何操作(例如按鍵、滑鼠點擊等),也會經由這條通道送達 guacd,再轉發給遠端主機執行。最終,遠端桌面的畫面更新和回應結果又經由 **guacd → Guacamole 伺服器的 Web → 瀏覽器客戶端**的路徑傳回,瀏覽器上的 Guacamole JavaScript 客戶端會將其呈現在使用者面前,讓使用者宛如直接操作該遠端主機一般。
# 快速動手實作
## 使用 Podman Container 安裝 Guacamole
Guacamole 被使用 Podman 部署時,被分成 3 個 Containers,分別是
- `guacamole/guacd`
Provides the guacd daemon, built from the released guacamole-server source with support for VNC, RDP, SSH, telnet, and Kubernetes.
- `guacamole/guacamole`
Provides the Guacamole web application running within Tomcat 8 with support for WebSocket. The configuration necessary to connect to guacd, MySQL, PostgreSQL, LDAP, etc. will be generated automatically when the image starts based on Docker links or environment variables.
- `mysql` or `postgresql`
Provides the database that Guacamole will use for authentication and storage of connection configuration data.
```
# 1. 啟動 guacd app container(Guacamole 代理服務,負責 RDP/VNC/SSH 轉譯)
## 注意設定 GUACD_LOG_LEVEL 為 debug 有助除錯
$ sudo podman run --name guacd \
-p 4822:4822 \
-e GUACD_LOG_LEVEL=debug \
-d \
guacamole/guacd
# 2. 確認 guacd 是否啟動成功
$ sudo podman ps --filter name=guacd
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2386e584dff2 docker.io/guacamole/guacd:latest 37 seconds ago Up 38 seconds (starting) 0.0.0.0:4822->4822/tcp guacd
# 3. 產生初始化 MySQL 的 SQL 腳本,內容會有建立 Guacamole 所需的資料表結構
$ sudo podman run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql
# 4. 注意事項,跑完以上初始化的腳本,還需要對全新的 mysql 做以下設定
- 在 MySQL 中為 Guacamole 建立一個資料庫,例如 guacamole_db。
- 在 MySQL 中為 Guacamole 建立一個擁有該資料庫存取權限的用戶,例如 guacamole_user。
- 在新建立的資料庫上執行該腳本。
# 5. 設定腳本在 guacamole database 上執行
$ sed -i '1iUSE guacamole;' initdb.sql
# 6. # 啟動 MySQL app container 並掛載初始化腳本
# - MYSQL_ROOT_PASSWORD:root 密碼,切勿用預設值於正式環境
# - 透過環境變數來讓 mysql container 一跑起來就有這些設定 :
# - MYSQL_DATABASE、MYSQL_USER、MYSQL_PASSWORD:
$ sudo podman run --name mysql\
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_HOSTNAME=192.168.11.33 \
-e MYSQL_DATABASE=guacamole \
-e MYSQL_USER=guacamole \
-e MYSQL_PASSWORD=guacamole \
-e TZ=Asia/Taipei \
-v $(pwd)/initdb.sql:/docker-entrypoint-initdb.d/initdb.sql:ro \
-d \
-p 3306:3306 \
mysql
# 7. 確認 mysql 有正常運作
$ sudo podman ps --filter name=mysql
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e6639bc2fa37 docker.io/library/mysql:latest mysqld 32 minutes ago Up 32 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp mysql
# 8. 啟動 Guacamole app container
# 一定要設定 MYSQL 和 guacd 的連接資訊
$ sudo podman run --name guacamole \
-e GUACD_HOSTNAME=192.168.11.33 \
-e GUACD_PORT=4822 \
-e MYSQL_HOSTNAME=192.168.11.33 \
-e MYSQL_DATABASE=guacamole \
-e MYSQL_USER=guacamole \
-e MYSQL_PASSWORD=guacamole \
-d \
-p 8080:8080 \
guacamole/guacamole
# 確認 Guacamole 有正常運作
$ sudo podman ps --filter name=guacamole
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c8f49541c411 docker.io/guacamole/guacamole:latest /opt/guacamole/bi... 21 seconds ago Up 21 seconds 0.0.0.0:8080->8080/tcp guacamole
```
## 連線到 Web UI
```
http://<ip>:8080/guacamole
```
帳密都是 : `guacadmin`

## 參考文件
- [Implementation and architecture - Apache Guacamole Docs](https://guacamole.apache.org/doc/gug/guacamole-architecture.html)
- [Installing Guacamole with Docker - Apache Guacamole Docs ](https://guacamole.apache.org/doc/gug/guacamole-docker.html)