tcptun

配置

一份 JSON 拓扑。

未知字段失败即关闭。native 载体、mux、resume、反向发布与路由都在同一份 FileConfig 中。

配置

JSON 拓扑、native 与 REALITY。

在一份配置里描述入站、出站和安全。先从 native 开始,再看 REALITY 与协议选择。

v0.5.0 · native + raw + reality

native + raw + reality + carrier.mode=auto

This is the recommended automatic stack in v0.5.0: one listen address, dual Reality carriers, QUIC preferred, TCP fallback, and optional resumable TCP streams. carrier.mode selects auto/tcp/quic while security.type stays reality. Without mux, Reality remains TCP-only.

Default pathQUIC-first carrier.mode=auto

Force TCP with carrier.mode=tcp, or force QUIC with carrier.mode=quic.

Protocolnative

Token auth, TCP/UDP tunnel semantics, reverse publish, and resumable logical streams.

Transportraw

Required base transport for automatic dual carriers. Do not stack ws / h2 / h3 in this mode.

Securityreality

Camouflage keys/SNI/dest. Pair with carrier.mode for auto, TCP-only, or QUIC-only selection.

Carriermode=auto

v0.5.0 generator path: Reality or TLS with carrier.mode=auto on one address; outbound carrier.prefer is adaptive by default.

Multiplexingmux.enabled

Mux enables dual-carrier and pooling. Optional mux.resume preserves eligible TCP flows across carrier replacement.

Automatic · v0.5.0

security.reality + carrier.mode="auto" + mux.enabled

Binds TCP and UDP on one address, prefers QUIC, falls back to Reality TCP with backoff, and probes to restore QUIC preference.

Forced TCP

carrier.mode="tcp"

Uses only the Reality TCP carrier (security.type stays reality). Choose this when UDP is intentionally unavailable.

Forced QUIC

carrier.mode="quic" + mux.enabled

Uses the dedicated QUIC pool without TCP fallback. The server listen port must be reachable over UDP.

Required stack

Automatic dual carriers need type=native, transport.type=raw, mux enabled, security.type=reality, and carrier.mode=auto (default for generators). Missing mux keeps ordinary TCP-only Reality.

carrier.mode

Set carrier.mode to auto (QUIC-first with TCP fallback), tcp, or quic. security.type remains reality in all three cases. quic and auto require mux.enabled.

One address, two sockets

The inbound binds TCP and UDP to the same host:port. Clients race the same address over both carriers without a second listen entry.

QUIC first, TCP fallback

Outbounds prefer the Reality QUIC carrier. When UDP is blocked or unhealthy, they fall back to Reality TCP with jittered exponential backoff, then probe to restore QUIC preference.

Shared camouflage

Both carriers share the same REALITY keys, short IDs, SNI, and dest. The camouflage destination should support HTTPS over TCP and HTTP/3 over UDP.

Scope of selection

TCP streams, UDP relay, and reverse carriers follow the same automatic carrier policy when carrier.mode=auto.

Escape hatches

carrier.mode=tcp forces Reality TCP only. carrier.mode=quic forces the dedicated QUIC pool without TCP fallback. security.type remains reality.

Structure

Top-level fields include log, resources, inbounds, outbounds, route, and dns. Unknown fields are rejected; resources.resumable_buffer_budget controls the shared replay-buffer budget.

Address

inbound.address and outbound.address are both host:port arrays. Multiple addresses race as candidate entry points; use balance for independent nodes.

References

Components link through tags; via chains and balance members are checked for missing refs and cycles.

Startup

Load → Validate → Compile → Start. Listening begins only after validation succeeds.

FileConfig route

路由规则

route.default_outbound 必填。rules 按声明顺序执行,第一条命中的规则选定其 outbound。mixed、socks5 与平台 TUN 的每条流都走这套路由器。native 入站在 route_mode 设为 rules 之前,把已接受的流送到默认出站。

先匹配先生效

规则保持文件中的顺序。命中后停止继续查找。一条只写了 outbound 的规则会匹配剩余的全部流,并挡住后面的规则。

条件组合

inbound、network、principals、app 与目的地条件组用 AND 组合。同一数组内的值是 OR。domains、domain_regexes、domain_suffixes、ips、ip_cidrs 与 ip_ranges 组成同一个目的地条件组:任一命中即可。空的条件组不增加约束。

规则在哪里生效

mixed、socks5 与平台 TUN 始终使用编译后的路由器。native 入站省略 route_mode 或设为 default 时,每条已接受的流都走 default_outbound。route_mode 为 rules 时,按每条 TCP flow 和每个固定目标 UDP association 选择。应用身份由嵌入方提供,不会写入 native、mux 或 UDP 帧。带 app 的规则在缺少该身份时不匹配。

