Files
obsidian-vault/personal/tech/cloudflare-tunnel-ssh-published-route.md
T

63 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-контейнера и логи туннеля