SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-27

Настройка Cloudflare Tunnel на VPS без открытых портов

Пошаговое руководство по запуску cloudflared как службы systemd. Узнайте, как правильно настроить ingress rules и закрыть порты 80 и 443, чтобы полностью скрыть IP сервера.

Что делает Cloudflare Tunnel и что на самом деле означает отсутствие открытых портов

Cloudflare Tunnel размещает на вашем VPS небольшой демон под названием cloudflared. Этот демон устанавливает исходящее соединение с Cloudflare и поддерживает его в активном состоянии. Запросы к вашему имени хоста поступают на пограничные серверы Cloudflare и передаются обратно по уже существующему соединению, поэтому входящие подключения к вашему серверу не требуются.

Этап, который пропускают большинство руководств: установка туннеля сама по себе ничего не закрывает. Если порты 80 и 443 остаются открытыми в вашем брандмауэре, а приложение продолжает прослушивать 0.0.0.0, вы добавили второй путь доступа, а не заменили первый. Ваш исходный IP-адрес по-прежнему доступен, и любой, кто его обнаружит, сможет обойти Cloudflare напрямую. Закрытие этих портов — это ручная операция, и именно она делает все предыдущие действия целесообразными.

cloudflared требует исходящего доступа к region1.v2.argotunnel.com и region2.v2.argotunnel.com на порту 7844. Он использует UDP для протокола QUIC с переключением на TCP для HTTP/2 в качестве резервного варианта. В сети с фильтрацией исходящего трафика разрешите оба протокола или принудительно используйте TCP-путь с помощью --protocol http2.

Перед началом работы

  • Домен, уже добавленный в аккаунт Cloudflare, где Cloudflare выступает в роли DNS-сервера для зоны. cloudflared tunnel route dns вносит записи в эту зону, поэтому она должна быть создана заранее.
  • Исходящий доступ с VPS по порту 7844, протоколы UDP и TCP.
  • Приложение, уже работающее локально, даже если для первого теста это просто python3 -m http.server 8080.
  • sudo на сервере и открытая вторая SSH-сессия до того, как вы начнете изменять настройки файрвола.

Установка cloudflared в Ubuntu или Debian

Cloudflare прикрепляет пакет .deb к каждому релизу cloudflared, поэтому установка сводится к одной загрузке и одному вызову dpkg.

curl -fsSL -o /tmp/cloudflared.deb \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i /tmp/cloudflared.deb
cloudflared --version

Сначала выполните dpkg --print-architecture, если вы не уверены в архитектуре системы. На 64-битной архитектуре ARM имя файла заканчивается на arm64, а не на amd64, в остальном процесс не меняется. cloudflared --version, выводящий строку версии, — это единственное подтверждение, необходимое перед продолжением.

Пакет, установленный таким способом, находится вне пути обновления apt, поэтому apt-get upgrade никогда не будет его обновлять, и ответственность за обновления ложится на вас. sudo cloudflared update загружает новейший релиз и заменяет бинарный файл на месте; как только сервис будет создан, выполните sudo systemctl restart cloudflared, чтобы запущенный процесс использовал новый бинарный файл. Включите это в график обслуживания наряду с остальными обновлениями, так как демон туннеля является программным обеспечением, взаимодействующим с интернетом, даже если он не открывает порты.

Вход в систему и создание именованного туннеля

cloudflared tunnel login

На VPS без графического интерфейса браузер не откроется, поэтому скопируйте выведенный URL в браузер на вашем ноутбуке и выберите зону. После завершения процесса будет создан файл ~/.cloudflared/cert.pem.

cert.pem — это учетные данные вашей учетной записи. Они позволяют создавать туннели, записывать DNS-записи в эту зону и удалять туннели. Запущенный туннель не использует этот файл. Обращайтесь с ним как с паролем, так как копии этого файла достаточно, чтобы злоумышленник мог публиковать новые имена хостов в вашем домене.

cloudflared tunnel create homelab

При успешном выполнении будут выведены обе строки, приведенные ниже; UUID из них — это значение, которое вы вставите в конфигурационный файл.

Tunnel credentials written to /home/you/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.
Created tunnel homelab with id 6ff42ae2-765d-4adf-8112-31c55c1551ef

