Cloudflare Tunnel: открыть локальный сервер без публичного IP
Cloudflare Tunnel — простой способ опубликовать приложение, у которого нет публичного IP. У тебя домашний сервер, виртуалка за NAT, dev-стенд за корпоративным файрволом — Tunnel это легко решает. Я гоняю Tunnel-ы для нескольких проектов: от dev-окружения до прод-сервиса. Расскажу про настройку и где у меня болело.
Контекст: Linux-сервер за NAT (домашний роутер, корпоративная сеть, серверный VPS без публичного IP). Cloudflare как DNS-провайдер для домена.
Как это работает
Идея простая: на твоём сервере запускается процесс cloudflared, который сам устанавливает исходящее соединение к Cloudflare. Когда из интернета приходит запрос на твой домен, Cloudflare пробрасывает его через этот туннель прямо на сервер. Никаких входящих портов, никаких пробросов на роутере, никакого настоящего IP-адреса в открытом доступе.
Важный нюанс: трафик проходит через Cloudflare. Это значит, что Cloudflare видит твой трафик в расшифрованном виде (там можно настроить mTLS до своего сервера, но это уже отдельная история). Для большинства dev и прод-сценариев — приемлемо, но если у тебя строгие требования к локализации данных, тут стоит дважды подумать.
Что нужно
- Аккаунт в Cloudflare (Free-плана достаточно).
- Домен, делегированный на Cloudflare DNS.
- Сервер с возможностью исходящих подключений на 443 порт.
- Установленный
cloudflared.
Установка cloudflared
На Ubuntu/Debian:
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb
cloudflared --versionНа других ОС есть бинарики и пакеты на странице релизов. Под Alpine — скачать бинарь, положить в /usr/local/bin.
Авторизация
cloudflared loginКоманда откроет браузер и попросит выбрать домен, делегированный на Cloudflare. После авторизации создастся файл ~/.cloudflared/cert.pem с сертификатом, привязанным к твоему аккаунту и домену. Этот файл — основа дальнейшей работы. Не теряй его и не публикуй.
Создание туннеля
cloudflared tunnel create my-tunnelВернётся UUID туннеля и путь к credentials-файлу: ~/.cloudflared/<uuid>.json. Этот файл нужен сервису, чтобы аутентифицироваться при подключении к Cloudflare.
Конфиг
В ~/.cloudflared/config.yml:
tunnel: my-tunnel
credentials-file: /home/user/.cloudflared/<uuid>.json
ingress:
- hostname: app.example.ru
service: http://localhost:3000
- hostname: api.example.ru
service: http://localhost:4000
- hostname: db-admin.example.ru
service: http://localhost:8081
# обязательный «catch-all»
- service: http_status:404Каждый блок ingress — это правило: «запросы на такой-то hostname кидать на такой-то локальный URL». Последний catch-all обязателен — без него будет ошибка.
DNS-записи
cloudflared умеет сам прописать DNS-записи:
cloudflared tunnel route dns my-tunnel app.example.ru
cloudflared tunnel route dns my-tunnel api.example.ru
cloudflared tunnel route dns my-tunnel db-admin.example.ruВ Cloudflare DNS появятся CNAME-записи вида app.example.ru → <tunnel_uuid>.cfargotunnel.com. SSL-сертификаты Cloudflare выпускает автоматически.
Запуск
Тестово:
cloudflared tunnel run my-tunnelЕсли в логах connection registered — туннель работает. Заходи в браузер на https://app.example.ru и проверяй.
Для прод запускаешь как сервис:
sudo cloudflared service install
sudo systemctl enable --now cloudflaredcloudflared положит свой systemd-юнит и запустит его. Конфиг будет браться из /etc/cloudflared/config.yml; убедись, что туда скопирован твой config.yml и credentials-файл.
Сценарии использования
Dev-стенд за корпоративным файрволом
Хочешь показать заказчику ветку без деплоя на staging — поднимаешь приложение на ноуте, открываешь tunnel preview-1.example.ru, кидаешь ссылку. Всё работает, никаких VPN-ов и публикаций портов на корпоративном маршрутизаторе.
Внутренние админки
Bull Board, Grafana, pgAdmin, Adminer — всё это сервисы, которые лучше не светить наружу. Через Cloudflare Tunnel + Cloudflare Access ты получаешь zero-trust доступ: «только сотрудники с email на @example.ru». Внешним сканерам интерфейс невидим, не нужно раздавать VPN-доступ.
Webhooks для локальной разработки
Никаких ngrok-токенов и эфемерных URL. Один раз настроил dev-webhooks.example.ru, он живёт месяцами и ходит ровно к твоему ноуту. Стабильный URL для тестов оплат, бот-вебхуков, сторонних интеграций.
Self-hosted сервисы дома
Файловое хранилище, Plex, Home Assistant — всё это можно опубликовать через Tunnel без проброса портов на домашнем роутере. Я держу пару домашних сервисов на этом сетапе уже два года.
Cloudflare Access — это важная часть
Tunnel сам по себе делает сервис доступным из интернета. Если это админка — нужна аутентификация. Cloudflare Access — это zero-trust gateway, который ставится перед сервисом и требует аутентификации до того, как запрос дойдёт до тебя.
Настройка через панель Cloudflare:
- Zero Trust → Access → Applications → Add an application.
- Указываешь поддомен (например,
db-admin.example.ru). - Выбираешь политику: доступ только для конкретных email или domain. Можно подключить SSO через Google/Microsoft/Okta.
На бесплатном плане Cloudflare даётся до 50 пользователей, которым можно настроить такой доступ. Этого хватает почти для любых внутренних команд.
Подводные камни
WebSocket и SSE
Tunnel поддерживает их без отдельной настройки. Но Cloudflare имеет таймауты на длинные соединения: для бесплатного плана — 100 секунд idle. Если у тебя SSE с тонким стримом, добавь heartbeat-сообщения раз в 30 секунд.
Большие POST-запросы
Cloudflare ограничивает размер тела запроса: на бесплатном плане 100 MB, на платном — 500 MB и больше. Если хочешь грузить большие файлы напрямую — это не подойдёт, лучше использовать прямой upload в Object Storage с presigned URL.
Несколько туннелей на один сервер
На одном сервере может работать несколько cloudflared с разными config.yml — это нормально. Я держу два: один публичный (admins на zero-trust), второй приватный для дев-преврью с другим credentials-файлом. Не путаться помогает строгое именование.
Бэкап credentials
Файл <uuid>.json с приватным ключом туннеля незаменимый. Если потеряешь — придётся пересоздавать туннель и обновлять DNS-записи. Я держу его в защищённом backup-хранилище и в репозитории секретов.
Обновление
cloudflared обновляется не автоматически. На свежих версиях бывают улучшения по производительности и новые опции. Раз в пару месяцев обновляй вручную:
sudo cloudflared service stop
sudo dpkg -i <new cloudflared.deb>
sudo cloudflared service startСравнение с ngrok и tailscale
Я часто слышу вопрос «а почему не ngrok / tailscale».
- ngrok. Удобный для разовой ссылки. Tunnel держит постоянный URL без подписки и абонентки.
- tailscale. Отлично для соединения нескольких устройств в общую mesh-сеть. Но не для публикации сервиса наружу: внешние пользователи не получат прозрачный доступ через домен.
Каждый инструмент на своём месте. Для «опубликовать сервис в интернете без публичного IP» — Tunnel лучший вариант, который я пробовал.
Шпаргалка
cloudflared login, потомtunnel create.- config.yml с ingress-правилами, обязательный catch-all 404.
- DNS-записи через
cloudflared tunnel route dns. - Запуск как systemd-сервис.
- Защищай админки через Cloudflare Access.
- Бэкап credentials-файла.
- Помни про лимиты на размер запроса и таймауты.
Cloudflare Tunnel — то решение, которое экономит мне много времени. На простых задачах разворачивается за 10 минут, работает годами без вмешательства, не требует прав на роутер. Для большинства dev и внутренних сценариев — почти идеальный инструмент.