[2026-09-04] eagle: family/how-to/arr-stack-kraken.md family/how-to/hermes-kraken-api.md family/how-to/kraken-access.md family/how-to/kraken-network.md family/how-to/kraken-portainer-access.md family/how-to/openmediavault-rpi5.md family/how-to/router-bishkek-asus.md family/projects/watchlist-automation.md personal/tech/cloudflare-tunnel-ssh-published-route.md

This commit is contained in:
Alexey Martemyanov
2026-09-04 14:16:45 +06:00
parent d6266cf2ee
commit ae51be4872
9 changed files with 244 additions and 18 deletions
@@ -0,0 +1,62 @@
# 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:
```bash
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`), который отвечает:
```bash
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` — рабочий живой пример (hostname `ssh-kraken.qentra.top`, ingress, команды)
- `family/how-to/kraken-portainer-access.md` — деплой cloudflared-контейнера и логи туннеля