Этот JSON-файл является идентификатором туннеля, и это единственные учетные данные, необходимые для работы службы. Любой, у кого есть этот файл, может зарегистрироваться как ваш туннель и получать ваш трафик. Отдельно сменить его невозможно: отзыв означает выполнение cloudflared tunnel delete homelab и создание нового туннеля.

Храните файл учетных данных в безопасном месте

Сервис работает от имени root, поэтому разместите файл в директории, принадлежащей root, вместо того чтобы оставлять его в домашней директории, к которой может получить доступ задача резервного копирования или общий аккаунт.

sudo install -d -m 700 -o root -g root /etc/cloudflared
sudo install -m 600 -o root -g root \
  ~/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json \
  /etc/cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
rm ~/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
sudo ls -l /etc/cloudflared
cloudflared tunnel list

ls -l должен отображать -rw------- root root для JSON-файла. cloudflared tunnel list считывает cert.pem, поэтому он продолжает работать; при этом он выводит имя туннеля, его UUID и количество текущих соединений.

Создание config.yml с актуальными правилами ingress

Создавайте конфигурацию по пути /etc/cloudflared/config.yml, а не в домашнем каталоге. Причина в следующем. cloudflared service install копирует найденный файл конфигурации в /etc/cloudflared/config.yml, а затем жестко прописывает --config /etc/cloudflared/config.yml в юнит systemd. Если вы создадите файл в ~/.cloudflared/config.yml, эта копия станет разовым снимком. Любые последующие правки в домашней копии ни на что не повлияют: сервис продолжит использовать старые правила, и система не выдаст предупреждение. Создание файла непосредственно в рабочем каталоге полностью устраняет эту проблему.

tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef
credentials-file: /etc/cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
loglevel: info

ingress:
  - hostname: app.example.com
    service: http://127.0.0.1:8080
  - hostname: files.example.com
    service: http://127.0.0.1:8081
  - hostname: grafana.example.com
    path: ^/api/
    service: http://127.0.0.1:3000
  - service: http_status:404

Правила считываются сверху вниз, первое совпадение считается приоритетным. Правило без hostname соответствует любому имени хоста, поэтому «универсальное» правило (catch-all) должно находиться в самом конце. Если его пропустить, конфигурация будет отклонена с ошибкой The last ingress rule must match all URLs (i.e. it should not have a hostname or path filter). http_status:404 — это встроенный сервис, который возвращает 404 и больше ничего не делает. Он необходим: без него запрос к хосту, который вы не планировали публиковать, будет перенаправлен на последнее из существующих правил.

Используйте 127.0.0.1 в URL service: вместо localhost. В Ubuntu localhost сначала разрешается в ::1, и приложение, привязанное только к IPv4 loopback, отклонит такое соединение. В логах появится запись dial tcp [::1]:8080: connect: connection refused, а пользователь увидит ошибку 502.

Обычный http:// здесь корректен, так как трафик не покидает пределы машины. Используйте https:// только в том случае, если локальное приложение требует TLS (transport layer security), и будьте готовы к ошибке x509: certificate is valid for example.com, not localhost, если его сертификат не совпадает с именем, к которому вы обращаетесь. Исправьте это с помощью originServerName в разделе originRequest или примите риск, используя noTLSVerify: true.

Проверьте правила перед запуском:

sudo cloudflared --config /etc/cloudflared/config.yml tunnel ingress validate
sudo cloudflared --config /etc/cloudflared/config.yml tunnel ingress rule https://app.example.com/login

ingress validate сообщает, является ли конфигурация валидной, или указывает на правило, вызвавшее ошибку. ingress rule принимает один URL и выводит первое правило, которое ему соответствует; это самый быстрый способ убедиться, что регулярное выражение path работает не так, как вы предполагали.

Настройка DNS для туннеля

cloudflared tunnel route dns homelab app.example.com
cloudflared tunnel route dns homelab files.example.com
cloudflared tunnel route dns homelab grafana.example.com

Каждый вызов создает проксируемую CNAME-запись, указывающую на 6ff42ae2-765d-4adf-8112-31c55c1551ef.cfargotunnel.com. Этот целевой адрес разрешается только внутри сети Cloudflare, поэтому в публичном DNS-ответе для вашего имени хоста будет указан адрес Cloudflare, а IP-адрес вашего VPS не будет раскрыт. Для подстановочного знака hostname в config.yml по-прежнему требуется наличие соответствующей DNS-записи для каждого используемого вами имени.

