この記事は2022年7月時点の検証メモです。Docker Compose の version 指定は現在非推奨となっており、イメージタグも当時のlatestを使用しています。構成の考え方は変わりませんが、本番導入時はイメージタグの固定と最新ドキュメントの確認をお勧めします。
リモートワーク環境で社内サーバーへのアクセス手段を検討していたとき、Apache Guacamole を試しました。ブラウザだけでSSH・RDP・VNCに接続できるオープンソースのリモートアクセスゲートウェイです。この記事では、Docker Compose を使ってローカルにさくっと起動するための最小構成と、いくつかの便利な機能を紹介しています。
Guacamole は VNC、RDP、SSH、そして独自拡張・・・というように多数のプロトコルに対応可能なソフトウェアですが、本記事ではまずお試し操作してみたいのでローカルでさっさと起動したいという目的に対して Docker Compose のコンフィグを記載しています。その他、いくつかの機能紹介をしていますがごく一部になります。
完成形(テスト起動目的の Docker Compose)
テスト起動のため、MySQLのrootパスワードを root に設定しています。Guacamoleの管理画面ログインは初期ID guacadmin / PW guacadmin です。Production環境では必ず変更してください。
version: '3'
# NOTE: Compose V2 では version 指定は不要ですが、当時の記法をそのまま残しています
services:
guacd:
image: guacamole/guacd
ports:
- 4822:4822
volumes:
- ./data/record/:/mnt/record
guacamole:
image: guacamole/guacamole
ports:
- 8080:8080
depends_on:
guacd:
condition: service_started
mysql:
condition: service_healthy
environment:
MYSQL_DATABASE: guacamole_db
MYSQL_USER: root
MYSQL_PASSWORD: root
GUACD_HOSTNAME: guacd
MYSQL_HOSTNAME: mysql
mysql:
image: mysql
ports:
- 3306:3306
volumes:
- ./data/mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
healthcheck:
test: "mysql -h127.0.0.1 -P3306 -uroot -proot -e 'quit'"
interval: 10s
timeout: 10s
retries: 3
start_period: 10s
## MySQL管理画面を使いたければコメントアウト
# adminer:
# image: adminer
# restart: always
# ports:
# - 8888:8080
解説は後述します。
Apache Guacamole とは
オフィシャルの言葉を引用すると、定番プロトコル( VNC, RDP, SSH等)に対応しているクライアント不要のリモートアクセスゲートウェイとなります。ブラウザの画面そのものがデスクトップかのような操作感で、ストレスなく非常に快適です。
Apache Guacamole is a clientless remote desktop gateway. It supports standard protocols like VNC, RDP, and SSH.
テスト環境起動構成
利用イメージ (Docker Image)
以下3種類の Docker Imageを利用します。アーキテクチャと照らし合わせながら参照すると分かりやすいです。
- https://hub.docker.com/r/guacamole/guacamole
- Guacamole: Webサーバー。人間が主にアクセスするインタフェースとなる部分
- https://hub.docker.com/r/guacamole/guacd
- guacd: 実際に接続先に対してアクセスするためのゲートウェイとなる心臓部
- https://hub.docker.com/_/mysql
- データを保存するRDB。Postgresでも構築可能。

図の引用:Implementation and architecture — Apache Guacamole Manual v1.4.0
セットアップ
記事の冒頭に記したコンフィグ docker-compose.yaml を用意してある前提で以下の通り起動します。
# MySQLデータベースを作成するためのスキーマ定義を準備する操作。
# initdb.sql として書き出されていることを確認する。
docker pull guacamole/guacamole
docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql
# データベースを作成するために MySQL を起動。ついでに guacd も起動しておく。
docker-compose up -d guacd mysql
# データベースをインポートする。MySQLのユーザーとパスワードは適宜書き換えること。
mysql -uroot -proot -h127.0.0.1 -P3306 guacamole_db < initdb.sql
# Guacamole Webサーバーを起動する
docker-compose up guacamole
起動
エラー無く起動しているようであれば、最後に http://localhost:8080/guacamole/ へのアクセスでログイン画面が表示されます。

