多隧道

一条隧道不够时(不同域名走不同后端、具名隧道与临时隧道并存……),把每条隧道写成一个 cfd_tunnel {} 块。块里的 inject_listen 决定「这条隧道来的请求送进哪个 listen」; 注入进去的请求就是那个 listen 上的一条普通客户端连接,于是落到那个 listen 的 server {} 里。

nginx
http {
    # 模块级配置:对所有隧道生效
    cfd_tunnel_edge            region1.v2.argotunnel.com:7844;
    cfd_tunnel_global_bq_limit 64m;

    cfd_tunnel {                       # 具名隧道 A → 127.0.0.1:8080
        name           edge-a;
        credentials    /etc/nginx/cloudflared/a.json;
        inject_listen  127.0.0.1:8080;
    }

    cfd_tunnel {                       # 具名隧道 B → 127.0.0.1:8082
        name           edge-b;
        token_file     /etc/nginx/cloudflared/b.token;
        inject_listen  127.0.0.1:8082;
    }

    cfd_tunnel {                       # 临时隧道 → 127.0.0.1:8090
        name           quick-1;
        quick          on;
        inject_listen  127.0.0.1:8090;
    }

    cfd_tunnel {                       # 与 quick-1 同一个端口(允许)
        name           quick-2;
        quick          on;
        inject_listen  8090;            # 也可以只写端口号
    }

    server { listen 127.0.0.1:8080; server_name a.example.com; ... }
    server { listen 127.0.0.1:8082; server_name b.example.com; ... }
    server { listen 127.0.0.1:8090; ... }   # 随机域名只能靠默认 server 兜住
}

块内 12 条指令 ​

指令含义
name可选;只进日志(cfd_tunnel: [edge-a] …),不写就用 #序号
credentials凭据文件路径(与 quick / token / token_file 四选一)
quickon = 这条隧道启动时申请临时地址
token这条隧道的 token(等价 cfd_tunnel_token)
token_file这条隧道的 token 文件(等价 cfd_tunnel_token_file)
quick_service / quick_timeout覆盖模块级同名配置
inject_listen注入目标(ip:port 或只写端口);开了 remote_config 可以不写
inject_source_addr这条隧道的注入来源地址(不写继承模块级)
remote_configon = 接受边缘下发的远程配置
host_override注入请求的 Host 覆盖值(同时写 X-Forwarded-Host)
conn_index默认按 worker 自动分配

要点 ​

  • 允许多条隧道指向同一个端口。 注入期间临时改监听器标志位的窗口是同步的,并发安全; 但请求会落到该 listen 的默认 server,除非注入的 Host 命中某个 server_name。
  • 一条坏掉不拖累其他。 凭据读不出、注入目标不存在、临时隧道申请失败,都只跳过那一条 (error_log 带隧道名说明原因),其余隧道照常注册、照常服务。
  • 扁平写法仍然可用。 不写任何 cfd_tunnel {} 时,原来那组 cfd_tunnel_* 就是「那一条隧道」, 行为与 0.10.0 完全一致(日志文本也逐字节相同)。两种写法不能混用,nginx -t 直接失败。
  • 多 worker。 每条隧道在每个 worker 各建一条连接(connIndex 取 ngx_process_slot, 也可在块里用 conn_index 指定);临时隧道例外,每条都只由 0 号 worker 建。
  • 内存。 背压阈值是模块级的一份配置,但记账每条隧道独立(严格对齐 cloudflared: 它一个进程一条隧道、一份预算,A 隧道积压绝不会让 B 隧道拒流)。所以请求体缓冲的内存上界是 N × cfd_tunnel_global_bq_limit(默认 64m,3 条隧道就是 192m)—— 要压住就调小这个值。
  • 查临时地址。 cfd-quick-url -a 列出全部地址(每行一个 URL,不带隧道名); 要知道某个地址属于哪条隧道,在 error_log 里 grep 'cfd_tunnel: \[',带名字的行里名字与地址同行。

配置期会拒绝的几件事 ​

bash
nginx -t
  • 块与扁平写法混用(除非那些指令是「模块级 + 块内都允许」的,例如 inject_source_addr)。
  • 同一个块里凭据来源写了两个(credentials + token)。
  • 块里既没开 remote_config 又没写 inject_listen。
  • inject_listen 只写端口时,如果这个端口上存在多个监听地址(例如 127.0.0.1:8090 与 0.0.0.0:8090 同时存在),这条隧道会被判「有歧义」并单独跳过(只在日志里说明,不猜是哪 一个),其余隧道照常。

模块文档 · 对齐依据是 cloudflared 的源码与实测行为