Если запись уже существует, команда завершается с ошибкой:

Failed to add route: code: 1003, reason: Failed to create record app.example.com with err An A, AAAA, or CNAME record with that host already exists.

Эта существующая запись почти всегда является старой A-записью, указывающей на публичный IP-адрес вашего VPS, — именно её необходимо удалить. Удалите её в панели управления Cloudflare и повторно выполните команду. Если оставить её, DNS продолжит публиковать IP-адрес вашего origin-сервера, и туннель не обеспечит скрытие данных.

Установка в качестве службы для автозапуска после перезагрузки

Запустите процесс в интерактивном режиме, так как ошибки проще отслеживать в терминале, чем в журнале.

sudo cloudflared --config /etc/cloudflared/config.yml tunnel run homelab

При успешном запуске в логах появится несколько строк Registered tunnel connection — по одной для каждой точки присутствия, каждая со своим connIndex. Откройте один из ваших хостнеймов в браузере и убедитесь, что правила входящего трафика направляют вас по нужному адресу, затем остановите процесс комбинацией Ctrl-C.

sudo cloudflared --config /etc/cloudflared/config.yml service install
systemctl status cloudflared

Эта команда создает /etc/systemd/system/cloudflared.service вместе с cloudflared-update.service и cloudflared-update.timer, а затем выполняет systemctl enable cloudflared.service и systemctl start cloudflared.service. Файл enable является ключевым, так как именно он обеспечивает восстановление туннеля после перезагрузки. В параметре ExecStart юнита указан путь cloudflared --no-autoupdate --config /etc/cloudflared/config.yml tunnel run, поэтому этот путь к конфигурации является обязательным.

Три типа ошибок на этом этапе имеют конкретные сообщения. possible conflicting configuration in /home/you/.cloudflared/config.yml and /etc/cloudflared/config.yml означает, что существуют оба файла, и cloudflared отказывается выбирать между ними: удалите ненужный файл. configuration file ... must contain entries for the tunnel to run and its associated credentials (tunnel: TUNNEL-UUID, credentials-file: CREDENTIALS-FILE) означает, что в конфигурации используется сокращенный синтаксис url: вместо ключей именованного туннеля, а такой синтаксис не может работать в качестве службы. cloudflared service is already installed означает, что в системе остался старый юнит, поэтому сначала выполните sudo cloudflared service uninstall.

Функции перезагрузки конфигурации не предусмотрено. После редактирования /etc/cloudflared/config.yml выполните sudo systemctl restart cloudflared. Затем проверьте работу автозапуска на практике, а не полагайтесь на предположения:

sudo reboot
# once it is back
systemctl is-enabled cloudflared
systemctl is-active cloudflared
journalctl -u cloudflared -n 50 --no-pager
curl -sI https://app.example.com

Вывод is-enabled в виде enabled и is-active в виде active — главная цель этого раздела. Как только маршруты созданы и служба запущена, cert.pem больше не требуется на сервере: rm ~/.cloudflared/cert.pem. Добавление нового хостнейма в будущем потребует лишь повторного выполнения cloudflared tunnel login.

Закройте порты 80 и 443, иначе туннель станет лишь дополнительным путем доступа

Вам необходимо выполнить два изменения. Если сделать только одно из них, исходный сервер останется доступным извне.

Сначала привяжите приложение к адресу loopback. В nginx это означает замену listen 127.0.0.1:8080; на listen 80;, как описано в этом руководстве по настройке обратного прокси nginx. В Docker Compose это означает использование ports: - "127.0.0.1:8080:80". Обычная форма "8080:80" публикует порт на всех интерфейсах, а Docker создает собственные правила NAT (network address translation), которые обрабатываются до того, как пакеты попадают в ufw, поэтому правило deny в ufw их не остановит. Этому ловушке посвящена отдельная статья: почему опубликованные порты Docker игнорируют ufw.

sudo ss -lntp

Каждый перенесенный сервис теперь должен отображать 127.0.0.1:8080 в столбце Local Address. Строка с 0.0.0.0:8080 или *:8080 означает, что сервис по-прежнему доступен извне.

Во-вторых, закройте порты.

sudo ufw status numbered
sudo ufw delete allow 'Nginx Full'
sudo ufw status

