"Быстрый
<br />
Apache Guacamole — это веб-шлюз удаленного доступа без клиентского ПО. Открываешь браузер, вводишь адрес, получаешь SSH, RDP или VNC к любому серверу в сети. Никаких плагинов, никаких отдельных клиентов. Все подключения в одном месте, снаружи виден только один порт твоего шлюза.<br />
<h2>Apache Guacamole: установка, настройка и подключение SSH, RDP, VNC через браузер</h2>
<p>Ты сейчас держишь в голове пять разных клиентов. PuTTY для SSH, mstsc для RDP, какой-нибудь TigerVNC для VNC, отдельный SSH-туннель для Kubernetes и ещё что-то для экзотики. Каждый раз когда подключаешься с нового устройства — ставишь всё заново. Каждый раз когда надо дать доступ коллеге — объясняешь по телефону как настроить клиент.</p>
<p>Guacamole закрывает эту боль. Один раз поднял шлюз — и больше не думаешь о клиентах.</p>
<p>В этой статье разберём: что внутри, как поднять через <a class="wpil_keyword_link" href="https://it-apteka.com/tag/docker/" target="_blank" rel="noopener" title="Docker" data-wpil-keyword-link="linked" data-wpil-monitor-id="1683">Docker</a> Compose за 15 минут, как добавить подключения SSH/RDP/VNC, как это защитить и что делать когда сломается. Без воды.</p>
<h2>Что нужно перед стартом</h2>
<table>
<thead>
<tr>
<th>Компонент</th>
<th>Минимум</th>
<th>Рекомендовано</th>
</tr>
</thead>
<tbody>
<tr>
<td>ОС</td>
<td>Ubuntu 20.04 LTS</td>
<td>Ubuntu 22.04 LTS / <a class="wpil_keyword_link" href="https://it-apteka.com/tag/debian/" target="_blank" rel="noopener" title="Debian" data-wpil-keyword-link="linked" data-wpil-monitor-id="1680">Debian</a> 12</td>
</tr>
<tr>
<td>RAM</td>
<td>2 GB</td>
<td>4 GB</td>
</tr>
<tr>
<td>CPU</td>
<td>1 ядро</td>
<td>2 ядра</td>
</tr>
<tr>
<td>Диск</td>
<td>10 GB</td>
<td>20 GB</td>
</tr>
<tr>
<td>Docker</td>
<td>20.10+</td>
<td>24.x+</td>
</tr>
<tr>
<td>Docker Compose</td>
<td>v2.0+</td>
<td>v2.20+</td>
</tr>
<tr>
<td>Apache Guacamole</td>
<td>1.5.x</td>
<td>1.5.5 (актуальна на момент публикации)</td>
</tr>
<tr>
<td>PostgreSQL</td>
<td>13</td>
<td>15</td>
</tr>
</tbody>
</table>
<p>Перед установкой проверь свежие релизы на <code>hub.docker.com/r/guacamole/guacamole</code> — версии обновляются.</p>
<p>Доступы которые нужны: root или sudo на сервере, открытый порт 8080 (или любой другой который выберешь для шлюза).</p>
<h2>Архитектура: как это вообще работает</h2>
<p>Прежде чем копировать команды — разберись с архитектурой. Иначе потом не поймёшь почему что-то не работает.</p>
<p>Guacamole состоит из двух частей:</p>
<p><strong>guacd</strong> — демон на C. Это движок. Он принимает соединения от веб-приложения и транслирует их в нативные протоколы: RDP, SSH, VNC, Telnet. Никакой логики, никакого UI — только транспорт.</p>
<p><strong>guacamole-client</strong> — Java-приложение в Tomcat. Это веб-интерфейс. Он аутентифицирует пользователей, хранит конфиги подключений в базе и общается с guacd по протоколу Guacamole.</p>
<p>Поток данных выглядит так:</p>
<pre class="mermaid">%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#ffffff',
'primaryTextColor': '#1e293b',
'primaryBorderColor': '#94a3b8',
'lineColor': '#64748b',
'fontSize': '15px',
'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
},
'flowchart': {'curve': 'linear', 'nodeSpacing': 50, 'rankSpacing': 50}
}}%%
flowchart TD
A["Браузер пользователя"] --> B["guacamole-client\nTomcat / Java\nport 8080"]
B --> C["guacd\nDaemon / C\nport 4822"]
C --> D["SSH\nport 22"]
C --> E["RDP\nport 3389"]
C --> F["VNC\nport 5900"]
B --> G["PostgreSQL\nКонфиги и пользователи"]
style A fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
style B fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
style C fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#9a3412
style D fill:#f8fafc,stroke:#94a3b8,stroke-width:1px,color:#1e293b
style E fill:#f8fafc,stroke:#94a3b8,stroke-width:1px,color:#1e293b
style F fill:#f8fafc,stroke:#94a3b8,stroke-width:1px,color:#1e293b
style G fill:#f8fafc,stroke:#94a3b8,stroke-width:1px,color:#1e293b
</pre>
<p>Ключевой момент: снаружи открыт только порт 8080 (или 443 после настройки Nginx). SSH, <a href="https://it-apteka.com/smena-porta-rdp-windows-shpargalka-it-inzhenera-s-primerami/" title="Смена порта RDP Windows: шпаргалка IT-инженера с примерами" target="_blank" rel="noopener" data-wpil-monitor-id="1685">RDP и VNC порты</a> целевых серверов наружу не торчат — к ним ходит guacd изнутри сети. Это и есть главный плюс с точки зрения безопасности.</p>
<h2>Таблица портов</h2>
<table>
<thead>
<tr>
<th>Сервис</th>
<th>Порт</th>
<th>Направление</th>
<th>Описание</th>
</tr>
</thead>
<tbody>
<tr>
<td>guacamole-client</td>
<td>8080/tcp</td>
<td>входящий (от пользователей)</td>
<td>Веб-интерфейс, перекрывается Nginx на 443</td>
</tr>
<tr>
<td>guacd</td>
<td>4822/tcp</td>
<td>внутренний (client → guacd)</td>
<td>Только между контейнерами, наружу не открывать</td>
</tr>
<tr>
<td>PostgreSQL</td>
<td>5432/tcp</td>
<td>внутренний (client → db)</td>
<td>Только между контейнерами</td>
</tr>
<tr>
<td>SSH цели</td>
<td>22/tcp</td>
<td>исходящий (guacd → цель)</td>
<td>guacd подключается к целевым серверам</td>
</tr>
<tr>
<td>RDP цели</td>
<td>3389/tcp</td>
<td>исходящий (guacd → цель)</td>
<td>guacd подключается к целевым <a class="wpil_keyword_link" href="https://it-apteka.com/category/windows-server/" target="_blank" rel="noopener" title="Windows Server" data-wpil-keyword-link="linked" data-wpil-monitor-id="1684">Windows</a></td>
</tr>
<tr>
<td>VNC цели</td>
<td>5900/tcp</td>
<td>исходящий (guacd → цель)</td>
<td>guacd подключается к VNC-серверам</td>
</tr>
</tbody>
</table>
<h2>Установка Apache Guacamole через Docker Compose</h2>
<p>Буду честен: есть два пути — собирать из исходников и Docker. Из исходников — это зависимости, libfreerdp, libssl, patching, и два часа жизни которые ты не вернёшь. Docker — это 15 минут и рабочий шлюз. Выбор очевиден.</p>
<h3>Шаг 1: Создай структуру проекта</h3>
<pre><code class="language-bash">
mkdir -p ~/guacamole/init && cd ~/guacamole
</code></pre>
<h3>Шаг 2: Сгенерируй SQL-схему для PostgreSQL</h3>
<p>Guacamole не создаёт таблицы сам при первом запуске. Нужно запустить образ с флагом генерации схемы и сохранить SQL-файл.</p>
<pre><code class="language-bash">
docker run --rm guacamole/guacamole:1.5.5 /opt/guacamole/bin/initdb.sh --postgresql > ~/guacamole/init/initdb.sql
</code></pre>
<p>Проверь что файл не пустой:</p>
<pre><code class="language-bash">
wc -l ~/guacamole/init/initdb.sql
# Должно быть несколько сотен строк
</code></pre>
<h3>Шаг 3: Создай docker-compose.yml</h3>
<pre><code class="language-text">
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:
</code></pre>
<p>Обрати внимание: папка <code>./init</code> монтируется в <code>/docker-entrypoint-initdb.d</code>. PostgreSQL автоматически выполнит все .sql файлы из этой папки при первом старте. Вот зачем мы генерировали схему на шаге 2.</p>
<h3>Шаг 4: Запусти</h3>
<pre><code class="language-bash">
cd ~/guacamole
docker compose up -d
</code></pre>
<h3>Шаг 5: Проверь что всё поднялось</h3>
<pre><code class="language-bash">
docker compose ps
</code></pre>
<p>Результат должен быть такой:</p>
<pre><code class="language-text">
NAME STATUS PORTS
guacd Up 4822/tcp
guacamole-postgres Up 5432/tcp
guacamole-web Up 0.0.0.0:8080->8080/tcp
</code></pre>
<p>Если какой-то контейнер в состоянии Exited — смотри логи:</p>
<pre><code class="language-bash">
docker compose logs guacamole
docker compose logs postgres
</code></pre>
<h3>Шаг 6: Первый вход и смена пароля</h3>
<p>Открой в браузере: <code>http://IP_СЕРВЕРА:8080/guacamole</code></p>
<p>Логин: <code>guacadmin</code>, пароль: <code>guacadmin</code></p>
"Критично:
<br />
guacadmin с паролем guacadmin — это первое что пробуют боты. Зайди в Settings — Users — guacadmin и смени пароль до того как сделаешь что-либо ещё.<br />
<h2>Настройка подключений</h2>
<h3>SSH-подключение к Linux-серверу</h3>
<p>Иди в <strong>Settings — Connections — New Connection</strong>.</p>
<table>
<thead>
<tr>
<th>Поле</th>
<th>Значение</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name</td>
<td>Любое понятное имя</td>
</tr>
<tr>
<td>Protocol</td>
<td>SSH</td>
</tr>
<tr>
<td>Hostname</td>
<td>IP или <a class="wpil_keyword_link" href="https://it-apteka.com/tag/dns/" target="_blank" rel="noopener" title="DNS" data-wpil-keyword-link="linked" data-wpil-monitor-id="1681">DNS</a> имя сервера</td>
</tr>
<tr>
<td>Port</td>
<td>22</td>
</tr>
<tr>
<td>Username</td>
<td>Пользователь на сервере</td>
</tr>
<tr>
<td>Password</td>
<td>Пароль (или оставь пустым если используешь ключ)</td>
</tr>
<tr>
<td>Private Key</td>
<td>Вставь содержимое ~/.ssh/id_rsa если используешь ключ</td>
</tr>
</tbody>
</table>
<p>Если используешь ключ — поле Password оставь пустым, иначе Guacamole попробует пароль и ключ проигнорирует.</p>
<p>Сохрани. Теперь на главной странице появится иконка подключения. Кликай — откроется терминал прямо в браузере.</p>
<h3>RDP-подключение к Windows</h3>
<table>
<thead>
<tr>
<th>Поле</th>
<th>Значение</th>
</tr>
</thead>
<tbody>
<tr>
<td>Protocol</td>
<td>RDP</td>
</tr>
<tr>
<td>Hostname</td>
<td>IP Windows-машины</td>
</tr>
<tr>
<td>Port</td>
<td>3389</td>
</tr>
<tr>
<td>Username</td>
<td>Пользователь (с доменом: DOMAIN\user)</td>
</tr>
<tr>
<td>Password</td>
<td>Пароль</td>
</tr>
<tr>
<td>Security mode</td>
<td>NLA — если сервер поддерживает; Any — если не уверен</td>
</tr>
<tr>
<td>Ignore server certificate</td>
<td>Включи если самоподписанный сертификат</td>
</tr>
</tbody>
</table>
<p>Вот тут важно: если подключаешься к Windows Server и видишь ошибку аутентификации — сначала проверь что на целевой машине включён Remote Desktop и пользователь добавлен в группу «Remote Desktop Users». Это не Guacamole виноват.</p>
<h3>VNC-подключение</h3>
<table>
<thead>
<tr>
<th>Поле</th>
<th>Значение</th>
</tr>
</thead>
<tbody>
<tr>
<td>Protocol</td>
<td>VNC</td>
</tr>
<tr>
<td>Hostname</td>
<td>IP машины с VNC-сервером</td>
</tr>
<tr>
<td>Port</td>
<td>5900 (или 5901, 5902 — зависит от дисплея)</td>
</tr>
<tr>
<td>Password</td>
<td>VNC-пароль</td>
</tr>
</tbody>
</table>
<h3>Подключение к Pod в Kubernetes</h3>
<p>Хитрый случай. Прямого коннектора к Kubernetes у Guacamole нет — но есть обходной путь через SSH с начальной командой.</p>
<p>Настрой SSH-подключение к бастион-хосту или ноде кластера где есть kubeconfig. В поле <strong>Initial command</strong> на вкладке Terminal вставь:</p>
<pre><code class="language-bash">
kubectl exec -it ИМЯ_ПОДА -n NAMESPACE -- /bin/bash
</code></pre>
<p>При подключении по этому соединению сразу попадёшь в оболочку пода. Удобно для дежурных сценариев когда надо быстро зайти без терминала.</p>
<h2>Видео по теме</h2>
<p><strong><a href="https://youtu.be/GAPrAsNesyU" target="_blank" rel="nofollow noopener">Ссылка на оригинал на YouTube</a></strong></p>
<h2>Групповые соединения и балансировка</h2>
<p>Если у тебя несколько однотипных серверов — Guacamole умеет группировать их с балансировкой нагрузки.</p>
<p>Иди в <strong>Settings — Connection Groups — New Group</strong>.</p>
<table>
<thead>
<tr>
<th>Параметр</th>
<th>Значение</th>
<th>Когда использовать</th>
</tr>
</thead>
<tbody>
<tr>
<td>Type: ORGANIZATIONAL</td>
<td>Просто папка для группировки</td>
<td>Логическая структура без балансировки</td>
</tr>
<tr>
<td>Type: BALANCING</td>
<td>Балансировка по загрузке</td>
<td>Терминальные фермы, кластеры</td>
</tr>
</tbody>
</table>
<p>При типе BALANCING Guacamole будет отправлять нового пользователя на наименее нагруженное соединение в группе. Для <a href="https://it-apteka.com/tag/terminalnyj-server/" title="терминальный сервер" target="_blank" rel="noopener" data-wpil-monitor-id="1686">терминальных</a> ферм или кластеров из нескольких идентичных серверов — удобно.</p>
<h2>HTTPS через Nginx: без этого в продакшн не идём</h2>
<p>Guacamole на порту 8080 без TLS — это не продакшн. Ставим <a href="https://it-apteka.com/nginx_proxy_manager/" title="Nginx Proxy Manager: Конфигурация reverse-proxy для популярных веб-интерфейсов" target="_blank" rel="noopener" data-wpil-monitor-id="1687">Nginx как reverse proxy</a>.</p>
<h3>Установка Nginx и Certbot</h3>
<pre><code class="language-bash">
apt update && apt install -y nginx certbot python3-certbot-nginx
</code></pre>
<h3>Конфиг Nginx для Guacamole</h3>
<pre><code class="language-text">
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;
}
}
</code></pre>
<p>Обрати внимание на <code>proxy_read_timeout 3600</code>. Это критично для SSH/RDP сессий — без этого Nginx будет рвать долгие соединения через стандартные 60 секунд.</p>
<h3>Получи сертификат</h3>
<pre><code class="language-bash">
certbot --nginx -d guacamole.example.com
</code></pre>
<h3>Перезапусти Nginx</h3>
<pre><code class="language-bash">
nginx -t && systemctl reload nginx
</code></pre>
<h2>Безопасность</h2>
"Минимальный
<br />
Это не рекомендации — это минимум без которого шлюз не должен быть доступен из интернета. Проверь каждый пункт.<br />
<h3>UFW: закрой всё лишнее</h3>
<pre><code class="language-bash">
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
</code></pre>
<h3>Fail2ban для Guacamole</h3>
<p>Guacamole пишет неудачные попытки входа в лог Tomcat. Настроим fail2ban на этот лог.</p>
<pre><code class="language-bash">
apt install -y fail2ban
</code></pre>
<p>Создай файл <code>/etc/fail2ban/filter.d/guacamole.conf</code>:</p>
<pre><code class="language-text">
[Definition]
failregex = o.a.g.r.auth.AuthenticationService - Authentication attempt from for user .* failed
ignoreregex =
</code></pre>
<p>Создай <code>/etc/fail2ban/jail.d/guacamole.conf</code>:</p>
<pre><code class="language-text">
[guacamole]
enabled = true
port = 80,443
filter = guacamole
logpath = /var/lib/docker/containers/*/*.log
maxretry = 5
bantime = 3600
findtime = 600
</code></pre>
<pre><code class="language-bash">
systemctl restart fail2ban
fail2ban-client status guacamole
</code></pre>
<h3>Отдельный пользователь для каждой группы людей</h3>
<p>Не давай guacadmin всем. Создай отдельных пользователей в Settings — Users и назначь им права только на нужные подключения. Принцип минимальных привилегий работает и здесь.</p>
<h3>Двухфакторная аутентификация</h3>
<p>Guacamole поддерживает TOTP через расширение. Скачай <code>guacamole-auth-totp-1.5.5.jar</code> с официального сайта и положи в:</p>
<pre><code class="language-bash">
# Создай папку для расширений и смонтируй её в контейнер
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
</code></pre>
<p>Добавь в <code>docker-compose.yml</code> в секцию volumes контейнера guacamole:</p>
<pre><code class="language-text">
- ./extensions:/etc/guacamole/extensions:ro
</code></pre>
<p>Перезапусти контейнер — при следующем входе пользователю предложат настроить TOTP.</p>
<h2>Резервное копирование</h2>
<p>Что бэкапить: базу PostgreSQL с конфигами подключений и пользователями, папку extensions если используешь расширения.</p>
<h3>Бэкап базы</h3>
<pre><code class="language-bash">
#!/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"
</code></pre>
<p>Добавь в cron:</p>
<pre><code class="language-bash">
crontab -e
# Добавь строку:
0 3 * * * /opt/scripts/backup_guacamole.sh >> /var/log/guacamole_backup.log 2>&1
</code></pre>
<h3>Восстановление из бэкапа</h3>
<pre><code class="language-bash">
# Останови контейнеры
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
</code></pre>
<h2>Обновление Guacamole</h2>
<p>Обновляй через смену тега образа в docker-compose.yml.</p>
<pre><code class="language-bash">
# Сделай бэкап базы ПЕРЕД обновлением
/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
</code></pre>
"Проверь
<br />
Иногда между мажорными версиями меняется схема базы. В таких случаях нужна миграция. Это описано в официальных release notes на guacamole.apache.org/releases. Не игнорируй их.<br />
<h2>Проверка работоспособности</h2>
<pre><code class="language-bash">
# Статус контейнеров
docker compose ps
# Логи в реальном времени
docker compose logs -f guacamole
# Доступность веб-интерфейса
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/guacamole/
# Должен вернуть 200 или 302
</code></pre>
<pre><code class="language-bash">
# Проверка что guacd слушает
docker exec guacd netstat -tlnp | grep 4822
# Проверка подключения к базе изнутри контейнера guacamole
docker exec guacamole-web env | grep POSTGRES
</code></pre>
<h2>Troubleshooting</h2>
<h3>Белый экран или 404 после открытия браузера</h3>
<p><strong>Причина:</strong> приложение ещё не запустилось. Tomcat стартует медленно.<br />
<strong>Решение:</strong> подожди 30-60 секунд и обнови страницу. Если не помогает — смотри логи:</p>
<pre><code class="language-bash">
docker compose logs guacamole | tail -50
</code></pre>
<h3>Ошибка «Cannot connect to guacd»</h3>
<p><strong>Причина:</strong> контейнер guacd не запустился или guacamole обращается по неправильному адресу.<br />
<strong>Решение:</strong></p>
<pre><code class="language-bash">
# Проверь что 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
</code></pre>
<h3>Ошибка инициализации PostgreSQL: «relation does not exist»</h3>
<p><strong>Причина:</strong> SQL-схема не была применена при первом старте. Это бывает если том postgres_data уже существовал до монтирования init-папки.<br />
<strong>Решение:</strong></p>
<pre><code class="language-bash">
# Останови всё
docker compose down
# Удали том с данными (данные потеряются - это свежая установка)
docker volume rm guacamole_postgres_data
# Убедись что initdb.sql лежит в ./init/
ls -la ~/guacamole/init/initdb.sql
# Запусти снова
docker compose up -d
</code></pre>
<h3>RDP подключение зависает или отваливается через несколько минут</h3>
<p><strong>Причина:</strong> таймаут proxy_read_timeout в Nginx.<br />
<strong>Решение:</strong> убедись что в конфиге Nginx стоит <code>proxy_read_timeout 3600</code> и <code>proxy_send_timeout 3600</code>.</p>
<h3>SSH работает, но нет поддержки UTF-8 / кириллица не отображается</h3>
<p><strong>Причина:</strong> не настроена кодировка в параметрах подключения.<br />
<strong>Решение:</strong> в настройках SSH-соединения на вкладке Terminal укажи:<br />
— Terminal type: xterm-256color<br />
— Font name: monospace</p>
<h3>Не работает буфер обмена между браузером и сессией</h3>
<p>Это фича браузеров, не баг Guacamole. Нажми <kbd>Ctrl+Alt+Shift</kbd> внутри сессии — откроется боковая панель Guacamole с буфером обмена. Вставляй текст туда, и он появится в сессии.</p>
<h2>Альтернативы Apache Guacamole</h2>
<table>
<thead>
<tr>
<th>Решение</th>
<th>Плюсы</th>
<th>Минусы</th>
<th>Когда выбрать</th>
</tr>
</thead>
<tbody>
<tr>
<td>Apache Guacamole</td>
<td>Open source, активная разработка, много протоколов</td>
<td>Java в стеке, требует отдельного guacd</td>
<td>Универсальный шлюз для смешанной среды</td>
</tr>
<tr>
<td>Teleport</td>
<td>Встроенный аудит, certificate-based auth, Kubernetes</td>
<td>Сложнее в настройке, бесплатно только Community</td>
<td>Когда нужен детальный аудит и compliance</td>
</tr>
<tr>
<td>MeshCentral</td>
<td>Бесплатно, агентский доступ, встроенный relay</td>
<td>Нужен агент на целевых машинах</td>
<td>Когда нужно управлять конечными устройствами</td>
</tr>
<tr>
<td>RustDesk Server</td>
<td>Простота, P2P, открытый код</td>
<td>В основном для десктопов, слабее для серверов</td>
<td>Поддержка пользователей, не серверная инфра</td>
</tr>
</tbody>
</table>
<p>Guacamole выигрывает когда нужен централизованный шлюз без агентов на целевых серверах и с поддержкой смешанного парка: <a class="wpil_keyword_link" href="https://it-apteka.com/category/linux/" target="_blank" rel="noopener" title="Linux" data-wpil-keyword-link="linked" data-wpil-monitor-id="1679">Linux</a> по SSH, Windows по RDP, виртуалки по VNC.</p>
<h2>Профилактика: как не сломать снова</h2>
<ul>
<li>Поставь <a class="wpil_keyword_link" href="https://it-apteka.com/category/monitoring/" target="_blank" rel="noopener" title="Мониторинг" data-wpil-keyword-link="linked" data-wpil-monitor-id="1682">мониторинг</a> на доступность <code>http://localhost:8080/guacamole/</code> — например через Uptime Kuma или простой curl в cron</li>
<li>Настрой автообновление сертификата: certbot сам добавляет таймер в systemd, проверь <code>systemctl list-timers | grep certbot</code></li>
<li>Не храни пароли к подключениям в открытом виде — используй отдельного пользователя с минимальными правами для каждого критичного подключения</li>
<li>Логируй сессии: Guacamole умеет записывать RDP и SSH сессии в файлы. Включи через параметр Recording path в настройках соединения</li>
</ul>
<h2>FAQ</h2>
<h3>Почему Guacamole не видит новое SSH-подключение сразу после создания?</h3>
<p>Видит. Просто иногда нужно обновить страницу. Кэширование на стороне браузера. Если соединение не появляется и после обновления — проверь что пользователь имеет права на это подключение в Settings — Connections — Permission.</p>
<h3>Как проверить что guacd реально подключается к целевому серверу?</h3>
<pre><code class="language-bash">
# Смотри логи guacd во время попытки подключения
docker compose logs -f guacd
# В момент когда кликаешь на соединение в браузере - увидишь строки типа:
# guacd[1]: INFO: Connection ID is "..."
# guacd[1]: INFO: Creating new client for protocol "ssh"
</code></pre>
<p>Если в логах пусто в момент клика — проблема между guacamole-client и guacd, не между guacd и целью.</p>
<h3>Что если нужно дать временный доступ подрядчику?</h3>
<p>Создай отдельного пользователя, дай права только на нужные соединения, после окончания работ — удали пользователя. Не давай guacadmin никому. Это стандартная практика.</p>
<h3>Как записывать RDP и SSH сессии для аудита?</h3>
<p>В настройках подключения найди раздел Screen Recording (для RDP) или Typescript recording (для SSH). Укажи путь к директории. Для <a href="https://it-apteka.com/docker-compose-ustanovka-komandy-i-nastrojka-kontejnerov/" title="Docker Compose — установка, команды и настройка контейнеров" target="_blank" rel="noopener" data-wpil-monitor-id="1688">Docker это должна быть директория внутри контейнера</a> с примонтированным томом:</p>
<pre><code class="language-text">
Recording path: /record
Recording name: ${GUAC_DATE}_${GUAC_TIME}_${GUAC_USERNAME}
</code></pre>
<p>Добавь том в docker-compose.yml:</p>
<pre><code class="language-text">
volumes:
- /opt/guacamole/recordings:/record:rw
</code></pre>
<h2>Итог</h2>
<p>Поднял Guacamole — закрыл несколько задач одновременно: централизованный доступ, аудит сессий, минимальная поверхность атаки снаружи. Больше не нужно объяснять коллеге как настроить PuTTY. Больше не нужно открывать RDP наружу.</p>
<p>Архитектура простая: guacd транслирует протоколы, клиент на Tomcat отдаёт веб-интерфейс, PostgreSQL хранит конфиги. Всё это живёт в трёх Docker-контейнерах и занимает 15 минут на поднятие.</p>
"Не
<br />
Если что-то пошло не так — пиши в комментарии с логами из docker compose logs. Конкретный вывод конкретной команды. "Не работает" без логов — это не диагноз.<br />
Быстрый ответ: что такое Apache Guacamole и зачем он нужен
Apache Guacamole — это веб-шлюз удаленного доступа без клиентского ПО. Открываешь браузер, вводишь адрес, получаешь SSH, RDP или VNC к любому серверу в сети. Никаких плагинов, никаких отдельных клиентов. Все подключения в одном месте, снаружи виден только один порт твоего шлюза.
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.
Поток данных выглядит так:
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#ffffff',
'primaryTextColor': '#1e293b',
'primaryBorderColor': '#94a3b8',
'lineColor': '#64748b',
'fontSize': '15px',
'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
},
'flowchart': {'curve': 'linear', 'nodeSpacing': 50, 'rankSpacing': 50}
}}%%
flowchart TD
A["Браузер пользователя"] --> B["guacamole-client\nTomcat / Java\nport 8080"]
B --> C["guacd\nDaemon / C\nport 4822"]
C --> D["SSH\nport 22"]
C --> E["RDP\nport 3389"]
C --> F["VNC\nport 5900"]
B --> G["PostgreSQL\nКонфиги и пользователи"]
style A fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
style B fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
style C fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#9a3412
style D fill:#f8fafc,stroke:#94a3b8,stroke-width:1px,color:#1e293b
style E fill:#f8fafc,stroke:#94a3b8,stroke-width:1px,color:#1e293b
style F fill:#f8fafc,stroke:#94a3b8,stroke-width:1px,color:#1e293b
style G fill:#f8fafc,stroke:#94a3b8,stroke-width:1px,color:#1e293b
Ключевой момент: снаружи открыт только порт 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
Критично: смени пароль немедленно
guacadmin с паролем guacadmin — это первое что пробуют боты. Зайди в Settings — Users — 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
При подключении по этому соединению сразу попадёшь в оболочку пода. Удобно для дежурных сценариев когда надо быстро зайти без терминала.
Видео по теме
Ссылка на оригинал на YouTube
Групповые соединения и балансировка
Если у тебя несколько однотипных серверов — 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
Проверь release notes перед обновлением
Иногда между мажорными версиями меняется схема базы. В таких случаях нужна миграция. Это описано в официальных release notes на guacamole.apache.org/releases. Не игнорируй их.
Проверка работоспособности
# Статус контейнеров
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 минут на поднятие.
Не заработало - разберёмся
Если что-то пошло не так — пиши в комментарии с логами из docker compose logs. Конкретный вывод конкретной команды. «Не работает» без логов — это не диагноз.