---
title: 使用 Docker Compose 部署 MCP 通道
url: https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/deploy-compose
description: 使用 Docker Compose 在虛擬機器上安裝 MCP 通道堆疊。
---

<Note>
  「MCP tunnels」（MCP 通道）目前處於研究預覽階段。[申請存取權限](https://claude.com/form/mcp-tunnels)即可試用。
</Note>

本指南將[通道堆疊](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/concepts#components)（tunnel stack）以強化過的容器形式部署在單一主機上。相同的設定可以複製到多台主機以提高可用性。

## 開始之前

您需要：

* **一個通道（tunnel）。** 使用程式化存取時，若您未提供通道 ID，[設定元件](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/concepts#components)（setup component）會為您建立一個；若要改為附加到現有通道，請[在 Console 中建立它](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/console#create-a-tunnel)並記下通道 ID（`tnl_...`）。手動佈建一律從 Console 建立的通道開始。

* **讓主機向 Tunnels API 進行身分驗證的方式。**

  * **程式化存取（建議）。** 建立通道時開啟 **Set up programmatic access**，讓設定元件可以透過「Workload Identity Federation」（工作負載身分聯合）進行身分驗證。如果您讓設定元件建立通道，請改為直接在 Claude Console 的 [Workload identity](https://platform.claude.com/settings/workload-identity-federation) 頁面（`platform.claude.com/settings/workload-identity-federation`）上建立聯合規則。記錄聯合規則 ID（`fdrl_...`）以及您的組織 ID。
  * **手動。** 略過程式化存取。您將[從 Console 取得通道權杖](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/console#get-the-connection-details)、自行產生 CA 與伺服器憑證，並[在 Console 中註冊 CA](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/console#add-a-ca-certificate)。

* **一台已安裝 Docker 與 Docker Compose 的主機。** 手動流程還需要 `openssl`（1.1.1 或更新版本）。

* **對外網路連線**，從主機連至 `api.anthropic.com`（443 TCP）以及[通道邊緣](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/concepts#components)（tunnel edge）（7844 TCP 與 UDP）。請參閱完整的[網路需求](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/overview#network-requirements)。

* **一個或多個 MCP 伺服器**，正在執行且可從主機透過您將在 `routes` 下設定的位址連線。如果您還沒有，請[使用範例伺服器](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/deploy-compose#optional-use-a-sample-mcp-server)。

## 選用：使用範例 MCP 伺服器

如果您沒有可供測試的 MCP 伺服器，請使用這個最精簡的版本：

```bash
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 的參考做法。您有責任自行調整，以符合您組織的安全需求。

<Tabs>
  <Tab title="使用程式化存取">
    此路徑要求主機具備 OIDC 身分提供者（例如雲端虛擬機器中繼資料伺服器或 SPIFFE）。若沒有，請改用**不使用程式化存取**分頁。

    設定元件使用 Workload Identity Federation 來擷取通道權杖、產生 CA 與伺服器憑證，並向 Anthropic 註冊該 CA。

    <Steps>
      <Step title="準備部署目錄">
        ```bash
        mkdir -p mcp-tunnel/{config,data}
        cd mcp-tunnel
        sudo chown 65532:65532 data
        ```

        容器以非 root 的 UID `65532` 執行，且需要對 `data/` 的寫入權限。
      </Step>

      <Step title="撰寫 docker-compose.yaml">
        此 compose 檔案以 SHA-256 摘要固定映像檔版本、以非 root 身分搭配唯讀檔案系統執行每個容器、移除所有 Linux capabilities，並停用權限提升。

        ```bash
        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
            # 共用 proxy 的 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 伺服器](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/deploy-compose#optional-use-a-sample-mcp-server)，請將其附加為一個服務：

        ```bash
        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
        ```
      </Step>

      <Step title="佈建通道">
        設定識別碼。將 `TUNNEL_ID` 保持未設定，讓設定元件建立通道；若要附加到 [Console](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/console#create-a-tunnel) 中的現有通道，請設定它：

        ```bash
        # export TUNNEL_ID=tnl_...   # 設定此值以連接至現有的 tunnel
        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 指南](https://platform.claude.com/docs/zh-TW/manage-claude/workload-identity-federation#identity-providers)註冊簽發者、設定規則的 subject，並鑄造權杖；規則的 audience 必須與您鑄造時所請求的 audience 相符。

        執行設定元件：

        ```bash
        docker compose run --rm setup
        ```

        `setup init` 對 `data/` 具有冪等性：重新執行時會重複使用已儲存於其中的通道 ID 與 CA，絕不會建立第二個通道。只有在 `data/` 為空或 `TUNNEL_ID` 已變更時，才會產生並註冊新的 CA；在這種情況下，兩張有效憑證的上限會適用，因此若兩個位置都已佔滿，請先在 Console 中撤銷其中一張。

        若發生錯誤，請參閱[設定元件身分驗證失敗](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/troubleshooting#setup-component-authentication-failures)。

        取得您的通道網域並匯出，供後續步驟使用：

        ```bash
        export TUNNEL_DOMAIN=$(sudo cat data/tunnel-domain)
        echo "$TUNNEL_DOMAIN"
        ```

        <Note>
          Workload Identity Federation 權杖的效期很短（預設為 1 小時）且會自動過期；設定完成後沒有任何需要撤銷的項目。
        </Note>
      </Step>

      <Step title="撰寫 proxy 設定">
        `tunnel_domain` 為**必填**：[proxy](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/concepts#components) 會使用它從傳入的主機名稱中去除網域後綴，然後再於 `routes` 中查詢子網域。`routes` 是從子網域對應到上游 URL 的扁平映射，而非清單。

        ```bash
        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 伺服器](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/deploy-compose#optional-use-a-sample-mcp-server)；請以您自己的路由取代（或新增）。所有可用欄位請參閱 [proxy 設定](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/reference#proxy-configuration)參考文件。
      </Step>

      <Step title="啟動部署">
        ```bash
        export TUNNEL_TOKEN=$(sudo cat data/tunnel-token)
        docker compose up -d
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="不使用程式化存取">
    如果您未開啟 **Set up programmatic access**，或用於本機開發與測試，請使用此流程。此流程沒有 `setup` 服務。

    <Steps>
      <Step title="從 Console 取得通道權杖與網域">
        在通道詳細資訊頁面上，複製 **Domain**（其格式為 `abcd1234.tunnel.anthropic.com`），然後點擊 **Token** 旁的眼睛圖示以擷取通道權杖，並使用複製圖示將其複製。

        將兩者設定為 shell 變數，供本指南其餘部分使用：

        ```bash
        export TUNNEL_DOMAIN=YOUR_TUNNEL_DOMAIN_HERE
        export TUNNEL_TOKEN='eyJ...'
        ```
      </Step>

      <Step title="建立骨架並產生憑證">
        ```bash
        mkdir -p mcp-tunnel/{data,config}
        cd mcp-tunnel
        ```

        proxy 透過純 WebSocket 監聽 `:8080`；[內層 TLS](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/concepts#components)（inner TLS）交握使用這些憑證在該 WebSocket 串流**內部**進行。Anthropic 會依據您在 Console 中註冊的 CA 驗證內層交握。依照[憑證需求](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/reference#certificate-requirements)，伺服器憑證的 Subject Alternative Name（主體別名），即 SAN，必須包含 `*.<tunnel-domain>`。

        ```bash
        # 自簽 CA。明確指定擴充欄位，使其無論發行版 openssl.cnf 預設值為何，
        # 皆能符合憑證要求。
        openssl req -x509 -newkey rsa:2048 -nodes \
          -keyout data/ca.key -out data/ca.crt \
          -days 3650 -subj "/CN=mcp-tunnel-ca" \
          -addext "basicConstraints=critical,CA:TRUE" \
          -addext "keyUsage=critical,keyCertSign,cRLSign" \
          -addext "subjectKeyIdentifier=hash"

        # 伺服器憑證的擴充檔。使用 -extfile（而非僅限 OpenSSL 3.0+ 的
        # -copy_extensions）可讓此流程在
        # OpenSSL 1.1.x 上持續運作。
        cat > data/tls.ext <<EOF
        subjectAltName = DNS:${TUNNEL_DOMAIN},DNS:*.${TUNNEL_DOMAIN}
        authorityKeyIdentifier = keyid,issuer
        extendedKeyUsage = serverAuth
        EOF

        # 由 CA 簽署的伺服器憑證
        openssl req -newkey rsa:2048 -nodes \
          -keyout 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

        # 允許非 root 的 proxy 容器（UID 65532）從 bind mount 讀取金鑰。
        # 若未設定全域可讀位元，容器便無法開啟
        # 主機擁有的檔案。
        chmod 644 data/tls.key
        ```
      </Step>

      <Step title="在 Console 中註冊 CA 憑證">
        在通道詳細資訊頁面上，捲動至 **Certificates** 區段並點擊 **Add certificate**。使用 **Choose file** 直接上傳 `data/ca.crt`（該對話框接受 `.pem`、`.crt` 與 `.cer`），或貼上其內容：

        ```bash
        cat data/ca.crt
        ```

        一旦註冊了憑證，通道名稱旁的 **Needs certificate** 標記就會消失。請參閱[新增 CA 憑證](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/console#add-a-ca-certificate)。
      </Step>

      <Step title="撰寫 proxy 設定">
        `tunnel_domain` 為**必填**：proxy 會使用它從傳入的主機名稱中去除網域後綴，然後再於 `routes` 中查詢子網域。`routes` 是從子網域對應到上游 URL 的扁平映射，而非清單。

        ```bash
        cat > config/mcp-proxy.yaml <<EOF
        listen_addr: ":8080"
        log_level: info
        tunnel_domain: ${TUNNEL_DOMAIN}
        tls:
          cert_file: /data/tls.crt
          key_file: /data/tls.key
        routes:
          echo: http://hello-mcp:9000
        EOF
        ```

        `echo:` 路由指向[範例 MCP 伺服器](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/deploy-compose#optional-use-a-sample-mcp-server)；請以您自己的路由取代（或新增）。所有可用欄位請參閱 [proxy 設定](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/reference#proxy-configuration)參考文件。
      </Step>

      <Step title="撰寫 docker-compose.yaml">
        `network_mode: "service:mcp-proxy"` 設定會將 [cloudflared](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/concepts#components) 置於 proxy 的網路命名空間中，使 cloudflared 容器內的 `localhost:8080` 能連到 proxy。`--url http://localhost:8080` 旗標為 cloudflared 指定其轉送目標；若沒有該旗標，cloudflared 對傳入的請求沒有路由，會回傳 503。

        ```bash
        cat > docker-compose.yaml <<'EOF'
        services:
          cloudflared:
            image: cloudflare/cloudflared@sha256:6b599ca3e974349ead3286d178da61d291961182ec3fe9c505e1dd02c8ac31b0
            # --url 為必填：手動流程中不會推送任何 ingress 規則，
            # 因此若未指定，cloudflared 會對每個請求回傳 503。
            command: tunnel --no-autoupdate run --url http://localhost:8080
            environment:
              - TUNNEL_TOKEN
            # 共用 proxy 的 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 伺服器](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/deploy-compose#optional-use-a-sample-mcp-server)，請將其附加為一個服務：

        ```bash
        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
        ```
      </Step>

      <Step title="啟動部署">
        ```bash
        docker compose up -d
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

compose 檔案從主機環境讀取 `TUNNEL_TOKEN` 且沒有預設值，因此在每個新的 shell 中以及重新開機後都必須重新執行 export。

若要進行多虛擬機器部署，請將 `mcp-tunnel/` 目錄複製到每台主機、設定 `TUNNEL_TOKEN`，然後執行 `docker compose up -d`。在程式化流程中，`TUNNEL_TOKEN` 為 `$(sudo cat data/tunnel-token)`；在手動流程中，則是您從 Console 複製的值。相同的通道權杖與憑證可在所有副本上使用。

## 驗證部署

從 Anthropic 端呼叫[上游 MCP 伺服器](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/concepts#components)以進行端對端驗證：請參閱[使用通道化的 MCP 伺服器](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/overview#use-the-tunneled-mcp-servers)。使用[範例 MCP 伺服器](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/deploy-compose#optional-use-a-sample-mcp-server)時，路由後的 URL 為 `https://echo.<your-tunnel-domain>/mcp`。若驗證失敗，請參閱[疑難排解](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/troubleshooting)。

## 升級

請在 `mcp-tunnel/` 部署目錄內執行本節中的指令。

### 輪替通道權杖

使用程式化存取時，請遞增 `setup` 服務指令中的 `--token-version`、設定 Workload Identity Federation 識別碼、鑄造新的 OIDC JWT，然後重新執行設定元件：

```bash
# 編輯 docker-compose.yaml：將 setup 服務的
# --token-version 引數中的整數遞增（例如從 --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_...   # 若您的規則以工作區為範圍
# 依照您環境適用的 WIF 提供者指南重新產生 ANTHROPIC_IDENTITY_TOKEN
# （自安裝以來它應已過期）。
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 權杖。

不使用程式化存取時，請在 Console 的通道詳細資訊頁面上點擊 **Rotate token**，然後更新每台主機上的 `TUNNEL_TOKEN` 環境變數並重新啟動 cloudflared（`docker compose up -d cloudflared`）。

<Warning>
  點擊 **Rotate token** 會立即使目前的權杖失效。從那一刻起，到在每台主機上更新 `TUNNEL_TOKEN` 並重新啟動 cloudflared 之前，任何 cloudflared 發生重新啟動（當機、主機重新開機）的主機都無法重新連線。輪替後請儘速更新每台主機。
</Warning>

### 憑證更新

您有責任監控到期時間，並在伺服器憑證到期前進行更新。

使用程式化存取時：

```bash
docker compose run --rm setup renew-cert --output=dir:/data
```

CLI 引數會取代 `setup` 服務的 `command`（即 `init` 引數），但保留其 `entrypoint`，因此這會執行 `/setup renew-cert --output=dir:/data`。

<Tip>
  傳入 `--renew-before=720h`，可讓該指令在剩餘效期超過 30 天時不執行任何動作。這使其可以安全地依固定排程執行。
</Tip>

不使用程式化存取時，請使用您現有的 CA 簽署新的伺服器憑證（在 Console 中註冊的 CA 不會變更），並取代 `data/tls.crt`。如果您是在新的 shell 中執行，請先設定 `TUNNEL_DOMAIN`。

```bash
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
```

在任一流程中，proxy 都會輪詢 `tls.cert_file` 並自動重新載入，因此不需要重新啟動。

## 後續步驟

<CardGroup cols={2}>
  <Card title="使用通道化的 MCP 伺服器" icon="link" href="https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/overview#use-the-tunneled-mcp-servers">
    將上游 MCP 伺服器附加到 Managed Agent 或 Messages API。
  </Card>

  <Card title="安全性" icon="lock" href="https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/security">
    強化指引、憑證輪替與入侵應變。
  </Card>

  <Card title="疑難排解" icon="wrench" href="https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-tunnels/troubleshooting">
    診斷連線、TLS 與路由問題。
  </Card>
</CardGroup>