初期ID・PWは以下の通りでログイン可能。
- ID:
guacadmin - PW:
guacadmin
設定の解説
guacd
guacd:
image: guacamole/guacd
ports:
- 4822:4822
volumes:
- ./data/record/:/mnt/record
./data/record/:/mnt/record は、操作のレコーディングをしたい場合に、書き出されたファイルを永続化しておく必要があるのでマウントしています。レコーディング機能が不要ならば、volume を記載する必要はありません。
guacamole:
image: guacamole/guacamole
ports:
- 8080:8080
depends_on:
guacd:
condition: service_started
mysql:
condition: service_healthy
environment:
MYSQL_DATABASE: guacamole_db
MYSQL_USER: root
MYSQL_PASSWORD: root
GUACD_HOSTNAME: guacd
MYSQL_HOSTNAME: mysql
depends_on では、依存対象の guacd と mysql が起動していることを確認するように condition を設定しています。
MYSQL_ から始まるデータベース関連設定は適宜変更してください。
_HOSTNAME は、Guacamole Web サーバーから見たときの guacd や MySQLサーバーへアクセスするためのホスト名です。ここでは同一 Docker Compose 構成内で動いているので、サービス名を書いています。
Docker Compose の link 構文でも動かすことはできますが、今となっては古い記載になっています。
Links are a legacy option. We recommend using networks
instead.
mysql:
image: mysql
ports:
- 3306:3306
volumes:
- ./data/mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
healthcheck:
test: "mysql -h127.0.0.1 -P3306 -uroot -proot -e 'quit'"
interval: 10s
timeout: 10s
retries: 3
start_period: 10s
パスワードが root の非常に良くない例ですので、Production 環境ではもちろん、適切なパスワードを設定してください。
MySQL起動までに時間がかかるのでヘルスチェックを設定しましたが、消しても問題ありません。
Guacamole を使ってみる
ログインしたので、実際にどこかのホストへ接続してみましょう。この例では、AWSのEC2インスタンスへ接続することとします。接続する先のマシンがないと、ここで何もできなくて終了です。

接続の追加をクリック。
そして、以下の通り情報を記入。入力欄が多数ありますが、SSHしてみるだけであれば入力欄は少ないです。

- プロトコルはSSHを選択
- ネットワーク
- ホスト名:対象のIPアドレス等
- ポート:対象によるが一般的には 22
- 認証
- AWSなので ec2-user
- 秘密鍵は、***.pem 等のRSA鍵をベタっと貼り付けます
設定完了後、ホームに戻ると「すべての接続情報」に表示されるので、クリックすると接続できるはずです。

機能紹介
画面共有
現在の操作画面を、URLで誰かに共有することができます。サーバーオペレーションのダブルチェックやペアプログラミングで便利そうですね。
Guacamole では、以下のコマンドを押すとブラウザ内にメニューを表示することができます。
- Macの場合
⌘(Command) + Ctrl + Shift - Windowsの場合
Alt + Ctrl + Shift
このメニュー内に「共有」が出てくるはずなのですが、見当たりません・・・。追加で共有設定が必要なようです。

先程の設定画面に戻ると、「共有プロファイルの追加」という文字が見えます。

ここで共有プロファイルを作成します。読み取り専用にしたい場合はチェック。

プロファイルが作成されました。

そして、リモートアクセス中の画面に戻って改めてメニューを表示すると、先ほど作成したプロファイルが表示されます。

「Read Profile」をクリックすると共有URLが発行されました。

共有URLを開いてみます。
以下の画面は、左側はメインの操作画面、そして右側は共有URLで Read Only で参照中の画面を並べています。今回は同じホスト内で試しているので期待通りではありますが、タイムラグが全くありませんでした。便利ですね。

振る舞いを少々補足:
- プロファイルボタンをクリックするとURLが都度再生性されますが、古いURLが即座に無効となるわけではありません。プロファイルの共有URLを変更しても古いURLを用いてアクセスできました。
- メインのターミナル操作を明確に切断(exit)したら画面はちゃんと切られ、URLも無効になりました。
- 共有URLでアクセスした人は、アクセス履歴には匿名として記録されていました。
画面切断の図

