Self-hosted сервис дома или в маленьком офисе традиционно требует белого IP у провайдера, проброса портов на роутере и постоянной тревоги о том, что 22 порт светится всему интернету. Cloudflare Tunnel переворачивает схему: лёгкий фоновый процесс cloudflared на вашем сервере сам устанавливает исходящее соединение к ближайшим точкам Cloudflare, а входящий трафик приходит по нему изнутри наружу уже зашифрованным. Ни открытых портов, ни статического IP, ни настройки NAT. В статье разбираем реальную настройку: туннели на dashboard и через CLI, публикация HTTP-сервисов и TCP, доступ по Access-политикам и типовые грабли эксплуатации.
Как устроен туннель и почему ему не нужен белый IP
Классическая схема публикации выглядит так: интернет стучится на ваш публичный адрес, роутер перебрасывает порт внутрь. У cloudflared всё наоборот: процесс на сервере открывает четыре долгоживущих QUIC-соединения к двум дата-центрам Cloudflare, и эти соединения живут постоянно. Когда пользователь обращается к вашему домену, запрос попадает на ближайший edge-узел Cloudflare, проходит по уже установленному каналу к cloudflared и дальше к локальному сервису.
Следствий из этой модели несколько. Нужно только исходящее соединение на 443 порт - это работает из-за любого NAT, включая серые адреса мобильных и домашних провайдеров. Публичный адрес сервера в интернете не существует: сканеры портов просто не найдут вашу машину, потому что слушать снаружи нечего. TLS тоже приходит из коробки: Cloudflare терминирует TLS на своём edge и издаёт сертификаты для ваших имён автоматически, certbot не нужен. Дополнительный бонус - DDoS-защита уровня сети включена по умолчанию, потому что трафик идёт через сеть Cloudflare.
Требования скромные: зарегистрированный домен, перенесённый на неймсерверы Cloudflare (бесплатный план достаточен), и машина с Linux, Windows, macOS или контейнером, куда поставится cloudflared. Сами туннели входят в бесплатный тариф, что делает решение привлекательным для домашних лабораторий.
Быстрый старт, named tunnel через CLI
Практика начинается с установки: на Debian и Ubuntu доступен официальный репозиторий, на остальном бинарник скачивается со страницы релизов. После установки сервер привязывается к аккаунту командой cloudflared tunnel login, которая открывает браузер для авторизации и складывает cert.pem в ~/.cloudflared.
Дальше создаётся туннель и DNS-запись:
cloudflared tunnel create home-infra
cloudflared tunnel route dns home-infra app.example.com
Конфигурация описывается в ~/.cloudflared/config.yml:
tunnel: <tunnel-id>
credentials-file: /root/.cloudflared/<tunnel-id>.json
ingress:
- hostname: app.example.com
service: http://localhost:8080
- hostname: grafana.example.com
service: http://localhost:3000
- service: http_status:404
Правила ingress проверяются сверху вниз, и последним обязан быть catch-all - иначе cloudflared не запустится. После запуска cloudflared tunnel run home-infra сервис становится доступным по имени. Для постоянной работы процесс оформляется в systemd: cloudflared service install сам выпишет юнит, и дальше systemctl enable --now cloudflared.
Важная мелочь: credentials-file это фактически ключ к туннелю, хранить его надо с правами 0600 и не коммитить в репозиторий. Потеря файла не катастрофа - токен можно перевыпустить (cloudflared tunnel token), но файл с машины при компрометации надо отозвать через удаление туннеля и создание нового.
Управление через панель, remotely-managed туннели
Второй способ ведения туннеля - через Zero Trust dashboard. Там туннель создаётся в веб-интерфейсе, а на сервере ставится только docker-контейнер или сервис с токеном: cloudflared service install <token>. Вся маршрутизация ingress-правил живёт в панели и правится мышкой. Плюс очевиден: можно редактировать маршруты без захода на сервер, и для инфраструктуры из нескольких площадок это удобно. Минус тоже есть: конфиг не лежит в git рядом с инфраструктурным кодом, и восстановить его из бэкапа сложнее.
На практике выбирают так: одиночный домашний сервер - конфиг файлом через CLI, потому что он читается, версионируется и переносится. Много площадок и несколько администраторов - через dashboard, потому что централизованное управление и аудит действий перевешивают неудобства absence of git.
Не только HTTP, SSH, TCP и доступ для людей
Туннель умеет не только веб. Для SSH на домашнюю машину публикуется сервис вида ssh.example.com со service: ssh://localhost:22, а на стороне клиента используется обёртка cloudflared access ssh или строка в ~/.ssh/config с вызовом cloudflared access ssh --hostname %h в роли соединителя. После этого SSH работает как обычно, но порт 22 на сервере закрыт даже в локальной сети от внешнего мира.
Для людей вместо IP-списков применяется Cloudflare Access: на имя grafana.example.com навешивается политика "пускать только этих email после одноразового кода на почту" или "пускать после входа через корпоративный identity provider". Это превращает самодельный сервис в нечто с нормальной аутентификацией без написания единой строчки кода. Для домашней лаборатории это избавляет от привычки прятать сервисы за обсурными портами типа 8453: безопасность через неизвестность работает до первого сканера, а политика Access реально проверяет личность.
Есть и ограничения бесплатного плана, о которых стоит знать: тяжёлый файловый трафик (раздача сотен гигабайт) не поощряется, это не CDN для торрентов; Websockets работают, но старые инструкции про их неподдержку устарели, всё давно заведено. RDP и произвольный TCP передаётся через cloudflared access tcp с клиентским cloudflared на стороне подключающегося.
Эксплуатация, грабли и мониторинг
Первая грабля, на которую наступают все: изменения ingress в локальном конфиге не применяются сами, нужен рестарт сервиса или отправка SIGHUP - cloudflared перечитает конфигурацию. Вторая грабля это большие загрузки: по умолчанию передача не ограничивает размер запроса, но 100-секундный таймаут на ответ Cloudflare для HTTP-spread случаев приводит к 524 ошибкам на долгих запросах; лечится переходом медленных операций на асинхронную обработку или использованием non-HTTP маршрутов.
Третья - наблюдаемость. У cloudflared есть встроенный metrics endpoint: флаг --metrics localhost:2000 поднимет prometheus-совместимые метрики с числом соединений и ошибок по туннелю. Алерт на "количество активных соединений к edge упало с 4 до 0" ловит сетевые проблемы сервера раньше, чем найдёт внешний мониторинг, потому что внешний мониторинг в этой схеме видит edge Cloudflare, а не ваш сервер - стоит помнить, что таймаут наружного healthcheck означает проблему между edge и cloudflared, а не недоступность самого cloudflared из интернета.
Отдельная полезная привычка - держать чек-лист имени сервиса. Для самых критичных сервисов прописывают параллельный способ доступа, не зависящий от туннеля: например, SSH через резервный канал на роутере. Туннель отказоустойчив благодаря четырём соединениям к двум ДЦ, но человеческая ошибка в конфиге надёжно ломает то, что не могли сломать сетевые сбои. И наконец: держите cloudflared обновлённым, у него регулярные релизы, и на Linux обновление это просто apt upgrade или замена бинарника с последующим рестартом сервиса.
Итоговая рекомендация проста: если у вас дома или в офисе живут сервисы, которыми вы пользуетесь снаружи - заведите named tunnel, закройте все входящие порты на роутере и забудьте словосочетание "проброс портов". Десять минут настройки заменяют годы мелких тревог о том, что именно сейчас видно вашей машиной из интернета.
Туннель для частных сетей, доступ ко всей домашней подсети
Помимо публикации отдельных сервисов, cloudflared умеет роль шлюза в домашнюю сеть: конфигурация private network объявляет маршрут, скажем 192.168.1.0/24, через туннель. Тогда устройство с клиентом WARP (мобильный телефон или ноутбук с установленным клиентом Cloudflare) получает доступ ко всем адресам домашней сети: роутеру, NAS, принтеру, тому самому сервису, для которого лень писать отдельный ingress. Это заменяет самосборные схемы доступа в домашнюю сеть без прокладки серых маршрутов руками.
Настройка на стороне панели: в туннеле включается private network с CIDR домашней подсети, а на стороне сети у cloudflared должны быть права форвардить трафик - на Linux включается net.ipv4.ip_forward. Split tunnel в клиенте решает, какой трафик идёт в туннель: обычно в него загоняют только домашние адреса и служебные домены, остальной трафик идёт напрямую, чтобы не гнуть весь интернет через дом.
Развёртывание в Docker и повторяемость конфигурации
В контейнерной домашней лаборатории cloudflared логично запускать контейнером. Минимальный service для docker compose:
services:
cloudflared:
image: cloudflare/cloudflared:latest
restart: unless-stopped
command: tunnel --no-autoupdate run
environment:
- TUNNEL_TOKEN=...
network_mode: host
Детали, которые экономят вечер. Флаг --no-autoupdate обязателен в контейнере: самообновление внутри контейнера приведёт к конфликту с image-тегом и потере контроля над версиями. network_mode host упрощает доступ к сервисам на localhost хоста; альтернатива - общая docker-сеть с внутренними именами сервисов, тогда cloudflared может быть в своей изолированной сети. Токен tunnel token берётся из панели или из cloudflared tunnel token и хранится в .env файле вне git, с правами 600.
Отказоустойчивость, реплики туннеля
Один cloudflared с четырьмя соединениями это уже надёжно, но для важных сервисов туннель запускают в репликах: второй экземпляр cloudflared на другой машине с тем же токеном поднимает свои соединения к edge, и Cloudflare сам балансирует входящий трафик между ними. Это даёт переживание апдейтов и ребутов: пока одна машина перезагружается, вторая несёт трафик, и пользователи сервиса ничего не замечают. В панели видно, сколько реплик сейчас активно; полезно настроить алерт на "ноль активных соединений".
Конфигурация реплик тривиальна: docker compose с туннелем поднимается на втором хосте с тем же TUNNEL_TOKEN, всё. Жонглировать отдельными туннелями не требуется - один named tunnel допускает сколько угодно подключений от имени одного токена.
Безопасность, что туннель меняет, а что нет
Туннель скрывает сервер от пассивного сканирования и убирает необходимость открытых портов, но не отменяет здравого смысла внутри сервиса. Приложение, публикуемое через ingress, должно само требовать аутентификацию или быть защищено политикой Access - отсутствие открытого порта не значит, что админка с пустым паролем стала безопасной. Заголовки: cloudflared добавляет Cf-Connecting-Ip и CF-Connecting-IP, поэтому реальный IP посетителя доступен приложению, и rate limiting на уровне приложения работает корректно.
Ещё полезно ограничить исходящие соединения сервера: cloudflared нужен только исходящий 443 к адресам Cloudflare. Если политика исходящего трафика у вас строгая, добавьте в allowlist именно их. И последнее: домен на Cloudflare это единая точка отказа всей схемы. Держите регистрацию домена оплаченной на годы вперёд, включите двухфакторную защиту аккаунта Cloudflare и ограничьте API-токены по принципу минимума - туннель удобен ровно до тех пор, пока контроль над доменом и аккаунтом принадлежит вам.
Собранная по этим правилам связка - домен на Cloudflare, named tunnel с ingress в git, cloudflared в systemd или docker compose с репликой на второй машине, Access-политики на чувствительные сервисы - даёт домашней инфраструктуре уровень публикации, который раньше требовал статического IP, оборудования и толикой смелости. А главное, схема одинаково хорошо работает и для одного сервера в шкафу, и для распределённой по нескольким адресам сети сервисов.