Туннели и NAT-обход
Агентам PRX часто необходимо принимать входящие соединения -- обратные вызовы вебхуков от GitHub, обновления Telegram, события Slack или межузловая коммуникация. При работе за NAT или файрволом подсистема туннелирования обеспечивает автоматический входящий доступ, устанавливая исходящее соединение к провайдеру туннеля и отображая публичный URL на ваш локальный экземпляр PRX.
Зачем нужно туннелирование
Многие функции PRX требуют публично доступного эндпоинта:
- Каналы вебхуков -- Telegram, Discord, Slack и GitHub отправляют события на указанный вами URL. Без публичного эндпоинта эти каналы не смогут доставлять сообщения вашему агенту.
- Обратные вызовы OAuth2 -- Потоки аутентификации провайдера перенаправляют браузер на локальный URL. Туннели позволяют это работать даже когда PRX запущен в приватной сети.
- Межузловая коммуникация -- Распределённые развёртывания PRX требуют, чтобы узлы могли связываться друг с другом. Туннели соединяют узлы в разных сетях.
- Хостинг MCP-сервера -- Когда PRX выступает MCP-сервером для внешних клиентов, туннель предоставляет публичный эндпоинт.
Поддерживаемые бэкенды
PRX поставляется с четырьмя бэкендами туннелей и заглушкой no-op:
| Бэкенд | Провайдер | Бесплатный план | Свой домен | Требуется авторизация | Zero-Trust |
|---|---|---|---|---|---|
| Cloudflare Tunnel | Cloudflare | Да | Да (с зоной) | Да (cloudflared) | Да |
| Tailscale Funnel | Tailscale | Да (личный) | Через MagicDNS | Да (аккаунт Tailscale) | Да |
| ngrok | ngrok | Да (ограниченно) | Да (платно) | Да (токен авторизации) | Нет |
| Пользовательская команда | Любой | Зависит | Зависит | Зависит | Зависит |
| Нет | -- | -- | -- | -- | -- |
Архитектура
Подсистема туннелирования построена на трейте Tunnel:
#[async_trait]
pub trait Tunnel: Send + Sync {
/// Start the tunnel and return the public URL.
async fn start(&mut self) -> Result<String>;
/// Stop the tunnel and clean up resources.
async fn stop(&mut self) -> Result<()>;
/// Check if the tunnel is healthy and the public URL is reachable.
async fn health_check(&self) -> Result<bool>;
}Каждый бэкенд реализует этот трейт. Структура TunnelProcess управляет базовым дочерним процессом (например, cloudflared, tailscale, ngrok) -- обрабатывая запуск, захват stdout/stderr, корректное завершение и автоматический перезапуск при сбое.
┌─────────────────────────────────────────────┐
│ PRX Gateway │
│ (localhost:8080) │
└──────────────────┬──────────────────────────┘
│ (локально)
┌──────────────────▼──────────────────────────┐
│ TunnelProcess │
│ ┌──────────────────────────────────┐ │
│ │ cloudflared / tailscale / ngrok │ │
│ │ (дочерний процесс) │ │
│ └──────────────┬───────────────────┘ │
└─────────────────┼───────────────────────────┘
│ (исходящий TLS)
┌─────────────────▼───────────────────────────┐
│ Граничная сеть провайдера туннеля │
│ https://your-agent.example.com │
└──────────────────────────────────────────────┘Конфигурация
Настройка туннеля в config.toml:
[tunnel]
# Backend selection: "cloudflare" | "tailscale" | "ngrok" | "custom" | "none"
backend = "cloudflare"
# Local address that the tunnel will forward traffic to.
# This should match your gateway listen address.
local_addr = "127.0.0.1:8080"
# Health check interval in seconds. The tunnel is restarted if
# the health check fails consecutively for `max_failures` times.
health_check_interval_secs = 30
max_failures = 3
# Auto-detect: if backend = "auto", PRX probes for available
# tunnel binaries in order: cloudflared, tailscale, ngrok.
# Falls back to "none" with a warning if nothing is found.Конфигурация для конкретных бэкендов
Каждый бэкенд имеет собственную секцию конфигурации. Подробности на страницах отдельных бэкендов:
- Cloudflare Tunnel --
[tunnel.cloudflare] - Tailscale Funnel --
[tunnel.tailscale] - ngrok --
[tunnel.ngrok]
Бэкенд пользовательской команды
Для провайдеров туннелей, не поддерживаемых нативно, используйте бэкенд custom:
[tunnel]
backend = "custom"
[tunnel.custom]
# The command to run. Must accept traffic on local_addr and print
# the public URL to stdout within startup_timeout_secs.
command = "bore"
args = ["local", "8080", "--to", "bore.pub"]
startup_timeout_secs = 15
# Optional: regex to extract the public URL from stdout.
# The first capture group is used as the URL.
url_pattern = "listening at (https?://[\\S]+)"Автоопределение
При backend = "auto" PRX ищет бинарники туннелей в $PATH в следующем порядке:
cloudflared-- предпочтителен благодаря возможностям zero-trusttailscale-- предпочтителен для приватной mesh-сетиngrok-- широко доступен, простая настройка
Если ничего не найдено, туннель отключается и PRX записывает предупреждение. Каналы, зависящие от вебхуков, не будут работать без туннеля или публичного IP.
Жизненный цикл TunnelProcess
Структура TunnelProcess управляет жизненным циклом дочернего процесса:
| Фаза | Описание |
|---|---|
| Запуск | Старт бинарника туннеля с настроенными аргументами |
| Извлечение URL | Парсинг stdout для получения публичного URL (в пределах startup_timeout_secs) |
| Мониторинг | Периодические проверки состояния через HTTP GET к публичному URL |
| Перезапуск | При max_failures последовательных неудачных проверок -- остановка и перезапуск |
| Завершение | Отправка SIGTERM, ожидание 5 секунд, затем SIGKILL при необходимости |
Переменные окружения
Конфигурацию туннеля можно задать через переменные окружения, которые имеют приоритет над config.toml:
| Переменная | Описание |
|---|---|
PRX_TUNNEL_BACKEND | Переопределение бэкенда туннеля |
PRX_TUNNEL_LOCAL_ADDR | Переопределение локального адреса перенаправления |
PRX_TUNNEL_URL | Пропустить запуск туннеля и использовать этот URL |
CLOUDFLARE_TUNNEL_TOKEN | Токен Cloudflare Tunnel |
NGROK_AUTHTOKEN | Токен аутентификации ngrok |
Установка PRX_TUNNEL_URL полезна, когда у вас уже есть обратный прокси или балансировщик нагрузки, открывающий PRX публично. Подсистема туннелирования пропустит управление процессом и будет использовать предоставленный URL напрямую.
Замечания по безопасности
- Терминация TLS -- Все поддерживаемые бэкенды терминируют TLS на граничном узле провайдера. Трафик между провайдером и вашим локальным экземпляром PRX проходит через зашифрованный туннель.
- Контроль доступа -- Cloudflare и Tailscale поддерживают политики доступа на основе идентичности. Используйте их при открытии чувствительных эндпоинтов агента.
- Хранение учётных данных -- Токены туннеля и ключи авторизации хранятся в менеджере секретов PRX. Никогда не фиксируйте их в системе контроля версий.
- Изоляция процессов --
TunnelProcessзапускается как отдельный дочерний процесс. Он не разделяет память со средой выполнения агента PRX.
Устранение неполадок
| Симптом | Причина | Решение |
|---|---|---|
| Туннель запускается, но вебхуки не работают | URL не передан в конфигурацию канала | Проверьте, что tunnel.public_url используется каналом |
| Туннель перезапускается постоянно | Проверка состояния обращается к неверному эндпоинту | Убедитесь, что local_addr совпадает с адресом прослушивания шлюза |
| Ошибка "binary not found" | CLI-утилита туннеля не установлена | Установите соответствующий бинарник (cloudflared, tailscale, ngrok) |
| Таймаут при извлечении URL | Бинарник туннеля слишком долго запускается | Увеличьте startup_timeout_secs |