履歴には匿名として表示される図

操作のレコーディング
guacd コンテナでレコーディングのために volume をマウントしていましたが、SSHの操作内容をテキストで保存することができます。
なお、RDPの場合は当然テキストでは保存できませんが、画面のレコーディング(動画)として保存できます。こちらは、試していないので細部不明です。
/mnt/record を volume マウントしていますので、この配下を保存ディレクトリとします。例えば以下の通り設定した場合:

結果、操作ログは以下のようにテキストで保存できました。

前述のテスト(上の画像)では以下の通り設定しています。
- 設定値
${GUAC_DATE}-${GUAC_TIME}_${GUAC_USERNAME}.log - 得られた値
20220722-160643_guacadmin.log
変数について
一部しか試していませんが、マニュアルによると以下のパラメタが利用できるとのこと。これらを使えば、ある程度は整理がつきそうでしょうか。
${GUAC_USERNAME}
The username of the current Guacamole user. When a user accesses a connection, this token will be dynamically replaced with the username they provided when logging in to Guacamole.
${GUAC_PASSWORD}
The password of the current Guacamole user. When a user accesses a connection, this token will be dynamically replaced with the password they used when logging in to Guacamole.
${GUAC_CLIENT_ADDRESS}
The IPv4 or IPv6 address of the current Guacamole user. This will be the address of the client side of the HTTP connection to the Guacamole server at the time the current user logged in.
${GUAC_CLIENT_HOSTNAME}
The hostname of the current Guacamole user. This will be the hostname of the client side of the HTTP connection to the Guacamole server at the time the current user logged in. If no such hostname can be determined, the IPv4 or IPv6 address will be used instead, and this token will be equivalent to ${GUAC_CLIENT_ADDRESS}.
${GUAC_DATE}
The current date in the local time zone of the Guacamole server. This will be written in “YYYYMMDD” format, where “YYYY” is the year, “MM” is the month number, and “DD” is the day of the month, all zero-padded. When a user accesses a connection, this token will be dynamically replaced with the date that the connection began.
${GUAC_TIME}
The current time in the local time zone of the Guacamole server. This will be written in “HHMMSS” format, where “HH” is hours in 24-hour time, “MM” is minutes, and “SS” is seconds, all zero-padded. When a user accesses a connection, this token will be dynamically replaced with the time that the connection began.
参照: https://guacamole.apache.org/doc/gug/configuring-guacamole.html#parameter-tokens
その他興味深い機能
ここからは、実際に使ってみて気になった機能をいくつか紹介します。
RemoteApp
Recent versions of Windows provide a feature called RemoteApp which allows individual applications to be used over RDP, without providing access to the full desktop environment. If your RDP server has this feature enabled and configured, you can configure Guacamole connections to use those individual applications.
RDPのようにマシンの画面全体を操作するのではなく、アプリ部分のみを画面転送してくれるようです。上手に活用すれば、特定の人に一部アプリケーションのみを安全に・効率的に提供できるかもしれません。試してみたいところ。
Kubernetes
Kubernetes provides an API for attaching to the console of a container over the network. As with SSH and telnet, Guacamole’s Kubernetes support emulates a terminal on the server side which renders to the Guacamole client’s display.
Kubernetes への接続とあるので興味深いと思ったのですが、設定画面を見る限りだと Pod 名を都度指定して設定を作らなければならないようで、生成・破棄のサイクルが早い Kubernetes においては、この設定インタフェースは面倒くさいな・・・という印象で、試すのを諦めました。

まとめ
テスト用構成ではありますが、さくっと Guacamole を起動してリモートサーバーへSSH接続するまでを一瞬で構築することができました。上手に運用設計をすれば、安全なリモートアクセス環境として Production レベルでも実用的に使えます。
ブラウザだけで出来ることがどんどん増えて、とても便利ですね。


