Развёртывание туннелей MCP с помощью Docker Compose
Установите стек туннеля MCP на виртуальную машину с помощью Docker Compose.
В этом руководстве стек туннеля развёртывается в виде защищённых контейнеров на одном хосте. Ту же конфигурацию можно реплицировать на несколько хостов для обеспечения доступности.
Прежде чем начать
Вам потребуется:
- Туннель. При программном доступе компонент настройки (setup component) создаёт его за вас, если вы не указываете идентификатор туннеля; чтобы вместо этого подключиться к существующему туннелю, создайте его в Console и запишите идентификатор туннеля (
tnl_...). Ручная подготовка всегда начинается с туннеля, созданного в Console. - Способ аутентификации хоста в Tunnels API.
- Программный доступ (рекомендуется). Включите Set up programmatic access при создании туннеля (или создайте правило федерации напрямую в разделе Settings > Workload identity, если вы позволяете компоненту настройки создать туннель), чтобы компонент настройки мог аутентифицироваться через Workload Identity Federation. Запишите идентификатор правила федерации (
fdrl_...) и идентификатор вашей организации. - Вручную. Пропустите программный доступ. Вы получите токен туннеля из Console, самостоятельно сгенерируете CA и серверный сертификат и зарегистрируете CA в Console.
- Программный доступ (рекомендуется). Включите Set up programmatic access при создании туннеля (или создайте правило федерации напрямую в разделе Settings > Workload identity, если вы позволяете компоненту настройки создать туннель), чтобы компонент настройки мог аутентифицироваться через Workload Identity Federation. Запишите идентификатор правила федерации (
- Хост с установленными Docker и Docker Compose. Для ручного процесса также требуется
openssl(версии 1.1.1 или новее). - Исходящее сетевое подключение от хоста к
api.anthropic.com(443 TCP) и к границе туннеля (tunnel edge) (7844 TCP и UDP). См. полные сетевые требования. - Один или несколько серверов MCP, запущенных и доступных с хоста по адресам, которые вы настроите в
routes. Если у вас его ещё нет, используйте пример сервера.
Необязательно: используйте пример сервера MCP
Если у вас нет сервера MCP для тестирования, используйте этот минимальный вариант:
mkdir -p mcp-tunnel
cat > mcp-tunnel/hello_server.py <<'EOF'
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("hello-server", host="0.0.0.0", port=9000)
@mcp.tool()
def hello(name: str = "world") -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run(transport="streamable-http")
EOFСледующие шаги установки выполняют cd в mcp-tunnel/ и указывают, где добавить соответствующий сервис и маршрут.
Установка
В этом руководстве приведён один эталонный подход с использованием Docker Compose. Вы несёте ответственность за его адаптацию в соответствии с требованиями безопасности вашей организации.
Этот путь требует, чтобы у хоста был поставщик удостоверений OIDC (например, сервер метаданных облачной виртуальной машины или SPIFFE). Если его нет, используйте вместо этого вкладку Без программного доступа.
Компонент настройки использует Workload Identity Federation, чтобы получить токен туннеля, сгенерировать CA и серверный сертификат и зарегистрировать CA в Anthropic.
Подготовьте каталог развёртывания
mkdir -p mcp-tunnel/{config,data} cd mcp-tunnel sudo chown 65532:65532 dataКонтейнеры запускаются от имени непривилегированного UID
65532и нуждаются в доступе на запись кdata/.Напишите docker-compose.yaml
Файл compose закрепляет образы по дайджесту SHA-256, запускает каждый контейнер от имени непривилегированного пользователя с файловой системой только для чтения, отбрасывает все возможности (capabilities) Linux и отключает повышение привилегий.
cat > docker-compose.yaml <<'EOF' services: setup: image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:efb27b299d627e4134815663cb8896641eeaee025d734c0f695582b4df38f013 entrypoint: ["/setup"] command: - init - --api-url=https://api.anthropic.com - --output=dir:/data - --token-version=1 environment: - TUNNEL_ID - ANTHROPIC_FEDERATION_RULE_ID - ANTHROPIC_ORGANIZATION_ID - ANTHROPIC_WORKSPACE_ID - ANTHROPIC_IDENTITY_TOKEN volumes: - ./data:/data user: "65532:65532" read_only: true security_opt: - no-new-privileges:true cap_drop: - ALL profiles: ["setup"] cloudflared: image: cloudflare/cloudflared@sha256:6b599ca3e974349ead3286d178da61d291961182ec3fe9c505e1dd02c8ac31b0 command: tunnel --no-autoupdate run --url http://localhost:8080 environment: - TUNNEL_TOKEN # Используем netns прокси, чтобы localhost:8080 был доступен. network_mode: "service:mcp-proxy" restart: unless-stopped user: "65532:65532" read_only: true security_opt: - no-new-privileges:true cap_drop: - ALL stop_grace_period: 30s logging: options: max-size: "10m" max-file: "3" mcp-proxy: image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:efb27b299d627e4134815663cb8896641eeaee025d734c0f695582b4df38f013 volumes: - ./config/mcp-proxy.yaml:/etc/mcp-gateway/config.yaml:ro - ./data:/data:ro restart: unless-stopped user: "65532:65532" read_only: true security_opt: - no-new-privileges:true cap_drop: - ALL stop_grace_period: 30s logging: options: max-size: "10m" max-file: "3" EOFЕсли вы используете пример сервера MCP, добавьте его как сервис:
cat >> docker-compose.yaml <<'EOF' hello-mcp: image: python:3.13-slim working_dir: /app volumes: - ./hello_server.py:/app/hello_server.py:ro command: sh -c "pip install --quiet mcp && python hello_server.py" restart: unless-stopped EOFПодготовьте туннель
Задайте идентификаторы. Оставьте
TUNNEL_IDнезаданным, чтобы компонент настройки создал туннель; задайте его, чтобы подключиться к существующему туннелю из Console:# export TUNNEL_ID=tnl_... # задайте, чтобы подключиться к существующему туннелю export ANTHROPIC_FEDERATION_RULE_ID=fdrl_... export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000Если ваше правило федерации ограничено рабочим пространством, отличным от рабочего пространства вашей организации по умолчанию, также задайте
ANTHROPIC_WORKSPACE_ID=wrkspc_...; в противном случае компонент настройки использует рабочее пространство по умолчанию. Автоматически создаваемый туннель создаётся в этом рабочем пространстве.Задайте
ANTHROPIC_IDENTITY_TOKENравным OIDC JWT от поставщика удостоверений этого хоста. Следуйте руководству по WIF для вашего поставщика, чтобы зарегистрировать издателя, задать субъект правила и выпустить токен; аудитория правила должна совпадать с аудиторией, которую вы запрашиваете при выпуске.Запустите компонент настройки:
docker compose run --rm setupsetup initидемпотентен относительноdata/: при повторном запуске он повторно использует уже сохранённые там идентификатор туннеля и CA и никогда не создаёт второй туннель. Новый CA генерируется и регистрируется только тогда, когдаdata/пуст илиTUNNEL_IDизменился; в этом случае действует ограничение в два активных сертификата, поэтому сначала отзовите один в Console, если оба слота заняты.См. раздел Сбои аутентификации компонента настройки, если возникает ошибка.
Получите домен вашего туннеля и экспортируйте его для последующих шагов:
export TUNNEL_DOMAIN=$(sudo cat data/tunnel-domain) echo "$TUNNEL_DOMAIN"Напишите конфигурацию прокси
tunnel_domainявляется обязательным: прокси использует его, чтобы удалить суффикс домена из входящих имён хостов перед поиском поддомена вroutes.routes— это плоское отображение поддомена на URL вышестоящего сервера, а не список.cat > config/mcp-proxy.yaml <<EOF listen_addr: ":8080" log_level: info shutdown_timeout: 30s tunnel_domain: ${TUNNEL_DOMAIN} tls: cert_file: /data/tls.crt key_file: /data/tls.key routes: echo: http://hello-mcp:9000 EOFМаршрут
echo:указывает на пример сервера MCP; замените его своими маршрутами (или добавьте их). См. справочник по конфигурации прокси со всеми доступными полями.Запустите развёртывание
export TUNNEL_TOKEN=$(sudo cat data/tunnel-token) docker compose up -d
Файл compose считывает TUNNEL_TOKEN из окружения хоста без значения по умолчанию, поэтому экспорт необходимо повторять в каждой новой оболочке и после перезагрузки.
Для развёртывания на нескольких виртуальных машинах скопируйте каталог mcp-tunnel/ на каждый хост, задайте TUNNEL_TOKEN и выполните docker compose up -d. В программном процессе TUNNEL_TOKEN равен $(sudo cat data/tunnel-token); в ручном процессе это значение, которое вы скопировали из Console. Один и тот же токен туннеля и сертификаты работают на всех репликах.
Проверка развёртывания
Выполните сквозную проверку, вызвав вышестоящий сервер MCP (upstream MCP server) со стороны Anthropic: см. раздел Использование туннелированных серверов MCP. С примером сервера MCP маршрутизируемый URL — https://echo.<your-tunnel-domain>/mcp. Если проверка не удалась, см. раздел Устранение неполадок.
Обновления
Выполняйте команды из этого раздела внутри каталога развёртывания mcp-tunnel/.
Ротация токена туннеля
При программном доступе увеличьте --token-version в команде сервиса setup, задайте идентификаторы Workload Identity Federation, выпустите новый OIDC JWT и повторно запустите компонент настройки:
# Отредактируйте docker-compose.yaml: увеличьте целое число в аргументе
# --token-version сервиса setup (например, с --token-version=1 на
# --token-version=2). Бинарный файл setup отказывается выполнять ротацию,
# если значение не изменилось.
# export TUNNEL_ID=tnl_... # задайте, только если задавали при установке
export ANTHROPIC_FEDERATION_RULE_ID=fdrl_...
export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000
# export ANTHROPIC_WORKSPACE_ID=wrkspc_... # если правило привязано к рабочему пространству
# Заново выпустите ANTHROPIC_IDENTITY_TOKEN по руководству провайдера WIF для вашей
# среды (с момента установки срок его действия истёк).
export ANTHROPIC_IDENTITY_TOKEN=...
docker compose run --rm setup
export TUNNEL_TOKEN=$(sudo cat data/tunnel-token)
docker compose up -d cloudflaredАргумент --token-version редактируется в docker-compose.yaml, а не передаётся в командной строке, чтобы новое значение сохранялось для будущих запусков компонента настройки. Компонент настройки аутентифицируется с помощью Workload Identity Federation; токена API для отзыва нет.
Без программного доступа нажмите Rotate token на странице сведений о туннеле в Console, затем обновите переменную окружения TUNNEL_TOKEN на каждом хосте и перезапустите cloudflared (docker compose up -d cloudflared).
Обновление сертификата
Вы несёте ответственность за отслеживание срока действия и обновление серверного сертификата до его истечения.
При программном доступе:
docker compose run --rm setup renew-cert --output=dir:/dataАргументы CLI заменяют command сервиса setup (аргументы init), но сохраняют его entrypoint, поэтому выполняется /setup renew-cert --output=dir:/data.
Без программного доступа подпишите новый серверный сертификат вашим существующим CA (CA, зарегистрированный в Console, не меняется) и замените data/tls.crt. Сначала задайте TUNNEL_DOMAIN, если вы выполняете это из новой оболочки.
export TUNNEL_DOMAIN=YOUR_TUNNEL_DOMAIN_HERE
openssl req -new -key data/tls.key -out /tmp/server.csr \
-subj "/CN=${TUNNEL_DOMAIN}"
openssl x509 -req -in /tmp/server.csr \
-CA data/ca.crt -CAkey data/ca.key -CAcreateserial \
-out data/tls.crt -days 90 \
-extfile data/tls.extВ любом из процессов прокси опрашивает tls.cert_file и перезагружает его автоматически, поэтому перезапуск не требуется.
Следующие шаги
Подключите вышестоящий сервер MCP к Managed Agent или Messages API.
Рекомендации по усилению защиты, ротация учётных данных и реагирование на взлом.
Диагностика проблем с подключением, TLS и маршрутизацией.
Was this page helpful?