5.0 KiB
Cloudflare Tunnel: SSH через Published Application Route
Обновлено: 2026-09-04 (итог отладки захода на Kraken) Рабочий case с полными командами:
family/how-to/kraken-access.md
Генерализуемые выводы про то, как сделать SSH через Cloudflare Tunnel (published application route), чтобы вход работал ssh user@host — через cloudflared на клиенте.
Ключевое правило: hostname должен быть 1-уровневым subdomain (БЕЗ точки до домена)
Симптом: двухуровневый subdomain вида ssh.kraken.qentra.top (ssh.kraken + точка + qentra.top) НЕ работает как SSH/TLS через Cloudflare.
Проверка (решающий факт) — на edge НЕТ TLS-терминации для 2-уровневого hostname:
openssl s_client -connect ssh.kraken.qentra.top:443 -servername ssh.kraken.qentra.top
# → SSL alert number 40 (handshake failure), "no peer certificate available"
curl -s https://ssh.kraken.qentra.top # ssl=1 handshake failure
В отличие от 1-уровневого hostname (kraken.qentra.top), который отвечает:
openssl s_client -connect kraken.qentra.top:443 ... # CN=qentra.top, verify ok
Почему: Universal SSL Cloudflare-зоны покрывает только *.domain (1 уровень wildcard) и сам domain. Он НЕ покрывает *.sub.domain (2 уровень). Для 2-уровневых нужен Advanced Certificate (SAN на полный двухуровневый wildcard) — обычно проще взять одиночный subdomain.
⚠️ ПИТФОЛ: Cloudflare-точка в hostname (
a.b.domain) = 2 уровня по SSL, точка НЕ безобидна. Рабочая замена — один уровень с дефисом:ssh-kraken.qentra.top(покрывается*.qentra.top).
Правильная схема SSH через Tunnel (по доке Cloudflare)
На сервере/туннеле (Zero Trust):
- Tunnels → туннель → Routes → Add route → Published application
- Service: SSH →
localhost:22(или<ip>:22) - hostname использовать одиночный subdomain (
ssh-kraken.qentra.top, неssh.kraken...)
В Zero Trust Access:
- Access → Applications → Add self-hosted (тип SSH, browser rendering off) на тот же hostname, с политикой (Allow / Service Token).
- SSH-route без Access Application не даёт клиенту пройти даже до авторизации:
cloudflared access login <ssh-host>→failed to get app info: ... tls: handshake failure.
На клиенте (cloudflared установлен):
~/.ssh/config:
Host ssh-kraken.qentra.top
HostName ssh-kraken.qentra.top
User kraken
ProxyCommand cloudflared access ssh --hostname %h
Первый раз — авторизация: cloudflared access login ssh-kraken.qentra.top (откроет SSO/браузер). Дальше ssh kraken@ssh-kraken.qentra.top.
Client-side подводные камни
cloudflared access login <ssh-hostname>нельзя проверить поHEAD https://<ssh-host>— SSH-kind hostname НЕ терминирует HTTP/TLS, поэтомуfailed to get app info: tls: handshake failure— ожидаемо, если на маршруте нет Access App.~/.cloudflared/*-org-token=not-availableозначает, что cloudflared НЕ авторизован в Access org — разовыйcloudflared access loginобязателен.- Сам ssh к hostname:22 напрямую (без cloudflared в ProxyCommand) к проксированному DNS не работает — hostname за Cloudflare-Anycast, в туннель трафик попадает только через cloudflared-клиент.
network_mode: host(container cloudflared) — сервис напрямую видит локальные порты (sshd на0.0.0.0:22).
Общий паттерн «жив, но шумит» cloudflared на origin без IPv6
Если у origin нет глобального IPv6 (роутер не выдаёт), cloudflared пытается поднять QUIC и по IPv6 → в логах постоянные ERR ... write udp [::]->198.41.x.x:7844: sendmsg: network is unreachable, соединения падают/retry. Туннель продолжает работать по IPv4-QUIC. Возможный фикс — заставить cloudflared использовать только IPv4.
Связанные заметки
family/how-to/kraken-access.md— рабочий живой пример (hostnamessh-kraken.qentra.top, ingress, команды)family/how-to/kraken-portainer-access.md— деплой cloudflared-контейнера и логи туннеля