blackhole

type 为 blackhole 的出站拒绝 TCP,并丢弃 UDP。该流不会继续转到 direct 或其他出站。

DNS 与路由器

dns.outbound 把拦截到的 DNS 固定到一个同时支持 TCP 与 UDP 的出站,并绕过路由规则。该出站不可用时,DNS 失败即关闭。启用 dns.fake_ip.enabled 后,A 与 AAAA 使用配置的 fake-IP 范围(省略时为 198.18.0.0/15 与 fc00::/18),之后发往这些地址的流会在路由选择前还原成域名。其他 DNS 报文仍走配置的路由。dns.strategy 为 prefer_ipv4、prefer_ipv6、ipv4_only 或 ipv6_only。TUN 上 TCP 或 UDP 53 端口的 DNS 进入同一路由器,除非被固定到 dns.outbound。

JSON 契约

未知字段会被拒绝。匹配项就是本页列出的这些数组。geosite: 与 geoip: 前缀会被拒绝。一条 URI 只携带一个隧道端点;路由规则和 via 链留在 JSON 里。via 把该出站的拨号串起来,并会做环检查。Android 应用使用 Full Tunnel,不编辑这些规则。

route

default_outbound
必填的出站标签。未命中的流量使用它。标签必须存在。
rules
有序规则数组。空数组表示每条流都走 default_outbound。
rules[].outbound
规则命中时选定的出站标签,必填。

匹配项

inbound
入站标签,OR。留空匹配每个入站。每个标签都必须存在。
network
tcp 与/或 udp,OR。留空则不按网络过滤。
domains
精确主机名,OR。比较前会把主机名转成小写,并去掉末尾一个点。
domain_suffixes
在同一主机名上做 OR。example.com 匹配 example.com,以及以 .example.com 结尾的主机名。
domain_regexes
Go 正则表达式,OR,作用在同一规范化主机名上。
ips
精确 IP 地址,OR。比较前会把 IPv4-mapped IPv6 还原成 IPv4。
ip_cidrs
CIDR 前缀,OR。支持 IPv4 与 IPv6。
ip_ranges
闭区间 start-end,OR。两端必须是同一地址族,且 start 不晚于 end。示例:192.168.1.10-192.168.1.20。

app

app
仅当嵌入方提供身份时匹配。缺少身份则跳过该规则。ids、id_prefixes、platforms、attributes 至少要有一项。
app.ids
精确 ID,OR,区分大小写。Android 集成通常使用包名。
app.id_prefixes
ID 前缀,OR,区分大小写。
app.platforms
平台名,OR,比较时不区分大小写。示例:android。
app.attributes
键到值列表的映射。键会做大小写归一。每个键必须命中其中一个值。ids、前缀、平台与每个属性键用 AND 组合。

Principal

users[].principal
native 入站用户上的名字。仅 ASCII 字母、数字、'.'、'_'、'-' 或 '@',最多 128 字节。它与 users[].id 分开。
route_mode
写在 native 入站上:省略或 default 保持 default_outbound。rules 让该入站使用编译后的路由器。
principals
这些名字的 OR 列表。规则必须把 inbound 指到 route_mode 为 rules 的 native 入站,且每个名字都存在于这些用户上。

可运行的 route 对象

这些对象在 v0.5.0 上可以通过 tcptun config check。分流示例仍需真实的 REALITY 公钥;示例目录会在浏览器里填入。

打开路由分流示例

客户端分流 · client-route-split.json

ads.example 走 blackhole,RFC1918 前缀与 internal.example 走 direct,其余流走 native 出站。运行 config check 前请换上真实的 REALITY 公钥。