Удалите разрешающие правила для 80 и 443 вместо того, чтобы добавлять поверх них запрещающие, так как ufw останавливается на первом совпавшем правиле, и старое разрешающее правило выше в списке будет иметь приоритет. Сохраните правило для SSH. Руководство по основам брандмауэра ufw описывает остальную часть этого набора правил. Большинство провайдеров VPS также используют отдельный сетевой брандмауэр в своей панели управления, который не связан с ufw, поэтому закройте порты 80 и 443 также и там.

Теперь выполните проверку с другого узла, так как curl http://127.0.0.1:8080 на самом сервере ничего не говорит о доступности из внешней сети.

# run these from a different machine
nc -vz 203.0.113.10 443
curl -sI https://app.example.com

Отказ в соединении или таймаут при выполнении nc по прямому IP-адресу в сочетании с успешным 200 через имя хоста — это тот результат, который вам нужен. Проверка того, открыт ли порт на самом деле содержит дополнительные способы тестирования.

Туннель обеспечивает передачу данных, а не аутентификацию. Все, что вы публикуете через него, доступно публично, если вы не установите перед этим авторизацию: либо Cloudflare Access на границе сети, либо OAuth2-прокси перед приложением на самом сервере. Для SSH также требуется отдельное решение, так как туннель его не защищает: оставьте порт 22 открытым, но ограничьте доступ к нему только вашими IP-адресами.

Преимущества и недостатки Cloudflare Tunnel

Вы получаете реальные выгоды. IP-адрес вашего origin-сервера скрыт, входящие порты не открыты, настройка работает даже на машине без публичного IP-адреса. Управление публичными сертификатами берет на себя Cloudflare, поэтому на вашем сервере не требуется запускать ACME-клиент. Объемные атаки поглощаются на границе сети, не расходуя вашу полосу пропускания.

Издержки столь же реальны. Cloudflare выполняет TLS termination на своей границе: запрос посетителя расшифровывается там и заново шифруется для передачи в туннель, поэтому Cloudflare может читать ваш трафик. Именно это позволяет работать их файрволу, кэшированию и правилам Access, и эту функцию невозможно отключить, пока вы используете их прокси. Если передача открытого текста третьей стороне для вас неприемлема, на этом этапе стоит выбрать другое решение.

Cloudflare также становится критической зависимостью для доступности сервиса. Когда cloudflared не подключен, посетители видят страницу ошибки Cloudflare 1033 вместо вашего приложения, при этом вы осознанно удалили прямой маршрут, который мог бы служить резервным.

Только HTTP, HTTPS и WebSocket доступны по публичному имени хоста из обычного браузера. Любой другой TCP-протокол, SSH, RDP (remote desktop protocol) или игровой сервер требуют установки дополнительного ПО на стороне клиента: cloudflared access tcp для проброса локального порта или клиент WARP. Других способов доступа без клиентского ПО не существует.

Размер тела запроса ограничен на границе сети, и загрузка, превышающая лимит, отклоняется с ошибкой HTTP 413 еще до того, как запрос достигнет вашего приложения. По состоянию на август 2026 года этот лимит составляет 100 MB на бесплатных и Pro-тарифах и выше на платных уровнях, поэтому перед проектированием архитектуры проверьте текущую страницу ограничений Cloudflare. Условия использования Cloudflare также ограничивают использование прокси для раздачи видео и других крупных не-HTML файлов; с ними стоит ознакомиться, прежде чем направлять медиабиблиотеку через бесплатный туннель.

Cloudflare Tunnel, обратный SSH-туннель или Tailscale Funnel

Все три решения работают только на исходящие соединения, поэтому они подходят для серверов без открытых входящих портов и публичных IP-адресов. Разница заключается в том, кто имеет доступ к вашим незашифрованным данным и какое доменное имя будет видеть пользователь.

Для обратного SSH-туннеля требуется второй сервер с публичным IP-адресом, который станет входной точкой: сертификаты, обратный прокси и межсетевой экран на нем находятся под вашим полным контролем. Никто, кроме вас, не расшифровывает трафик. Это решение требует больше усилий по настройке, а для корректной работы после разрывов сети необходим autossh или systemd-юнит с параметром Restart=always. В руководстве по настройке обратного SSH-туннеля для CGNAT описан процесс создания такой конфигурации.

