Apache Guacamole: установка, настройка и подключение SSH, RDP, VNC через браузер
Ты сейчас держишь в голове пять разных клиентов. PuTTY для SSH, mstsc для RDP, какой-нибудь TigerVNC для VNC, отдельный SSH-туннель для Kubernetes и ещё что-то для экзотики. Каждый раз когда подключаешься с нового устройства — ставишь всё заново. Каждый раз когда надо дать доступ коллеге — объясняешь по телефону как настроить клиент.
Guacamole закрывает эту боль. Один раз поднял шлюз — и больше не думаешь о клиентах.
В этой статье разберём: что внутри, как поднять через Docker Compose за 15 минут, как добавить подключения SSH/RDP/VNC, как это защитить и что делать когда сломается. Без воды.
Что нужно перед стартом
| Компонент | Минимум | Рекомендовано |
|---|---|---|
| ОС | Ubuntu 20.04 LTS | Ubuntu 22.04 LTS / Debian 12 |
| RAM | 2 GB | 4 GB |
| CPU | 1 ядро | 2 ядра |
| Диск | 10 GB | 20 GB |
| Docker | 20.10+ | 24.x+ |
| Docker Compose | v2.0+ | v2.20+ |
| Apache Guacamole | 1.5.x | 1.5.5 (актуальна на момент публикации) |
| PostgreSQL | 13 | 15 |
Перед установкой проверь свежие релизы на hub.docker.com/r/guacamole/guacamole — версии обновляются.
Доступы которые нужны: root или sudo на сервере, открытый порт 8080 (или любой другой который выберешь для шлюза).
Архитектура: как это вообще работает
Прежде чем копировать команды — разберись с архитектурой. Иначе потом не поймёшь почему что-то не работает.
Guacamole состоит из двух частей:
guacd — демон на C. Это движок. Он принимает соединения от веб-приложения и транслирует их в нативные протоколы: RDP, SSH, VNC, Telnet. Никакой логики, никакого UI — только транспорт.
guacamole-client — Java-приложение в Tomcat. Это веб-интерфейс. Он аутентифицирует пользователей, хранит конфиги подключений в базе и общается с guacd по протоколу Guacamole.
Поток данных выглядит так:
Ключевой момент: снаружи открыт только порт 8080 (или 443 после настройки Nginx). SSH, RDP и VNC порты целевых серверов наружу не торчат — к ним ходит guacd изнутри сети. Это и есть главный плюс с точки зрения безопасности.
Таблица портов
| Сервис | Порт | Направление | Описание |
|---|---|---|---|
| guacamole-client | 8080/tcp | входящий (от пользователей) | Веб-интерфейс, перекрывается Nginx на 443 |
| guacd | 4822/tcp | внутренний (client → guacd) | Только между контейнерами, наружу не открывать |
| PostgreSQL | 5432/tcp | внутренний (client → db) | Только между контейнерами |
| SSH цели | 22/tcp | исходящий (guacd → цель) | guacd подключается к целевым серверам |
| RDP цели | 3389/tcp | исходящий (guacd → цель) | guacd подключается к целевым Windows |
| VNC цели | 5900/tcp | исходящий (guacd → цель) | guacd подключается к VNC-серверам |
Установка Apache Guacamole через Docker Compose
Буду честен: есть два пути — собирать из исходников и Docker. Из исходников — это зависимости, libfreerdp, libssl, patching, и два часа жизни которые ты не вернёшь. Docker — это 15 минут и рабочий шлюз. Выбор очевиден.
Шаг 1: Создай структуру проекта
mkdir -p ~/guacamole/init && cd ~/guacamole
Шаг 2: Сгенерируй SQL-схему для PostgreSQL
Guacamole не создаёт таблицы сам при первом запуске. Нужно запустить образ с флагом генерации схемы и сохранить SQL-файл.
docker run --rm guacamole/guacamole:1.5.5 /opt/guacamole/bin/initdb.sh --postgresql > ~/guacamole/init/initdb.sql
Проверь что файл не пустой:
wc -l ~/guacamole/init/initdb.sql
# Должно быть несколько сотен строк
Шаг 3: Создай docker-compose.yml
version: '3.9'
services:
guacd:
image: guacamole/guacd:1.5.5
container_name: guacd
restart: unless-stopped
networks:
- guacamole_net
postgres:
image: postgres:15-alpine
container_name: guacamole-postgres
restart: unless-stopped
environment:
POSTGRES_DB: guacamole_db
POSTGRES_USER: guacamole_user
POSTGRES_PASSWORD: ВАШ_СЛОЖНЫЙ_ПАРОЛЬ
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init:/docker-entrypoint-initdb.d:ro
networks:
- guacamole_net
guacamole:
image: guacamole/guacamole:1.5.5
container_name: guacamole-web
restart: unless-stopped
depends_on:
- guacd
- postgres
ports:
- "8080:8080"
environment:
GUACD_HOSTNAME: guacd
GUACD_PORT: 4822
POSTGRES_HOSTNAME: postgres
POSTGRES_PORT: 5432
POSTGRES_DATABASE: guacamole_db
POSTGRES_USER: guacamole_user
POSTGRES_PASSWORD: ВАШ_СЛОЖНЫЙ_ПАРОЛЬ
volumes:
- drive:/drive:rw
networks:
- guacamole_net
networks:
guacamole_net:
driver: bridge
volumes:
postgres_data:
drive:
Обрати внимание: папка ./init монтируется в /docker-entrypoint-initdb.d. PostgreSQL автоматически выполнит все .sql файлы из этой папки при первом старте. Вот зачем мы генерировали схему на шаге 2.
Шаг 4: Запусти
cd ~/guacamole
docker compose up -d
Шаг 5: Проверь что всё поднялось
docker compose ps
Результат должен быть такой:
NAME STATUS PORTS
guacd Up 4822/tcp
guacamole-postgres Up 5432/tcp
guacamole-web Up 0.0.0.0:8080->8080/tcp
Если какой-то контейнер в состоянии Exited — смотри логи:
docker compose logs guacamole
docker compose logs postgres
Шаг 6: Первый вход и смена пароля
Открой в браузере: http://IP_СЕРВЕРА:8080/guacamole
Логин: guacadmin, пароль: guacadmin
Настройка подключений
SSH-подключение к Linux-серверу
Иди в Settings — Connections — New Connection.
| Поле | Значение |
|---|---|
| Name | Любое понятное имя |
| Protocol | SSH |
| Hostname | IP или DNS имя сервера |
| Port | 22 |
| Username | Пользователь на сервере |
| Password | Пароль (или оставь пустым если используешь ключ) |
| Private Key | Вставь содержимое ~/.ssh/id_rsa если используешь ключ |
Если используешь ключ — поле Password оставь пустым, иначе Guacamole попробует пароль и ключ проигнорирует.
Сохрани. Теперь на главной странице появится иконка подключения. Кликай — откроется терминал прямо в браузере.
RDP-подключение к Windows
| Поле | Значение |
|---|---|
| Protocol | RDP |
| Hostname | IP Windows-машины |
| Port | 3389 |
| Username | Пользователь (с доменом: DOMAIN\user) |
| Password | Пароль |
| Security mode | NLA — если сервер поддерживает; Any — если не уверен |
| Ignore server certificate | Включи если самоподписанный сертификат |
Вот тут важно: если подключаешься к Windows Server и видишь ошибку аутентификации — сначала проверь что на целевой машине включён Remote Desktop и пользователь добавлен в группу «Remote Desktop Users». Это не Guacamole виноват.
VNC-подключение
| Поле | Значение |
|---|---|
| Protocol | VNC |
| Hostname | IP машины с VNC-сервером |
| Port | 5900 (или 5901, 5902 — зависит от дисплея) |
| Password | VNC-пароль |
Подключение к Pod в Kubernetes
Хитрый случай. Прямого коннектора к Kubernetes у Guacamole нет — но есть обходной путь через SSH с начальной командой.
Настрой SSH-подключение к бастион-хосту или ноде кластера где есть kubeconfig. В поле Initial command на вкладке Terminal вставь:
kubectl exec -it ИМЯ_ПОДА -n NAMESPACE -- /bin/bash
При подключении по этому соединению сразу попадёшь в оболочку пода. Удобно для дежурных сценариев когда надо быстро зайти без терминала.
Видео по теме
Групповые соединения и балансировка
Если у тебя несколько однотипных серверов — Guacamole умеет группировать их с балансировкой нагрузки.
Иди в Settings — Connection Groups — New Group.
| Параметр | Значение | Когда использовать |
|---|---|---|
| Type: ORGANIZATIONAL | Просто папка для группировки | Логическая структура без балансировки |
| Type: BALANCING | Балансировка по загрузке | Терминальные фермы, кластеры |
При типе BALANCING Guacamole будет отправлять нового пользователя на наименее нагруженное соединение в группе. Для терминальных ферм или кластеров из нескольких идентичных серверов — удобно.
HTTPS через Nginx: без этого в продакшн не идём
Guacamole на порту 8080 без TLS — это не продакшн. Ставим Nginx как reverse proxy.
Установка Nginx и Certbot
apt update && apt install -y nginx certbot python3-certbot-nginx
Конфиг Nginx для Guacamole
server {
listen 80;
server_name guacamole.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name guacamole.example.com;
ssl_certificate /etc/letsencrypt/live/guacamole.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/guacamole.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:8080/guacamole/;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 3600;
proxy_send_timeout 3600;
}
}
Обрати внимание на proxy_read_timeout 3600. Это критично для SSH/RDP сессий — без этого Nginx будет рвать долгие соединения через стандартные 60 секунд.
Получи сертификат
certbot --nginx -d guacamole.example.com
Перезапусти Nginx
nginx -t && systemctl reload nginx
Безопасность
UFW: закрой всё лишнее
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
# Порт 8080 оставляем закрытым снаружи - к нему ходит только Nginx изнутри
ufw enable
ufw status
Fail2ban для Guacamole
Guacamole пишет неудачные попытки входа в лог Tomcat. Настроим fail2ban на этот лог.
apt install -y fail2ban
Создай файл /etc/fail2ban/filter.d/guacamole.conf:
[Definition]
failregex = o.a.g.r.auth.AuthenticationService - Authentication attempt from for user .* failed
ignoreregex =
Создай /etc/fail2ban/jail.d/guacamole.conf:
[guacamole]
enabled = true
port = 80,443
filter = guacamole
logpath = /var/lib/docker/containers/*/*.log
maxretry = 5
bantime = 3600
findtime = 600
systemctl restart fail2ban
fail2ban-client status guacamole
Отдельный пользователь для каждой группы людей
Не давай guacadmin всем. Создай отдельных пользователей в Settings — Users и назначь им права только на нужные подключения. Принцип минимальных привилегий работает и здесь.
Двухфакторная аутентификация
Guacamole поддерживает TOTP через расширение. Скачай guacamole-auth-totp-1.5.5.jar с официального сайта и положи в:
# Создай папку для расширений и смонтируй её в контейнер
mkdir -p ~/guacamole/extensions
# Скачай расширение
wget -O ~/guacamole/extensions/guacamole-auth-totp-1.5.5.jar \
https://downloads.apache.org/guacamole/1.5.5/binary/guacamole-auth-totp-1.5.5.jar
Добавь в docker-compose.yml в секцию volumes контейнера guacamole:
- ./extensions:/etc/guacamole/extensions:ro
Перезапусти контейнер — при следующем входе пользователю предложат настроить TOTP.
Резервное копирование
Что бэкапить: базу PostgreSQL с конфигами подключений и пользователями, папку extensions если используешь расширения.
Бэкап базы
#!/bin/bash
BACKUP_DIR=/opt/backups/guacamole
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
docker exec guacamole-postgres pg_dump \
-U guacamole_user guacamole_db \
> $BACKUP_DIR/guacamole_db_$DATE.sql
# Удаляй бэкапы старше 30 дней
find $BACKUP_DIR -name "*.sql" -mtime +30 -delete
echo "Backup done: $BACKUP_DIR/guacamole_db_$DATE.sql"
Добавь в cron:
crontab -e
# Добавь строку:
0 3 * * * /opt/scripts/backup_guacamole.sh >> /var/log/guacamole_backup.log 2>&1
Восстановление из бэкапа
# Останови контейнеры
docker compose down
# Пересоздай том базы (удалит текущие данные)
docker volume rm guacamole_postgres_data
# Запусти только postgres
docker compose up -d postgres
# Восстанови из дампа
cat /opt/backups/guacamole/guacamole_db_ДАТА.sql | \
docker exec -i guacamole-postgres psql -U guacamole_user guacamole_db
# Запусти остальные сервисы
docker compose up -d
Обновление Guacamole
Обновляй через смену тега образа в docker-compose.yml.
# Сделай бэкап базы ПЕРЕД обновлением
/opt/scripts/backup_guacamole.sh
# Измени версию в docker-compose.yml
# guacamole/guacamole:1.5.5 -> guacamole/guacamole:НОВАЯ_ВЕРСИЯ
# guacamole/guacd:1.5.5 -> guacamole/guacd:НОВАЯ_ВЕРСИЯ
# Подтяни новые образы и перезапусти
docker compose pull
docker compose up -d
Проверка работоспособности
# Статус контейнеров
docker compose ps
# Логи в реальном времени
docker compose logs -f guacamole
# Доступность веб-интерфейса
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/guacamole/
# Должен вернуть 200 или 302
# Проверка что guacd слушает
docker exec guacd netstat -tlnp | grep 4822
# Проверка подключения к базе изнутри контейнера guacamole
docker exec guacamole-web env | grep POSTGRES
Troubleshooting
Белый экран или 404 после открытия браузера
Причина: приложение ещё не запустилось. Tomcat стартует медленно.
Решение: подожди 30-60 секунд и обнови страницу. Если не помогает — смотри логи:
docker compose logs guacamole | tail -50
Ошибка «Cannot connect to guacd»
Причина: контейнер guacd не запустился или guacamole обращается по неправильному адресу.
Решение:
# Проверь что guacd работает
docker compose ps guacd
# Проверь что переменная GUACD_HOSTNAME совпадает с именем сервиса в compose
docker exec guacamole-web env | grep GUACD
# Должно быть GUACD_HOSTNAME=guacd
# Проверь сетевую связность между контейнерами
docker exec guacamole-web ping -c 3 guacd
Ошибка инициализации PostgreSQL: «relation does not exist»
Причина: SQL-схема не была применена при первом старте. Это бывает если том postgres_data уже существовал до монтирования init-папки.
Решение:
# Останови всё
docker compose down
# Удали том с данными (данные потеряются - это свежая установка)
docker volume rm guacamole_postgres_data
# Убедись что initdb.sql лежит в ./init/
ls -la ~/guacamole/init/initdb.sql
# Запусти снова
docker compose up -d
RDP подключение зависает или отваливается через несколько минут
Причина: таймаут proxy_read_timeout в Nginx.
Решение: убедись что в конфиге Nginx стоит proxy_read_timeout 3600 и proxy_send_timeout 3600.
SSH работает, но нет поддержки UTF-8 / кириллица не отображается
Причина: не настроена кодировка в параметрах подключения.
Решение: в настройках SSH-соединения на вкладке Terminal укажи:
— Terminal type: xterm-256color
— Font name: monospace
Не работает буфер обмена между браузером и сессией
Это фича браузеров, не баг Guacamole. Нажми Ctrl+Alt+Shift внутри сессии — откроется боковая панель Guacamole с буфером обмена. Вставляй текст туда, и он появится в сессии.
Альтернативы Apache Guacamole
| Решение | Плюсы | Минусы | Когда выбрать |
|---|---|---|---|
| Apache Guacamole | Open source, активная разработка, много протоколов | Java в стеке, требует отдельного guacd | Универсальный шлюз для смешанной среды |
| Teleport | Встроенный аудит, certificate-based auth, Kubernetes | Сложнее в настройке, бесплатно только Community | Когда нужен детальный аудит и compliance |
| MeshCentral | Бесплатно, агентский доступ, встроенный relay | Нужен агент на целевых машинах | Когда нужно управлять конечными устройствами |
| RustDesk Server | Простота, P2P, открытый код | В основном для десктопов, слабее для серверов | Поддержка пользователей, не серверная инфра |
Guacamole выигрывает когда нужен централизованный шлюз без агентов на целевых серверах и с поддержкой смешанного парка: Linux по SSH, Windows по RDP, виртуалки по VNC.
Профилактика: как не сломать снова
- Поставь мониторинг на доступность
http://localhost:8080/guacamole/— например через Uptime Kuma или простой curl в cron - Настрой автообновление сертификата: certbot сам добавляет таймер в systemd, проверь
systemctl list-timers | grep certbot - Не храни пароли к подключениям в открытом виде — используй отдельного пользователя с минимальными правами для каждого критичного подключения
- Логируй сессии: Guacamole умеет записывать RDP и SSH сессии в файлы. Включи через параметр Recording path в настройках соединения
FAQ
Почему Guacamole не видит новое SSH-подключение сразу после создания?
Видит. Просто иногда нужно обновить страницу. Кэширование на стороне браузера. Если соединение не появляется и после обновления — проверь что пользователь имеет права на это подключение в Settings — Connections — Permission.
Как проверить что guacd реально подключается к целевому серверу?
# Смотри логи guacd во время попытки подключения
docker compose logs -f guacd
# В момент когда кликаешь на соединение в браузере - увидишь строки типа:
# guacd[1]: INFO: Connection ID is "..."
# guacd[1]: INFO: Creating new client for protocol "ssh"
Если в логах пусто в момент клика — проблема между guacamole-client и guacd, не между guacd и целью.
Что если нужно дать временный доступ подрядчику?
Создай отдельного пользователя, дай права только на нужные соединения, после окончания работ — удали пользователя. Не давай guacadmin никому. Это стандартная практика.
Как записывать RDP и SSH сессии для аудита?
В настройках подключения найди раздел Screen Recording (для RDP) или Typescript recording (для SSH). Укажи путь к директории. Для Docker это должна быть директория внутри контейнера с примонтированным томом:
Recording path: /record
Recording name: ${GUAC_DATE}_${GUAC_TIME}_${GUAC_USERNAME}
Добавь том в docker-compose.yml:
volumes:
- /opt/guacamole/recordings:/record:rw
Итог
Поднял Guacamole — закрыл несколько задач одновременно: централизованный доступ, аудит сессий, минимальная поверхность атаки снаружи. Больше не нужно объяснять коллеге как настроить PuTTY. Больше не нужно открывать RDP наружу.
Архитектура простая: guacd транслирует протоколы, клиент на Tomcat отдаёт веб-интерфейс, PostgreSQL хранит конфиги. Всё это живёт в трёх Docker-контейнерах и занимает 15 минут на поднятие.
Оставайтесь на связи
Рецепты от IT-боли. Без воды, без рекламы, без маркетинговой шелухи.
Подписаться на IT-Аптеку →