{
  "log": { "level": "info" },
  "inbounds": [
    {
      "tag": "local",
      "type": "mixed",
      "address": ["127.0.0.1:1080"],
      "network": ["tcp", "udp"]
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "type": "native",
      "address": ["proxy.example.com:9443"],
      "token": "change-me",
      "transport": { "type": "raw" },
      "carrier": { "mode": "auto", "prefer": "quic", "udp_mode": "auto" },
      "mux": { "enabled": true },
      "security": {
        "type": "reality",
        "server_name": "example.com",
        "public_key": "REPLACE_WITH_SERVER_PUBLIC_KEY",
        "short_id": "abcd1234",
        "spider_x": "/"
      }
    },
    { "tag": "direct", "type": "direct" },
    { "tag": "block", "type": "blackhole" }
  ],
  "route": {
    "default_outbound": "proxy",
    "rules": [
      { "domain_suffixes": ["ads.example"], "outbound": "block" },
      { "ip_cidrs": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"], "outbound": "direct" },
      { "domain_suffixes": ["internal.example"], "outbound": "direct" }
    ]
  },
  "dns": {}
}
应用身份 · client-route-app.json

普通 CLI 流没有应用身份,所以两条规则都不会命中,流量走 direct。嵌入方在 Android 上返回 com.example.reader 且属性 profile=work 时选择 direct。以 com.example.game. 开头的 ID 选择 block。

{
  "log": { "level": "info" },
  "inbounds": [
    {
      "tag": "local",
      "type": "mixed",
      "address": ["127.0.0.1:1080"],
      "network": ["tcp", "udp"]
    }
  ],
  "outbounds": [
    { "tag": "direct", "type": "direct" },
    { "tag": "block", "type": "blackhole" }
  ],
  "route": {
    "default_outbound": "direct",
    "rules": [
      {
        "app": {
          "ids": ["com.example.reader"],
          "platforms": ["android"],
          "attributes": { "profile": ["work"] }
        },
        "outbound": "direct"
      },
      {
        "app": { "id_prefixes": ["com.example.game."] },
        "outbound": "block"
      }
    ]
  },
  "dns": {}
}
native 入站上的 principal · server-route-principal.json

remote-access 使用 route_mode rules。已认证用户 alice 可以通过 direct 打开这两个前缀上的 TCP/UDP。其余已接受的流走 deny。这里只展示路由字段,并不导出家庭局域网。

{
  "log": { "level": "info" },
  "inbounds": [
    {
      "tag": "remote-access",
      "type": "native",
      "address": ["0.0.0.0:9443"],
      "network": ["tcp", "udp"],
      "users": [{ "principal": "alice", "id": "change-me" }],
      "transport": { "type": "raw" },
      "mux": { "enabled": true },
      "route_mode": "rules"
    }
  ],
  "outbounds": [
    { "tag": "direct", "type": "direct", "network": ["tcp", "udp"] },
    { "tag": "deny", "type": "blackhole" }
  ],
  "route": {
    "default_outbound": "deny",
    "rules": [
      {
        "inbound": ["remote-access"],
        "principals": ["alice"],
        "network": ["tcp", "udp"],
        "ip_cidrs": ["192.168.50.0/24", "fd12:3456:789a::/64"],
        "outbound": "direct"
      }
    ]
  },
  "dns": {}
}

Native

Low-overhead private tunnel

Supports TCP / UDP and mux, with transport options raw / ws / h2 / h3. Server users[].id and client token must match.

Server inboundusers[].id
Client outboundtoken

Auth

Server users[].id and client token must match.

Address

address is a host:port array. Multiple addresses race as candidate entry points for the same service; they are not balance.

v0.3.0 carrier.mode=auto

native + raw + mux + security.type=reality + carrier.mode=auto prefers QUIC, falls back to TCP, and shares one camouflage identity on both carriers.

Resumable TCP

mux.resume=true on both carrier.mode=auto peers can preserve an eligible TCP logical stream across carrier replacement (v0.3.0+).

Throughput

Prefer native + raw + mux. Forced TLS / REALITY / ws / h2 / h3 add flexibility but cost more.

Reverse publish

Server publish + client expose can hang NAT-side TCP/UDP services on edge listeners (requires mux).

Native QUIC

native + raw + reality + carrier.mode=quic

Forced QUIC is still the same layers: native is the tunnel protocol, raw is the transport, and security.type=reality stays REALITY. Select the dedicated QUIC pool with carrier.mode=quic and mux.enabled. There is no TCP fallback.

Best fortcptun on both ends

Carry TCP streams and UDP DATAGRAMs together without managing TLS certificates.

Protocolnative

Handles token auth, TCP / UDP tunnel semantics, and reverse publish.

Transportraw

Required base transport for QUIC mode; do not stack ws / h2 / h3.

Securityreality

Protects the handshake with REALITY keys and site parameters; no cert deploy needed.

Carriermode=quic

Uses a dedicated QUIC pool for streams and UDP DATAGRAMs. Requires mux.enabled.

server-native.json
{
  "log": { "level": "info" },
  "inbounds": [
    {
      "tag": "server",
      "type": "native",
      "address": ["0.0.0.0:9443"],
      "network": ["tcp", "udp"],
      "users": [{ "id": "change-me" }],
      "transport": { "type": "raw" },
      "mux": { "enabled": true }
    }
  ],
  "outbounds": [
    { "tag": "direct", "type": "direct" }
  ],
  "route": { "default_outbound": "direct", "rules": [] },
  "dns": {}
}
Minimal topology

The server exposes a native inbound; the client forwards a local mixed inbound to a native outbound. Replace the sample credentials and addresses to run.

Fields

Common field overview.

Common fields

tagboth
Unique identifier referenced by routes.
typeboth
"native".
addressboth
host:port string array; outbounds may list multiple candidate entry points.
networkboth
tcp / udp, combinable.
transportboth
Only type / path (raw / ws / h2 / h3).
securityboth
tls or reality. Carrier path is carrier.mode=auto|tcp|quic; all security parameters live here.
muxboth
mux.enabled is required and must be true when mux is present; omit mux to disable. Pool parameters are mainly on the client.

Server

addressserver
Listen address list, e.g. ["0.0.0.0:9443"].
users[].idserver
Auth credential matching the client token.
publishserver
Reverse publish: service + address, optional network=tcp|udp.
security.cert/keyserver
Required for TLS inbounds; REALITY uses key fields instead of cert/key.

Client

addressclient
Remote entry points; multiple candidate host:port values are allowed.
tokenclient
Required; matches server users[].id.
security.server_nameclient
SNI for TLS/QUIC.
exposeclient
Reverse publish: service + target, optional network=tcp|udp.
carrier.modeboth
auto / tcp / quic. auto and quic require mux.enabled.
carrier.preferclient
auto only: adaptive / quic / tcp. Official auto examples use quic.
carrier.udp_modeclient
auto and quic: reliable / auto / datagram.
carrier.*_receive_windowboth
QUIC receive windows; stream max 16 MiB, connection max 64 MiB.
mux.max_sessionsclient
Connection pool cap, 1–32, default 4.
mux.max_streams_per_sessionclient
Per-connection stream cap, 1–4096.
mux.warm_sparesclient
Warm idle connections; must be less than max_sessions.
mux.resumeboth
v0.3.0: preserve eligible native TCP logical streams across carrier replacement when carrier.mode=auto.
mux.resume_timeoutboth
Recovery window: default 15s; explicit 100ms–5m.
mux.resume_buffer_sizeboth
Per-direction replay buffer: default 4 MiB; explicit 64 KiB–64 MiB.

Mux / QUIC

Enable mux for short-connection workloads. Prefer native + raw + mux for peak throughput.

How to enable

Set mux.enabled=true. enabled is required and must be true; omit the mux field to disable it.

TCP mux

Reuses physical connections. Unreachable targets are not reported as success to the local proxy early.

Automatic carriers

native + raw + mux + security.type=reality + carrier.mode=auto prefers QUIC, falls back to Reality TCP with bounded backoff, then probes to restore QUIC preference.

Resumable streams

mux.resume keeps eligible native TCP logical streams alive while an automatic Reality carrier is replaced. Enable matching settings on both peers.

QUIC

carrier.mode=quic uses a UDP/QUIC connection pool and requires native + raw + mux.enabled; security.type may be tls or reality.

UDP

reliable uses streams; auto prefers DATAGRAM with fallback; datagram does not degrade. DATAGRAM supports fragmentation, recovery, and adaptive FEC.

mux snippet
"mux": {
  "enabled": true,
  "max_sessions": 4,
  "max_streams_per_session": 128,
  "warm_spares": 1
}

v0.3.0 continuity

Resumable TCP logical streams

Add resume to matching carrier.mode=auto mux blocks to preserve an eligible TCP logical stream while its physical QUIC or TCP attachment is replaced.

Exact scope

native + raw + security.type=reality + carrier.mode=auto + mux only. UDP, reverse publish, and forced tcp/quic-only modes are not resumable.

Both peers

Set mux.resume=true on both endpoints running v0.3.0+. There is no silent downgrade when only one peer enables it.

Bounded recovery

resume_timeout defaults to 15s (100ms–5m). resume_buffer_size defaults to 4 MiB (64 KiB–64 MiB).

One server process

The registry is process-local. Use one unique outbound address whose TCP and UDP paths reach the same server process.

matching endpoint mux block
"carrier": { "mode": "auto" },
"mux": {
  "enabled": true,
  "resume": true,
  "resume_timeout": "15s",
  "resume_buffer_size": 4194304
}

Reverse publish

Hang NAT-side TCP/UDP services on tunnel server listen ports. Configure publish on the server and expose on the client.

Protocol scope

Only native + raw, and mux must be enabled.

Pairing rules

Server publish and client expose service names must match, and network must match as well (default tcp).

Security boundary

The client local target is not sent to the server; the server can only open allowlisted services.

QUIC requirements

QUIC reverse publish needs matching TLS or REALITY plus carrier.mode=quic (or auto) on both ends; TLS servers need cert/key.

Workflow

Generate → validate → start.

generate01

Generate a pair

Writes server.json and client.json.

tcptun config native --server proxy.example.com --port 9443
check02

Validate

Does not listen; useful after editing a config.

tcptun config check --config server.json
quic03

Generate a QUIC pair

Writes matching REALITY configs with carrier.mode=quic and mux enabled.

tcptun config native --quic --server proxy.example.com --port 9443
run04

Start

Start the server first, then the client.

tcptun --config server.json
tcptun --config client.json
uri05

Export URI

Exports URIs from tunnel outbounds; multiple addresses become multiple URIs.

tcptun uri export --config client.json --output client.uri

REALITY

REALITY and REALITY QUIC

Configured under security for native + raw. Pair with carrier.mode for auto, TCP-only, or QUIC-only.

rawX25519

raw only

transport must be raw and cannot be combined with ws / h2 / h3.

No stacked TLS

Plain reality cannot stack with security.type=tls; choose exactly one security type.

Supported endpoints

Works with native tunnel endpoints. mixed and socks5 are unsupported for URI export.

Key pairing

Server private_key pairs with client public_key; short_id must match on both ends.

native auto (v0.3.0)

On native + raw + mux + security.type=reality + carrier.mode=auto, dual carriers enable QUIC-first with TCP fallback. Without mux, Reality stays TCP-only.

Forced modes

carrier.mode=tcp forces Reality TCP only. carrier.mode=quic forces the dedicated QUIC pool (no TCP fallback).

Server

type
"reality".
private_key
X25519 private key (base64url).
server_names
Allowed SNI list.
short_ids
Allowed short ids (hex).
dest
Camouflage target, e.g. example.com:443.
max_time_diff
Optional clock skew, default 30s.

Client

type
"reality".
public_key
Server public key.
server_name
SNI; must be in server_names.
short_id
A single short id.
spider_x
Optional path, default /.
native + raw + reality + carrier.mode=auto
{
  "log": { "level": "info" },
  "inbounds": [
    {
      "tag": "server",
      "type": "native",
      "address": ["0.0.0.0:9443"],
      "network": ["tcp", "udp"],
      "users": [{ "id": "change-me" }],
      "transport": { "type": "raw" },
      "security": {
        "type": "reality",
        "private_key": "REPLACE_WITH_SERVER_PRIVATE_KEY",
        "server_names": ["example.com"],
        "short_ids": ["abcd1234"],
        "dest": "example.com:443",
        "max_time_diff": "30s"
      },
      "carrier": { "mode": "auto" },
      "mux": { "enabled": true }
    }
  ],
  "outbounds": [
    { "tag": "direct", "type": "direct", "network": ["tcp", "udp"] }
  ],
  "route": { "default_outbound": "direct", "rules": [] },
  "dns": {}
}

Generate a REALITY pair

Writes paired server.json and client.json; run tcptun uri export if you need URIs.

tcptun config native --server proxy.example.com --port 9443 --server-name example.com --dest example.com:443

native + REALITY

Generates matching REALITY configs for native on both ends.

tcptun config native --server proxy.example.com --port 9443 --server-name example.com --dest example.com:443

native + REALITY QUIC

Generates matching REALITY configs with carrier.mode=quic and mux enabled.

tcptun config native --quic --server proxy.example.com --port 9443 --server-name example.com --dest example.com:443

Validate and start

Validate keys and fields first, then start.

tcptun config check --config server.json && tcptun --config server.json
Note

Native + raw + mux + security.type=reality with carrier.mode=auto is automatic QUIC-first with TCP fallback. Force a single carrier with carrier.mode=tcp or carrier.mode=quic. tcptun config native --quic generates the latter. Legacy security.type=reality-quic / mux.mode=quic aliases are not the current scheme.

Compare

native 隧道协议

隧道端点是 native。mixed 与 socks5 仍用于本地代理跳。

协议凭证互操作默认安全Mux适合
nativetoken ↔ users[].idtcptun onlyraw + REALITYPrivate mux, recommendedThroughput / reverse publish
{
  "tag": "proxy",
  "type": "native",
  "address": ["proxy.example.com:9443"],
  "token": "change-me",
  "transport": { "type": "raw" },
  "mux": { "enabled": true }
}

tcptun config native --server … --port …