Tailscale Funnel — наиболее близкий аналог. Он также работает только на исходящие соединения, а TLS-терминация происходит на вашем устройстве, поэтому ретрансляторы Tailscale не видят незашифрованный трафик. Ограничения касаются имен и портов: Funnel работает только с именами в домене ts.net вашей tailnet и только на портах 443, 8443 и 10000. В статье Разница между Tailscale Serve и Funnel подробно разобраны оба механизма.

Выбирайте решение исходя из ваших ограничений. Используйте Cloudflare Tunnel, если пользователям нужен доступ к вашему собственному домену и вы готовы к тому, что Cloudflare будет видеть ваш трафик. Выбирайте Tailscale Funnel, если вас устраивает доменное имя ts.net и вы не хотите передавать незашифрованные данные прокси-серверу. Выбирайте обратный SSH-туннель, если у вас уже есть публичный сервер и вы хотите полностью исключить третьих лиц из цепочки передачи данных.

FAQ

Нужно ли оставлять открытым порт 443 при использовании Cloudflare Tunnel?

Нет. cloudflared устанавливает исходящее соединение с Cloudflare через порт 7844, и все запросы поступают обратно по этому же соединению, поэтому входящие порты не используются. Однако установка туннеля не закрывает порты автоматически. Удалите правила разрешения для 80 и 443 в ufw, закройте их в сетевом файрволе вашего провайдера, привяжите приложение к 127.0.0.1 и удалите все оставшиеся A-записи, которые публикуют IP-адрес вашего VPS. Проверьте состояние портов с помощью sudo ss -lntp на сервере и nc -vz <your-ip> 443 с другой машины.

Почему для моего имени хоста отображается ошибка Cloudflare Error 1033?

Ошибка 1033 означает, что Cloudflare содержит DNS-запись для этого имени хоста, но не может найти активный cloudflared, готовый принять запрос. Либо процесс остановлен, либо он запущен, но не может связаться с Cloudflare. Проверьте systemctl status cloudflared и journalctl -u cloudflared -n 50, затем убедитесь, что исходящий порт 7844 разрешен как для UDP, так и для TCP, так как файрвол, блокирующий UDP и QUIC без разрешения TCP-резервирования, вызывает именно эту проблему. cloudflared tunnel info homelab показывает текущие соединения, которые видит Cloudflare; пустой список означает, что проблема на вашей стороне.

Почему я получаю ошибку 502 Bad Gateway через туннель?

Ошибка 502 означает, что cloudflared получил запрос, но не смог связаться с вашим локальным сервисом, поэтому проблема находится между ними, а не на стороне Cloudflare. Изучите логи. dial tcp [::1]:8080: connect: connection refused означает, что по указанному адресу ничего не прослушивается, а [::1] в этом сообщении обычно указывает на то, что вы написали localhost в URL service:, в то время как приложение привязано только к IPv4, поэтому используйте http://127.0.0.1:8080. HTTP/1.x transport connection broken: malformed HTTP response — это обратное несоответствие: вы указали https:// для источника, который работает по обычному HTTP.

Могу ли я запустить SSH, RDP или игровой сервер через Cloudflare Tunnel?

Не через обычный клиент. Публичное имя хоста через туннель передает HTTP, HTTPS и WebSocket — протоколы, которые понимает браузер. Для любого другого TCP-протокола требуется дополнительное ПО на клиентской машине: либо cloudflared access tcp для перенаправления локального порта, либо клиент WARP. Если вам нужен SSH с любого устройства без установки дополнительного ПО, туннель — неподходящий инструмент. Оставьте порт 22 открытым, ограничив доступ по IP-адресу источника.

Видит ли Cloudflare мой трафик через туннель?

Да. Cloudflare завершает TLS на своем пограничном узле, расшифровывает запрос там и повторно шифрует его для передачи в туннель к вашему серверу. Эта расшифровка необходима для работы их файрвола, кэширования и политик Access, что означает, что данные в открытом виде существуют на их оборудовании. Никакая конфигурация не позволит избежать этого при использовании их прокси. Если это неприемлемо, используйте Tailscale Funnel или запустите собственный reverse proxy на публичном сервере.

#cloudflare-tunnel#cloudflared#zero-trust#firewall#self-hosting