9. Outbound Protocol Configuration#
Outbound protocols determine how Link1 ultimately connects to a target or upstream service. All static outbound nodes are defined in proxies; dynamic nodes from subscriptions, files, inline definitions, or WARP are defined in proxy-providers.
This chapter explains each protocol as “an egress type the user needs to configure,” instead of only listing fields. When reading about each protocol, consider four things:
- What problem it solves: a regular proxy, encrypted proxy, L3 VPN, enterprise VPN, or special egress.
- How a connection flows: whether Link1 uses TCP, UDP, QUIC, TLS, WireGuard, OpenVPN, or an enterprise proprietary protocol to reach the upstream.
- What behavior each field changes: how authentication, certificates, transport layer, DNS, UDP, routing, and performance parameters affect each part of the connection.
- Common pitfalls: which fields do not belong to this protocol, and which fields look similar but mean different things.
If you are configuring a protocol for the first time, we recommend copying the example in this chapter first and changing only the account, address, port, password/key provided by your service provider. After it works, adjust advanced fields as needed.
Common Outbound Node Structure#
proxies:
- name: node-name
type: socks5
server: 127.0.0.1
port: 1080
Common fields:
| Field | Meaning | Actual effect |
|---|---|---|
name | Node name | Must be unique; can be referenced by policy groups and rules |
type | Protocol type | Determines which outbound protocol implementation to use |
server / address | Remote address | Most protocols use server; a few protocols are compatible with address |
port | Remote port | 0 is usually treated as not configured |
dialer-proxy | Front proxy | Dial through another node first, then connect to this node’s remote endpoint |
interface-name | Bind network interface | Controls the egress interface in multi-NIC/router scenarios |
routing-mark | Linux mark | Used with policy routing |
ip-version | IP selection policy | Controls whether resolution/dialing prefers IPv4 or IPv6 |
tfo | TCP Fast Open | Can reduce handshake latency for supported TCP protocols |
mptcp | Multipath TCP | Enables Multipath TCP on supported platforms/protocols |
udp | UDP support | Affects UDP forwarding, games, QUIC, DNS, and more |
Not every protocol supports all common fields. Link1 rejects unsupported fields during configuration compilation.
How Common Fields Affect Data Flow#
These fields do not belong to a single protocol. They affect how the “Link1 to upstream” segment is dialed:
| Field group | Fields | How users should understand it |
|---|---|---|
| Naming and references | name, type | name is the name referenced by rules and policy groups; type determines which protocol all following fields are interpreted as. |
| Remote location | server, address, port, port-range, ports | Determines where the upstream is; ports/port-range usually indicate port hopping or protocol-specific capabilities, not ordinary backup ports. |
| Front chain | dialer-proxy | The current node does not connect to the upstream directly. It goes through another node first. Commonly used for “connect to a local proxy first, then connect to an enterprise VPN/remote node.” |
| Egress selection | interface-name, routing-mark, ip-version | Controls which network interface, policy route, and IP family the underlying TCP/UDP traffic uses. |
| TCP capabilities | tfo, mptcp | Only affects protocols that use TCP. It may have no effect if the system or upstream does not support it. |
| UDP capability | udp | Affects whether UDP traffic such as DNS, QUIC, games, voice, WireGuard/MASQUE can use this node. |
dialer-proxy is the easiest field to misunderstand. It is not a “backup node for this node.” It means “when connecting to this node’s server, go through another outbound first.” For example, if a trojan node uses dialer-proxy: PROXY, Trojan first establishes the underlying connection to its own server:port through the PROXY group. After the protocol handshake completes, this Trojan node still handles final application traffic using its own protocol.
Protocol Overview#
type | Category | How it works | When to choose it | Main risks/notes |
|---|---|---|---|---|
direct | Special egress | Link1 connects directly to the target IP/domain | LAN, domestic sites, targets that do not need a proxy | Still goes through Link1; only the final connection is direct |
reject | Special egress | Link1 rejects the connection directly | Ads, malicious domains, blocked access | May cause applications to retry repeatedly |
dns | Special egress | Hands the connection to the built-in DNS resolver | DNS rules or internal DNS forwarding | Rarely written manually by regular users |
http | Explicit proxy | Link1 connects to an HTTP proxy, and the upstream then CONNECTs/forwards to the target | Corporate proxy, upstream HTTP proxy | HTTP upstreams usually do not carry UDP |
socks / socks5 | Explicit proxy | Link1 connects to a SOCKS5 upstream, and the SOCKS5 server connects to the target | Local proxy chains, simple upstreams | UDP depends on SOCKS5 UDP associate |
ssh | Tunnel | Logs in to SSH first, then forwards TCP through an SSH channel; UDP requires udpgw | You have an SSH server or bastion host | Host key verification is important |
vmess | Encrypted proxy | VMess user identity + optional TLS/WS/H2/gRPC/KCP and other transports | Compatible with legacy VMess nodes | alterId, transport layer, and TLS must match the server |
vless | Encrypted proxy | VLESS user identity + TLS/REALITY/Vision/transport layer | REALITY, Vision, XUDP nodes | A wrong flow, REALITY, or SNI value will cause handshake failure |
trojan | Encrypted proxy | Trojan password authentication, usually disguised as a TLS service | Simple TLS proxy | Certificate/SNI and password must all match |
ss / shadowsocks | Encrypted proxy | AEAD/2022 encrypted proxy, with optional plugin | Lightweight proxy, routers | cipher/password/plugin must match the server |
ssr / shadowsocksr | Encrypted proxy | SS + obfs/protocol compatibility extensions | Legacy SSR nodes | Many parameter combinations; subscription fields may be inconsistent |
shadowtls | Wrapper/disguise | Wraps traffic in a ShadowTLS TLS disguise, then carries subsequent traffic | Requires a ShadowTLS upstream | Version, password, and SNI must match |
tuic | QUIC proxy | QUIC-based authentication and UDP/TCP forwarding | Mobile networks, UDP scenarios | Experience will be poor if UDP is blocked |
hysteria | QUIC proxy | Hysteria v1 with bandwidth and port hopping parameters | Legacy HY1 nodes | v1/v2 fields cannot be mixed |
hysteria2 / hy2 | QUIC proxy | Hysteria2 password authentication + QUIC + optional Salamander obfuscation | High-performance proxy, mobile networks | obfs and certificate parameters must match |
juicity | QUIC proxy | QUIC proxy with UUID/password authentication | Juicity server | Congestion control and certificate parameters affect connectivity |
naive | HTTP/2/3 proxy | NaiveProxy-style HTTP/2/3 upstream | Caddy/NaiveProxy ecosystem | Essentially an authenticated HTTP/2/3 upstream |
snell | Encrypted proxy | Snell PSK authentication; v4/v5 support TCP, v3/v4/v5 support UDP | Snell server | Version and obfs must match |
gost-relay | Proxy protocol | Link1 connects to a GOST relay server and sends a relay CONNECT request | GOST relay TCP upstreams and chained hops | The first version is TCP-only; no UDP/TLS/mTLS/mux |
anytls | Encrypted proxy | AnyTLS password authentication + TLS tunnel | AnyTLS server | SNI/certificate/fingerprint still need to be handled |
brook | Proxy protocol | Multiple Brook server transports, with optional WS/WSS/QUIC/mask | Brook server | network determines whether many fields are available |
mieru | Proxy protocol | Mieru user authentication + TCP/UDP transport | Mieru server | transport, multiplexing, and handshake must match |
trusttunnel | Tunnel | Lightweight tunnel with HTTP/2 ALPN, supports UDP over stream | TrustTunnel server | ALPN must include h2 |
sudoku | Extended protocol | Password/key + AEAD + padding/table/http-mask | Sudoku server | padding/table/mask parameters must match the server |
wireguard / wg | L3 tunnel | Establishes a WireGuard virtual Layer 3 link | WARP, self-hosted WG, enterprise tunnels | allowed-ips has tunnel routing semantics; it is not a rule |
masque | HTTP/3 tunnel | Builds a tunnel through HTTP/3 MASQUE CONNECT-UDP/IP | WARP MASQUE, services that support MASQUE | QUIC, URI, certificate, and MTU all affect connectivity |
tailscale | Mesh/VPN | Logs in to Tailnet/Headscale and uses an exit node or routes | Device mesh networking, LAN access | Affected by control-plane policies and node authorization |
openvpn | VPN | OpenVPN control-plane handshake + userspace netstack forwarding | Enterprise OpenVPN, traditional VPN | DNS/routes come from push or configuration; it cannot be treated as a regular proxy |
atrust | Enterprise VPN | Logs in to ATrust, obtains enterprise routes/DNS, then acts as an egress | Sangfor/enterprise access | Authentication policy, CAPTCHA, and device binding have major impact |
feilian | Enterprise VPN | Logs in to Feilian and selects a VPN gateway | Feilian enterprise network | Gateway selection and session persistence are critical |
easyconnect | Enterprise VPN | Logs in to EasyConnect, then acts as an enterprise VPN egress | EasyConnect enterprise network | Server versions/policies vary significantly |
warp | WARP provider | Not used directly as a leaf; materializes WireGuard/MASQUE nodes through a provider | Cloudflare WARP egress | Must be written in proxy-providers, not in proxies |
Protocol configuration can often be inferred from upstream materials:
- If you receive “proxy address + port + username/password,” it is usually
http,socks5,naive, or an enterprise VPN.
- If you receive “UUID + TLS/REALITY/WS/gRPC,” it is usually
vmess/vless.
- If you receive “password + TLS 443,” it may be
trojan,hysteria2,tuic, oranytls.
- If you receive “private key/public key/allowed ips,” it is usually
wireguardor WARP manual.
- If you receive
.ovpn,ca.crt,client.crt, ortls-auth, it is usuallyopenvpn.
Which Outbound Should I Choose?#
If you are not “designing your own server protocol” but entering an account someone gave you into Link1, choose the protocol based on the provider’s materials first. Do not change the type based on guesswork. The table below gives selection suggestions from user scenarios:
| Scenario | Protocols to check first | Why | What not to do at first |
|---|---|---|---|
| Your company provides an HTTP/SOCKS proxy | http, socks5 | Few fields, usually only address, port, username, and password. | Do not mistakenly write it as HTTP Engine. HTTP Engine is a content rewriting module, not an upstream HTTP proxy. |
| Airport/subscription nodes | vmess, vless, trojan, ss, hysteria2, tuic | These are common proxy node types, and subscriptions usually already include protocol fields. | Do not casually change network, tls, sni, flow, or obfs; they must match the server. |
| You have your own SSH server | ssh | No dedicated proxy service needs to be deployed; TCP can be forwarded through SSH channels. | Do not treat SSH as a high-performance UDP proxy; UDP requires udpgw support. |
| High performance, mobile networks, UDP required | hysteria2, tuic, wireguard, masque | QUIC/WireGuard-like protocols are better suited for UDP and network switching. | If the local network blocks UDP, check UDP reachability first. Do not only change the password or certificate. |
| Cloudflare WARP egress | proxy-providers.type=warp | WARP generates WireGuard/MASQUE candidate nodes and is naturally a provider. | Do not write proxies[].type=warp. |
| Enterprise VPN/LAN access | openvpn, atrust, feilian, easyconnect, tailscale | These protocols bring LAN routes, enterprise DNS, or device login state. | Do not treat it only as a “proxy port”; DNS, routes, and account state must all be considered. |
| Direct connection for LAN/domestic sites | DIRECT or direct | The target does not need a proxy, and direct connection has the lowest latency. | Do not put all traffic into a remote node. LAN addresses should be direct first. |
| Ad/malicious domain blocking | REJECT or reject | Rejects connections directly and reduces meaningless outbound traffic. | Do not make the blocking scope too broad, or applications may keep retrying or malfunction. |
A simple decision tree:
Did you receive a ready-made node/subscription?
Yes -> Fill fields according to the node type; do not change the protocol
No -> Is it an enterprise VPN/intranet account?
Yes -> openvpn / atrust / feilian / easyconnect / tailscale
No -> Is it WARP?
Yes -> proxy-providers.type=warp
No -> Is it only an upstream proxy port?
Yes -> http / socks5 / naive
No -> choose based on the self-hosted server protocol
TLS, Transport, and Extension Fields#
Many protocols share TLS fields:
tls: true
skip-cert-verify: false
servername: example.com
sni: example.com
alpn: [h2]
client-fingerprint: chrome
Practical effects:
tls=trueenables TLS wrapping or the protocol's TLS mode.
skip-cert-verify=trueskips certificate verification and reduces security.
servername/snichanges the domain name used in the TLS handshake.
alpnaffects HTTP/2, HTTP/3, or protocol negotiation.
client-fingerprintchanges the ClientHello fingerprint and requires protocol support.
Common transports for VMess/VLESS/Trojan:
network: ws
ws-opts:
path: /ws
headers:
Host: example.com
network | Related fields | Effect |
|---|---|---|
tcp or empty | None or protocol default fields | Plain TCP transport |
http | http-opts | HTTP camouflage |
ws | ws-opts | WebSocket transport |
h2 | h2-opts | HTTP/2 transport |
grpc | grpc-opts | gRPC transport |
kcp | kcp-opts | KCP transport |
xhttp | xhttp-opts | XHTTP-compatible transport, for VMess/VLESS/Trojan-like nodes that support xHTTP |
REALITY:
reality-opts:
public-key: xxxxx
short-id: abcd
fingerprint: chrome
ECH:
ech-opts:
enable: true
mode: grease
query-server-name: example.com
SMUX:
smux:
enabled: true
protocol: smux
max-connections: 4
min-streams: 4
max-streams: 32
How to read transport sub-configuration fields#
| Sub-configuration | Common fields | Practical effect |
|---|---|---|
http-opts | method, path, headers | Used for HTTP camouflage transport; path/header must match the server. |
ws-opts | path, headers, max-early-data, early-data-header-name, v2ray-http-upgrade | WebSocket path, Host, and early data behavior; most commonly used with CDN/reverse proxy setups. |
h2-opts | host, path | authority/path for HTTP/2 transport. |
grpc-opts | grpc-service-name, grpc-user-agent | gRPC service name and UA; a service name mismatch looks like "the port is reachable, but the protocol is not." |
kcp-opts | seed, header-type, mtu, tti, uplink-capacity, downlink-capacity, congestion, write-buffer, read-buffer | KCP transport parameters; server support is required, and wrong parameters can cause handshake or performance issues. |
ss-opts | enabled, method, password | Trojan's Shadowsocks extension, not a regular ss node. |
plugin / plugin-opts | Plugin name and plugin parameters | Shadowsocks plugin obfuscation; must match the server-side plugin. |
obfs-opts | mode, host, etc. | Snell/plugin obfuscation parameters. |
smux | enabled, protocol, max-connections, min-streams, max-streams, padding, statistic, only-tcp | Multiplexing settings; can reduce the number of connections, but is not suitable for every network. Disable it first when troubleshooting. |
How to read TLS/REALITY/ECH fields#
| Field | Used by which protocols | How users should understand it |
|---|---|---|
tls | VMess/VLESS/Trojan/HTTP/Brook/Naive, etc. | Whether to wrap the protocol with TLS; not all protocols allow it to be set manually. |
servername / sni | TLS-like protocols | The service name in the TLS handshake; usually must equal the certificate domain or the camouflage domain required by the server. |
skip-cert-verify | TLS-like protocols | Skips certificate verification. Recommended only for self-signed certificates or testing; reduces security. |
alpn | TLS/H2/H3/TrustTunnel, etc. | Negotiates the application-layer protocol, such as h2, h3, or http/1.1. |
client-fingerprint | Protocols that support uTLS | Adjusts the ClientHello fingerprint, such as chrome. |
pinned-certchain-sha256 | Certificate pinning scenarios | Accepts only the specified certificate chain. Suitable for strict verification, but configuration is more costly. |
reality-opts.public-key | VLESS/REALITY | Server REALITY public key. |
reality-opts.short-id | VLESS/REALITY | Short ID assigned by the server. |
reality-opts.fingerprint | VLESS/REALITY | Fingerprint parameter used by REALITY. |
reality-opts.support-x25519mlkem768 | VLESS/REALITY | Post-quantum/extended handshake capability, which must be compatible with the server. |
ech-opts.enable | TLS outbounds that support ECH | Enables Encrypted ClientHello. |
ech-opts.mode | ECH | ECH mode, such as grease/real configuration. |
ech-opts.config | ECH | Manually provided ECHConfig. |
ech-opts.query-server-name | ECH | Which domain name to use when querying the ECH configuration. |
If you do not know whether these fields are needed, do not set them at first. Set them only when provided by your service provider, and match the field values exactly.
Special Outbounds#
direct#
Connect directly to the target server.
proxies:
- name: local-direct
type: direct
interface-name: eth0
Field effects:
- You can use
interface-name/routing-markto control the direct outbound interface.
- The built-in
DIRECTalready exists; normal configurations do not need to declare it explicitly.
reject#
Reject connections.
proxies:
- name: block
type: reject
Used for rules that block ads, malicious traffic, or disallowed access. The built-in REJECT already exists.
dns#
A special outbound that hands traffic to Link1's built-in DNS resolver.
proxies:
- name: dns-out
type: dns
Regular users usually do not need to configure it explicitly.
Explicit Proxy Protocols#
http#
An HTTP upstream proxy works as follows: Link1 first connects to the upstream HTTP proxy. If the client accesses HTTPS, Link1 sends CONNECT target:443 to the upstream, and the upstream establishes a TCP tunnel to the target. If the client accesses plaintext HTTP, the upstream can forward the full HTTP request.
Suitable for: corporate proxies, HTTP proxies on cloud servers, and upstreams that require Basic authentication. It is not HTTP Engine and does not automatically decrypt HTTPS content.
proxies:
- name: http-upstream
type: http
server: proxy.example.com
port: 8080
username: alice
password: secret
tls: false
Key fields:
| Field | Effect |
|---|---|
server / port | HTTP proxy server address |
username / password | Basic authentication |
tls | Whether to use TLS when connecting to the upstream proxy |
headers | Additional request headers |
skip-cert-verify / servername | Affect the certificate and SNI in TLS mode |
socks / socks5#
A SOCKS5 upstream proxy works as follows: Link1 passes the target address to the SOCKS5 server, and the SOCKS5 server connects to the target. The target can be a domain name or an IP address.
DNS impact: If Link1 passes the domain name to SOCKS5, the upstream is responsible for resolution. If Link1 resolves it to an IP first and then passes it to SOCKS5, domain information may be lost. In transparent proxy/TUN scenarios, it is still recommended to let Link1 DNS/Fake-IP provide domain context first.
UDP impact: udp: true means Link1 will try to use SOCKS5 UDP associate. If the upstream does not support it, UDP traffic will fail, but TCP may still work normally.
proxies:
- name: socks-upstream
type: socks5
server: 127.0.0.1
port: 1080
username: alice
password: secret
udp: true
Key fields:
| Field | Effect |
|---|---|
server / port | SOCKS5 server |
username / password | SOCKS5 username and password |
udp | Whether to use SOCKS5 UDP associate |
tfo | TCP Fast Open, which requires protocol and system support |
ssh#
An SSH outbound works as follows: Link1 first logs in to the SSH server, then forwards TCP traffic through an SSH channel. It is more like "using the SSH server as a jump host" than a traditional encrypted proxy protocol.
Authentication can use either a password or a private key. In production, it is strongly recommended to configure host-key to verify the server host key. skip-host-key-verify is only suitable for temporary testing. UDP is not a native SSH capability; Link1 bridges it through udpgw mode, so a corresponding gateway is required.
proxies:
- name: ssh-node
type: ssh
server: ssh.example.com
port: 22
username: root
private-key: ./id_ed25519
private-key-passphrase: secret
host-key:
- SHA256:xxxxxxxx
udp: true
udp-relay-mode: udpgw
udp-gateway: 127.0.0.1:7300
Key fields:
| Field | Effect |
|---|---|
username | SSH login user, required |
password / private-key | Choose one authentication method |
private-key-passphrase | Passphrase for the encrypted private key |
host-key | Allowed server host keys; recommended for production |
skip-host-key-verify | Skips host key verification; insecure |
host-key-algorithms | Restricts host key algorithms |
udp | Enables UDP forwarding capability |
udp-relay-mode | Uses udpgw |
udp-gateway | udpgw address; requires udp=true |
Limitations: SSH does not support TLS, VMess/VLESS transport fields, Reality, ECH, SMUX, or other proxy protocol extensions.
VMess / VLESS / Trojan#
These three protocol types are common in "node subscriptions". Their configuration consists of three layers: identity fields (uuid/password), security layer (TLS/REALITY/certificates/SNI), and transport layer (TCP/WS/H2/gRPC/KCP). When troubleshooting, do not only check whether the port is reachable. Many failures happen because TLS, REALITY, or the transport-layer path does not match.
vmess#
proxies:
- name: vmess-ws
type: vmess
server: example.com
port: 443
uuid: 00000000-0000-0000-0000-000000000000
alterId: 0
cipher: auto
tls: true
network: ws
ws-opts:
path: /ws
headers:
Host: example.com
Key fields:
| Field | Impact |
|---|---|
uuid | VMess user ID, required |
alterId | VMess compatibility field |
cipher | VMess encryption method |
tls / skip-cert-verify / servername | TLS behavior |
network + *-opts | Transport layer |
udp | UDP forwarding capability |
smux | Multiplexing |
vless#
proxies:
- name: vless-reality
type: vless
server: example.com
port: 443
uuid: 00000000-0000-0000-0000-000000000000
flow: xtls-rprx-vision
encryption: none
tls: true
network: tcp
reality-opts:
public-key: xxxxx
short-id: abcd
fingerprint: chrome
Key fields:
| Field | Impact |
|---|---|
uuid | VLESS user ID, required |
flow | VLESS flow, such as Vision |
encryption | Usually none |
tls | VLESS is commonly used with TLS/REALITY |
reality-opts | REALITY parameters |
packet-addr / xudp / packet-encoding | UDP extension semantics |
udp-over-tcp / udp-over-tcp-version | UDP over TCP compatibility extension |
trojan#
proxies:
- name: trojan-grpc
type: trojan
server: example.com
port: 443
password: secret
tls: true
network: grpc
grpc-opts:
grpc-service-name: trojan
Key fields:
| Field | Impact |
|---|---|
password | Trojan password, required |
tls | Trojan usually uses TLS |
network | Can use transports such as WS/H2/gRPC |
ss-opts | Trojan Shadowsocks extension configuration |
udp | UDP forwarding capability |
Shadowsocks Ecosystem#
The core of the Shadowsocks ecosystem is "encryption method + password". SS itself is lightweight. Fields such as plugins, UDP-over-TCP, XUDP, and packet-addr exist to support different servers and transport scenarios. SSR and ShadowTLS are different compatibility/wrapping protocols, and their fields cannot be mixed.
ss / shadowsocks#
proxies:
- name: ss-node
type: ss
server: example.com
port: 8388
cipher: 2022-blake3-aes-128-gcm
password: secret
udp: true
plugin: obfs
plugin-opts:
mode: tls
host: www.example.com
Key fields:
| Field | Impact |
|---|---|
cipher | Encryption method, required |
password | Password, required |
udp | UDP forwarding |
plugin / plugin-opts | Plugin obfuscation |
smux | Multiplexing |
udp-over-tcp | UDP over TCP |
packet-addr / xudp | UDP address extensions |
Shadowsocks cipher and plugin combinations#
Shadowsocks is the most typical "cipher suite + plugin" protocol in this chapter. You can think of it as two layers:
cipherandpasswordencrypt the SS data stream.
pluginandplugin-optsdisguise or wrap the TCP connection to the SS server into another form.
Link1 processes them in this order: first connect to server:port; if a plugin is configured, let the plugin wrap this upstream connection first; then run the Shadowsocks encryption protocol over the plugin connection. Therefore, the server-side cipher, password, and plugin parameters must match field by field.
Supported ciphers:
| Category | Allowed cipher values | Description |
|---|---|---|
| Standard AEAD | aes-128-gcm, aes-192-gcm, aes-256-gcm, aes-128-ccm, aes-192-ccm, aes-256-ccm, aes-128-gcm-siv, aes-256-gcm-siv, chacha20-ietf-poly1305, chacha8-ietf-poly1305, xchacha20-ietf-poly1305, xchacha8-ietf-poly1305 | AEAD is recommended first. The chacha* series is usually suitable for devices without AES acceleration. |
| Extended AEAD | lea-128-gcm, lea-192-gcm, lea-256-gcm, rabbit128-poly1305, aegis-128l, aegis-256, deoxys-ii-256-128, aez-384, ascon128, ascon128a | Use only when explicitly provided by the server. If the server does not support it, the handshake will fail directly or there will be no response. |
| Shadowsocks 2022 | 2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm, 2022-blake3-chacha20-poly1305, 2022-blake3-chacha8-poly1305, 2022-blake3-aes-128-ccm, 2022-blake3-aes-256-ccm | SS 2022 uses an independent key format. Do not casually reuse an old SS password with a 2022 cipher. |
| Legacy stream cipher | aes-128-cfb, aes-192-cfb, aes-256-cfb, aes-128-ctr, aes-192-ctr, aes-256-ctr, chacha20, chacha20-ietf, xchacha20, xchacha20-ietf, rc4-md5 | Kept for compatibility with old servers. Not recommended as the first choice for new configurations. |
| Plaintext/testing | none, dummy | Only suitable for special testing or compatibility scenarios. It does not provide normal encryption protection. |
The configuration is also compatible with some aliases that use different letter cases, underscores, or
ss-2022-*; the user documentation only lists the recommended forms.
Supported plugins:
plugin | Core plugin-opts combination | TCP behavior | UDP behavior | Suitable scenarios |
|---|---|---|---|---|
| Not configured | None | Runs the SS encrypted stream directly | Uses native SS UDP when udp: true | Simplest and most stable. |
obfs | mode: http or mode: tls; optional host | simple-obfs-style HTTP/TLS disguise | The plugin itself does not support UDP packets. If UDP is required, the server must support it and you need to use a stream-based solution such as udp-over-tcp | Old servers, lightweight disguise. |
v2ray-plugin | mode: websocket/ws; optional host, path, headers, tls, mux, v2ray-http-upgrade, skip-cert-verify, fingerprint, certificate/private-key, ech-opts | Wraps SS TCP in WebSocket, with optional TLS, HTTP Upgrade, and mux layered on top | The plugin itself does not support UDP packets. When UDP is required, first confirm whether the server supports udp-over-tcp | CDN/reverse proxy/WebSocket servers. |
gost-plugin | mode: websocket/ws; optional host, path, headers, tls, mux, fingerprint, certificate/private-key, ech-opts | GOST-style WebSocket wrapping; mux is enabled by default | The plugin itself does not support UDP packets. When UDP is required, it depends on a stream-based UDP solution | Integrating with the GOST plugin ecosystem. |
cloak | transport: direct/cdn; required uid, publicKey, serverName; optional proxyMethod, encryptionMethod: plain/aes-gcm/aes-256-gcm/aes-128-gcm/chacha20-poly1305, browserSig: chrome/firefox/safari, cdnOriginHost, cdnWsUrlPath, numConn, streamTimeout, keepAlive, udp | Cloak handshake and session disguise; can connect directly or use CDN mode | The plugin provides UDP over stream packet capability only when plugin-opts.udp: true | Cloak servers and strong disguise scenarios. |
shadow-tls | Optional password, host, version: 1/2/3, alpn, strict-mode, skip-cert-verify, fingerprint, client-fingerprint, certificate/private-key | Layers ShadowTLS disguise outside SS; host defaults to the upstream host | Does not support plugin UDP packets | Connecting to ShadowTLS plugin servers. |
restls | Required password; optional host, version-hint: tls12/tls13, restls-script, fingerprint: chrome/firefox/safari/ios, skip-cert-verify | Layers the Restls handshake outside SS | Does not support plugin UDP packets | Restls servers. |
When using combinations, troubleshoot in this order:
- Disable the plugin first and verify only whether
cipher/password/server/portworks.
- Then enable the plugin and change only
pluginandplugin-opts. If TCP works but UDP does not, first check the UDP behavior in the table above.
plugin-opts.host, WebSocketpath, CloakserverName, and ShadowTLS/Restls versions are server-side agreements, not arbitrary "disguise domains" that can be changed freely.
ssr / shadowsocksr#
proxies:
- name: ssr-node
type: ssr
server: example.com
port: 8388
cipher: aes-256-cfb
password: secret
obfs: tls1.2_ticket_auth
obfs-param: example.com
protocol: auth_sha1_v4
protocol-param: ''
Key fields:
| Field | Impact |
|---|---|
cipher | SSR encryption method |
password | Password |
obfs / obfs-param | Obfuscation method and parameters |
protocol / protocol-param | SSR protocol plugin |
udp | UDP forwarding |
ShadowsocksR cipher / obfs / protocol combinations#
SSR configuration is determined by three things at the same time: cipher handles encryption, obfs controls traffic appearance, and protocol handles SSR authentication/fragmentation format. Link1 supports the following combinations:
| Combination dimension | Allowed values | How users should choose |
|---|---|---|
cipher | none, rc4-md5, aes-128-cfb, aes-192-cfb, aes-256-cfb, aes-128-ctr, aes-192-ctr, aes-256-ctr, chacha20, chacha20-ietf, xchacha20 | Use the value provided by the service provider. SSR nodes are mostly legacy nodes, so upgrading the cipher yourself is not recommended. |
obfs | plain, http_simple, http_post, random_head, tls1.2_ticket_auth, tls1.2_ticket_fastauth | Follow the server. obfs-param is usually a disguise domain or HTTP header parameter. |
protocol | origin, auth_sha1_v4, auth_aes128_md5, auth_aes128_sha1, auth_chain_a, auth_chain_b | Follow the server. protocol-param is commonly a user ID/password-style parameter. Fill in whatever the subscription provides. |
These dimensions can be combined at the configuration layer, but whether they actually work depends on whether the SSR server uses the same combination. When troubleshooting SSR, do not look only at cipher. Any mismatch in obfs or protocol can result in no data after the connection is established, quick disconnections, or UDP issues.
shadowtls#
proxies:
- name: shadowtls-node
type: shadowtls
server: example.com
port: 443
password: secret
version: 3
sni: www.example.com
Key fields:
| Field | Impact |
|---|---|
password | ShadowTLS password, required |
version | ShadowTLS version |
sni / servername | Disguised TLS domain |
certificate / private-key | Used as certificate material when both are configured |
dialer-proxy | Can be combined with a front proxy; some socket fields become unavailable after it is set |
QUIC / High-Performance Proxy Protocols#
This group of protocols mainly runs over QUIC/UDP. They are usually friendlier to mobile networks, packet loss, and UDP traffic, but only if the local network, ISP, router, and upstream all allow UDP. If “TCP websites open, but video/games/QUIC do not work,” check udp, firewall rules, and upstream UDP support first.
The bandwidth fields up/down are important inputs for protocol scheduling and congestion control, not just display text. Setting them too high may cause packet loss; setting them too low may limit throughput.
tuic#
proxies:
- name: tuic-node
type: tuic
server: example.com
port: 443
uuid: 00000000-0000-0000-0000-000000000000
password: secret
udp: true
udp-relay-mode: native
congestion-controller: bbr
reduce-rtt: true
Key fields:
| Field | Effect |
|---|---|
uuid / password | TUIC authentication |
udp-relay-mode | UDP relay mode, such as native / quic |
congestion-controller | Congestion control: cubic, new_reno, bbr, brutal |
reduce-rtt | Reduces handshake RTT |
request-timeout | Request timeout |
heartbeat-interval | Heartbeat interval |
disable-sni | Disables SNI |
max-udp-relay-packet-size | Maximum UDP relay packet size |
bbr-profile | Selects a BBR parameter profile when congestion-controller: bbr. Supports standard, conservative, and aggressive. If the controller is not set but bbr-profile is set, BBR is enabled by default. |
hysteria#
proxies:
- name: hy1-node
type: hysteria
server: example.com
port: 443
auth-str: secret
protocol: udp
up: 50 Mbps
down: 200 Mbps
sni: example.com
Key fields:
| Field | Effect |
|---|---|
auth / auth-str | Hysteria v1 authentication |
protocol | udp, wechat-video |
up / down | Bandwidth hints that affect congestion/rate policies |
obfs / obfs-password | Obfuscation |
ports / hop-interval | Port hopping |
recv-window / recv-window-conn | QUIC window |
faketcp depends on Linux raw-socket behavior, so Spark does not expose this non-cross-platform protocol feature.
hysteria2 / hy2#
proxies:
- name: hy2-node
type: hysteria2
server: example.com
port: 443
password: secret
obfs: salamander
obfs-password: obfs-pass
sni: example.com
skip-cert-verify: false
up: 50 Mbps
down: 200 Mbps
Key fields:
| Field | Effect |
|---|---|
password | Hysteria2 password |
obfs: salamander / obfs-password | Salamander obfuscation |
sni / servername | TLS SNI |
up / down | Bandwidth hints |
ports / hop-interval | Port hopping |
skip-cert-verify | Certificate verification |
bbr-profile | Selects a BBR parameter profile when congestion-controller: bbr. Supports standard, conservative, and aggressive. |
realm-opts | Realm relay configuration, used to help relay Hysteria2 through a realm server / STUN. |
Hysteria2 has very few optional obfuscation combinations. The following two forms are supported:
| Field combination | Allowed values | Actual effect |
|---|---|---|
| No obfuscation | Omit obfs / obfs-password | Uses Hysteria2 QUIC/TLS traffic directly. |
| Salamander obfuscation | obfs: salamander + obfs-password: <secret> | QUIC packets are obfuscated with Salamander. Setting only obfs-password or only obfs will be rejected. |
realm-opts is suitable when the server does not directly expose regular ports and forwarding must be coordinated through a realm server/STUN. After it is configured, server-url, token, realm-id, and at least one stun-servers entry must be provided. It cannot be used together with ports port hopping. realm-opts.proxy indicates the outbound used to access the realm control plane, and is not the same as the node’s own dialer-proxy.
realm-opts:
enable: true
server-url: https://realm.example
token: xxxxx
realm-id: hy2-realm
stun-servers:
- stun.example:3478
sni: realm.example
proxy: PROXY
Legacy protocol fields such as cipher, protocol, network, and plugin do not belong to Hysteria2. If these fields appear after conversion from another subscription format, they are usually ignored or rejected during validation.
juicity#
proxies:
- name: juicity-node
type: juicity
server: example.com
port: 443
uuid: 00000000-0000-0000-0000-000000000000
password: secret
sni: example.com
congestion-controller: bbr
Key fields: uuid, password, sni, skip-cert-verify, congestion-controller, udp.
naive#
proxies:
- name: naive-node
type: naive
server: example.com
port: 443
username: alice
password: secret
tls: true
NaiveProxy uses an HTTP/2/HTTP/3-style upstream proxy. Key fields: username, password, tls, skip-cert-verify, servername, alpn.
Other Proxy Protocols#
Each protocol in this group has its own server ecosystem. Unlike VMess/VLESS, they do not share many transport fields, so the most important rule is to match the server documentation field by field: version, password/key, obfuscation, mask, padding, and UDP policy must all match.
snell#
proxies:
- name: snell-node
type: snell
server: example.com
port: 443
psk: secret
version: 3
udp: true
obfs-opts:
mode: tls
host: www.example.com
Key fields:
| Field | Effect |
|---|---|
psk | Snell key |
version | 1/2/3/4/5 |
udp | Snell v3/v4/v5 support UDP over TCP |
reuse | Explicitly unsupported for now; reuse: true fails validation, and the default is equivalent to false |
obfs-opts | Snell obfuscation configuration |
Supported Snell version/obfuscation combinations:
| Field combination | Allowed values | Actual effect |
|---|---|---|
version | 1, 2, 3, 4, 5; defaults to 1 if omitted | The version must match the server. 5 is handled as a v4-compatible client; udp: true is allowed with version: 3/4/5. |
| No obfuscation | Omit obfs-opts or leave obfs-opts.mode empty | Runs the Snell protocol directly. |
| HTTP obfuscation | obfs-opts.mode: http, optional obfs-opts.host | Disguises the first packet as an HTTP request. If host is omitted, the implementation uses a default value. |
| TLS obfuscation | obfs-opts.mode: tls, optional obfs-opts.host | Disguises the first packet as TLS traffic. Must match the server configuration. |
network is handled as TCP behavior. Snell is not a generic WebSocket/TLS transport protocol and does not support transport sub-configurations such as ws-opts or grpc-opts.
gost-relay#
proxies:
- name: relay-node
type: gost-relay
server: relay.example.com
port: 8420
username: user
password: pass
dialer-proxy: DIRECT
gost-relay is a lightweight TCP outbound implementation for GOST relay v1. Link1 first connects to server:port, sends a relay CONNECT request, and then forwards subsequent TCP traffic to the target address. It is useful when a GOST relay server acts as a chained hop, or when it is used as the dialer-proxy for another outbound.
Key fields:
| Field | Effect |
|---|---|
server / port | GOST relay server address. |
username / password | Optional relay user authentication. Each field is limited to 255 bytes. |
dialer-proxy | Optional front outbound; connects to the relay server through the specified node first. |
interface-name / routing-mark / tfo | Controls the underlying TCP dial for the segment connecting to the relay server. |
First-version limitations: TCP CONNECT only. udp: true, tls: true, and network: udp fail during configuration compilation. GOST relay TLS/mTLS, mux, and UDP forward/associate are intentionally out of scope for this phase.
anytls#
proxies:
- name: anytls-node
type: anytls
server: example.com
port: 443
password: secret
sni: example.com
Key fields: password, sni/servername, skip-cert-verify, udp, alpn, client-fingerprint.
brook#
proxies:
- name: brook-node
type: brook
server: example.com
port: 443
password: secret
network: ws
ws-opts:
path: /ws
tls: true
Key fields:
| Field | Effect |
|---|---|
password | Brook password |
network | tcp, ws, quic, etc.; validated by the implementation |
without-brook-protocol | Compatibility field for some WS/WSS/QUIC modes |
fragment | Brook WSS server fragment configuration |
http-mask* | HTTP mask compatibility fields |
udp-over-tcp | Supported only by specific Brook server transports |
mieru#
proxies:
- name: mieru-node
type: mieru
server: example.com
port: 443
username: alice
password: secret
transport: TCP
Key fields: username, password, server, port, transport, multiplexing, handshake-mode.
trusttunnel#
proxies:
- name: trust-node
type: trusttunnel
server: example.com
port: 443
username: alice
password: secret
alpn: [h2]
udp: true
udp-over-stream: true
Key fields:
| Field | Effect |
|---|---|
username / password | Optional authentication. A username is required when a password is set. |
alpn | Must include h2 |
udp-over-stream | UDP over stream |
udp-relay-mode | Only native is allowed |
congestion-controller | cubic, new_reno, bbr |
certificate / private-key | Configured as a pair |
sudoku#
proxies:
- name: sudoku-node
type: sudoku
server: example.com
port: 443
password: secret
aead-method: chacha20-poly1305
udp: true
sudoku-udp-policy: uot
padding-min: 1
padding-max: 8
Key fields:
| Field | Effect |
|---|---|
password / key | At least one is required for authentication/keying |
aead-method | chacha20-poly1305, aes-128-gcm, none |
padding-min / padding-max | Padding range, 0-100 |
table-type | prefer_ascii or prefer_entropy |
custom-table / custom-tables | Must be used with table-type=prefer_entropy |
http-mask / httpmask | HTTP mask switch/compatibility configuration |
http-mask-mode | legacy, stream, poll, auto |
http-mask-host / path-root | HTTP mask target appearance |
http-mask-multiplex | off, auto, on |
sudoku-udp-policy | reject, direct, uot |
Supported Sudoku security/obfuscation combinations:
| Combination dimension | Allowed values | Actual effect |
|---|---|---|
aead-method | chacha20-poly1305, aes-128-gcm, none; uses the default if omitted | Encrypts data frames. none is only allowed in the special pure downlink scenario with enable-pure-downlink: true. |
| padding | padding-min / padding-max from 0 to 100, and max must not be less than min | Changes packet length distribution. Mismatched values on the two ends affect compatibility. |
| table | table-type: prefer_ascii or prefer_entropy; custom tables require prefer_entropy | Controls the data transformation table. A custom table must be 8 characters, with x=2,p=2,v=4. |
| HTTP mask | http-mask: true, http-mask-mode: legacy/stream/poll/auto, with optional http-mask-host, path-root, http-mask-tls | Makes Sudoku traffic look more like HTTP. Related fields are meaningful only when http-mask: true is set. |
| HTTP mask multiplex | http-mask-multiplex: off/auto/on | Controls multiplexing under HTTP mask. It cannot be configured alone when HTTP mask is not enabled. |
| UDP policy | sudoku-udp-policy: reject/direct/uot | reject rejects UDP; direct connects UDP directly; uot carries UDP using a UDP-over-TCP approach. |
Sudoku currently implements only TCP outbound networking. If network is configured, it can only be tcp or left empty.
L3 Tunneling and Networking Protocols#
The biggest difference between L3 tunnels and regular proxies is that they provide a “virtual network link”, not just CONNECT/SOCKS forwarding. DNS, routing, MTU, tunnel addresses, and allowed routes all affect which addresses can be reached.
Users should clearly distinguish between two routing layers:
- Link1 top-level
rules: decides whether a connection selects this VPN outbound.
- Internal VPN protocol routing: decides which destination IPs are reachable inside the tunnel after entering the VPN.
wireguard / wg#
proxies:
- name: wg-node
type: wireguard
private-key: xxxxx
ip: 172.16.0.2/32
ipv6: 2606:4700::1/128
mtu: 1280
peers:
- server: engage.cloudflareclient.com
port: 2408
public-key: xxxxx
pre-shared-key: optional
allowed-ips:
- 0.0.0.0/0
- ::/0
Key fields:
| Field | Effect |
|---|---|
private-key | Local WireGuard private key |
ip / ipv6 | Local tunnel address |
public-key / pre-shared-key | Peer keys |
reserved | reserved bytes, required by some providers |
allowed-ips | Routed prefixes that are allowed |
peers | Multi-peer list |
mtu | Tunnel MTU |
persistent-keepalive | NAT keepalive |
amnezia-wg-option | AmneziaWG extension |
dns / remote-dns-resolve | Remote DNS related settings |
WireGuard DNS and allowed-ips#
allowed-ips are the tunnel route prefixes for the WireGuard peer, not Link1 top-level rules. Providers usually supply 0.0.0.0/0 and ::/0, meaning all destinations after entering this outbound are allowed to go through this peer. If only enterprise intranet prefixes are provided, only those intranet IPs are reachable inside the tunnel.
dns and remote-dns-resolve are used to decide “where this domain name should be resolved”. VPN types default to remote-dns-resolve: true: when the destination is still a domain name, Link1 preferentially lets the VPN runtime resolve it using tunnel DNS. dns can manually specify tunnel DNS. If the runtime has no DNS provided by the server or configuration, enabling remote resolution will directly return an error and will not silently fall back to local DNS. To reuse local/global DNS, explicitly set remote-dns-resolve: false.
masque#
proxies:
- name: masque-node
type: masque
server: example.com
port: 443
uri: https://example.com/.well-known/masque/udp/1.1.1.1/443/
sni: example.com
handshake-mode: strict
congestion-controller: bbr
mtu: 1280
Key fields:
| Field | Effect |
|---|---|
uri | MASQUE target URI |
sni / servername | TLS SNI |
handshake-mode | strict or compatibility mode |
network | Defaults to h3; can be h3/http3/quic or h2/http2. h2 uses HTTP/2 fallback and does not support QUIC congestion control fields. |
congestion-controller | QUIC congestion control: cubic, new_reno, bbr, brutal; only effective when network=h3. |
bbr-profile | BBR parameter profile. Supports standard, conservative, and aggressive; only supports network=h3. If set without specifying a controller, BBR is enabled by default. |
cwnd | Initial congestion window; only effective when network=h3. |
up / down | Bandwidth hints for brutal congestion control; only effective when network=h3. |
dialer-proxy | Uses an upstream outbound when connecting to the MASQUE endpoint. After setting it, interface-name / routing-mark cannot be used at the same time. |
remote-dns-resolve / dns | Remote DNS |
mtu | Tunnel MTU |
MASQUE DNS and URI#
The MASQUE uri is not just a normal URL. It describes where the HTTP/3 MASQUE server accepts CONNECT-UDP/IP. server/port decides which endpoint to connect to, sni/servername decides the TLS handshake domain name, and uri decides the MASQUE request target. These three may be the same, or they may be provided separately by the provider.
dns and remote-dns-resolve have meanings similar to WireGuard: they control domain resolution after entering the MASQUE tunnel. VPN MASQUE defaults to remote-dns-resolve: true; it can be explicitly set to false to fall back to local/global DNS. For WARP MASQUE, the provider materializes the DNS and remote resolve parameters from the WARP state into the generated MASQUE node.
tailscale#
proxies:
- name: tailnet
type: tailscale
auth-key: tskey-xxxxx
hostname: link1-router
control-url: https://headscale.example.com
exit-node: 100.64.0.10
auto-route: true
route-rule-set: tailnet-routes
Key fields:
| Field | Effect |
|---|---|
auth-key | Key for logging in to Tailscale/Headscale |
hostname | Node name |
control-url | Control-plane URL, used in Headscale scenarios |
ephemeral | Ephemeral node |
accept-routes | Whether to accept routes pushed by the control plane; defaults to true |
exit-node | Use the specified exit node as the outbound |
exit-node-allow-lan-access | Whether to keep local LAN access when using an exit node |
remote-dns-resolve | Defaults to true. Destination domains are resolved using Tailscale MagicDNS / tailnet DNS |
auto-route | Defaults to true. Automatically injects a dynamic RULE-SET before MATCH |
route-rule-set | Defaults to $<proxy-name>. Dynamic route rule set name |
dialer-proxy | Upstream outbound used for Tailscale control-plane and DERP/peer connections |
By default, route-rule-set directly uses the proxy name with a $ prefix. If the proxy name or explicit rule set name contains a comma, the automatically injected RULE-SET is wrapped in double quotes and escaped according to the common rule syntax.
Tailscale MagicDNS#
Tailscale outbound defaults to remote-dns-resolve: true. When a rule sends a domain destination to this outbound, Link1 first queries MagicDNS / tailnet DNS through the embedded Tailscale runtime DNS manager, then uses the resolved tailnet IP to establish the connection. If Tailscale DNS does not return an address, an error is returned and it will not silently fall back to local DNS. To reuse local or global DNS, explicitly set remote-dns-resolve: false.
Global DNS can also directly reference a Tailscale outbound:
dns:
nameserver-policy:
'+.tailnet.ts.net':
- ts://tailnet
tailscale://tailnet and ts://tailnet are equivalent. Both mean “use the MagicDNS / tailnet DNS provided by the Tailscale outbound named tailnet”.
dialer-proxy applies to Tailscale’s own system dialing path: control-plane, DERP/relay, and peer direct connections all prefer the specified outbound. The current implementation uses a trimmed Tailscale fork in Link1 and connects the underlying WireGuard path to Link1’s internal WireGuard. The goal is to keep only the subset required for outbound use while preserving room for future WireGuard variant extensions.
openvpn#
OpenVPN outbound is not a regular “remote proxy port”; it is a full VPN client. Link1 first establishes a control channel with the OpenVPN server, completes TLS/certificate/username-password authentication, then creates a userspace tunnel network and places connections selected by rules into this tunnel. When dialer-proxy is configured, the underlying TCP/UDP channel used by OpenVPN to connect to the remote first goes through the specified outbound. UDP remotes require the upstream outbound to support UDP.
Its data flow can be understood as:
App connection
-> Link1 rules select ovpn-node
-> OpenVPN userspace netstack
-> OpenVPN control/data channel
-> VPN server
-> Enterprise intranet or public target
Minimal example:
proxies:
- name: ovpn-node
type: openvpn
server: vpn.example.com
port: 1194
network: udp
username: alice
password: secret
ca: ./certs/ca.crt
certificate: ./certs/client.crt
private-key: ./certs/client.key
private-key-passphrase: optional-passphrase
route-rule-set: ovpn-node-routes
Multiple remote example:
proxies:
- name: ovpn-node
type: openvpn
ca: ./certs/ca.crt
username: alice
password: secret
remotes:
- server: vpn1.example.com
port: 1194
protocol: udp
sni: vpn.example.com
- server: vpn2.example.com
port: 443
protocol: tcp
servername: vpn.example.com
OpenVPN Field Reference#
| Field | Required/Default | Actual effect |
|---|---|---|
server / port / network | Required when there is no remotes; network defaults to UDP | Declares the default remote; network only allows UDP/TCP and compatible spellings. |
remotes[] | Optional | Multiple OpenVPN remote candidates. Link1 selects/switches remotes based on status. |
remotes[].server / port / protocol | Required inside a remote | Address, port, and transport protocol of a single remote. |
remotes[].sni / servername | Optional | TLS name of a single remote. sni takes priority. |
username / password | Depends on the server | Username/password authentication. |
ca | Usually required | Verifies the OpenVPN server certificate. If ca is not set, skip-cert-verify: true must be explicitly set. |
certificate / private-key | Configured as a pair | Client certificate authentication. Setting only one of them is rejected. |
private-key-passphrase | Optional | Password for the encrypted private key. |
auth | Optional | OpenVPN auth digest. |
cipher / data-ciphers | Optional | Data channel ciphers. Supports AES-128-GCM, AES-192-GCM, AES-256-GCM, CHACHA20-POLY1305, and legacy AES-128-CBC/AES-256-CBC; AES-CBC is treated as AES-128-CBC, and data-ciphers is a candidate list. |
tls-auth / tls-crypt / tls-crypt-v2 | Mutually exclusive | OpenVPN TLS control channel protection. Only one of the three can be selected. |
key-direction | Used with tls-auth | Can only be 0, 1, or bidirectional, and must be used with tls-auth. |
ip / ipv6 | Optional | Manually specifies the local tunnel address. It can be provided by the server when the server pushes ifconfig. |
dns | Optional | Manually specifies VPN DNS server IPs. If the server pushes DNS, it is overridden by the pushed result. |
remote-dns-resolve | Defaults to true | Destination domains are resolved by the OpenVPN runtime using pushed/configured VPN DNS. When explicitly set to false, local/global DNS is used instead. |
mtu | Optional | Tunnel MTU. It may also be updated when the server pushes tun-mtu. |
request-timeout | Defaults to 30s | OpenVPN handshake timeout, in milliseconds. |
ping-interval / ping-timeout | Defaults to 10s / 60s | Keepalive and disconnection detection. Server push can also override them. |
reneg-sec | Defaults to 3600s | TLS renegotiation interval. |
route-rule-set | Defaults to $<proxy-name> | Exposes a dynamic rule set for matching route prefixes pushed by the VPN server. |
auto-route | Defaults to true | Automatically inserts RULE-SET,<route-rule-set>,<proxy-name> before MATCH. |
interface-name / routing-mark | Optional | Underlying outbound control for the segment where OpenVPN connects to the server. |
By default, route-rule-set directly uses the proxy name with a $ prefix. If the proxy name or explicit rule set name contains a comma, the automatically injected RULE-SET is wrapped in double quotes and escaped according to the common rule syntax.
Common unsupported fields:
tls,alpn,client-fingerprint,reality-opts,ech-opts,ws-opts,grpc-opts: these are regular proxy/TLS transport fields, not OpenVPN configuration.
auto-setup-routes: this is an enterprise VPN-style field, not an OpenVPN outbound field. OpenVPN usesroute-rule-setandauto-route.
How OpenVPN DNS Works#
OpenVPN DNS has three source layers, in descending priority:
- DNS pushed by the server: the OpenVPN server may send
dhcp-option DNS 10.8.0.1inPUSH_REPLY. Link1 records it in the OpenVPN runtime snapshot.
- The
dnsfield in the node: if the server does not push DNS, you can manually setdns: [10.8.0.1].
- Global Link1 DNS: when
remote-dns-resolve: false, or when a DNS query is not part of an outbound dialing target, normal DNS still follows global configuration such asdns.nameserverandnameserver-policy.
OpenVPN defaults to remote-dns-resolve: true. Domain destinations selected by rules and entering the OpenVPN outbound are resolved by the OpenVPN runtime using pushed/configured DNS. If no VPN DNS is available, an error is returned instead of falling back to local DNS.
If you need certain enterprise domains in the global DNS policy to explicitly call the internal OpenVPN DNS, write openvpn://<node-name> in dns.nameserver-policy:
dns:
enable: true
nameserver:
- https://223.5.5.5/dns-query
nameserver-policy:
'+.corp.example.com':
- openvpn://ovpn-node
'+.internal.example.com':
- openvpn://ovpn-node
Meaning:
- Normal domains still use the default
nameserver.
- Enterprise domains such as
corp.example.comcall the remote DNS capability ofovpn-node.
ovpn-nodemust already be able to establish an OpenVPN runtime and have DNS servers in its snapshot; otherwise, it reports “no remote dns servers” or remote resolution failure.
openvpn://ovpn-node and remote-dns-resolve use the same type of remote DNS capability, but have different entry points: the former is a nameserver in the global DNS policy, while the latter is the resolution policy used when the OpenVPN outbound dials a target domain.
How OpenVPN Routing Works#
The OpenVPN server may push routes, such as route 10.0.0.0 255.0.0.0 or IPv6 routes. Link1 records these prefixes in the runtime snapshot of that node.
route-rule-set exposes these prefixes as a dynamic rule set:
proxies:
- name: ovpn-node
type: openvpn
server: vpn.example.com
port: 1194
ca: ./certs/ca.crt
route-rule-set: corp-vpn-routes
auto-route: true
rules:
- DOMAIN-SUFFIX,corp.example.com,ovpn-node
- MATCH,PROXY
When auto-route: true, Link1 automatically inserts a rule like the following before MATCH:
rules:
- RULE-SET,corp-vpn-routes,ovpn-node
- MATCH,PROXY
Note: OpenVPN dynamic route rule-sets mainly match IP prefixes pushed by the server. For enterprise domains, it is still recommended to point them to openvpn://ovpn-node through dns.nameserver-policy. After they resolve to enterprise intranet IPs, the routing rules can then match them.
Common OpenVPN Issues#
| Symptom | Common Cause | Action |
|---|---|---|
Config compilation reports ca is empty | No CA is provided and certificate verification is not skipped | Configure ca, or explicitly set skip-cert-verify: true during testing |
Reports certificate and private-key must be configured together | Only one of the client certificate and private key is configured | Configure both, or configure neither |
| Enterprise domain resolution fails | No pushed/configured VPN DNS, or remote resolution is explicitly disabled | Configure dns, check the server push, or confirm whether remote-dns-resolve: false is needed |
| Intranet IPs do not use the VPN | The server did not push routes, or auto-route=false | Check OpenVPN snapshot routes and route-rule-set |
| UDP remote is unreachable | UDP is blocked by the network | Use a TCP remote or check the firewall |
WARP provider#
WARP is Cloudflare's dynamic egress capability. Link1 does not design it as proxies[].type=warp, but as proxy-providers.type=warp. The reason is that WARP is not a fixed leaf node, but a "node source" that generates nodes.
Why it must be a provider:
- One WARP configuration may generate multiple egresses: the same WARP state can materialize both
wireguardandmasquenode types.
- auto mode requires persistent state: accounts, keys, endpoints, reserved bytes, MASQUE parameters, and other data need to be managed and reused.
- It naturally fits policy group selection: nodes generated by the provider can enter policy groups such as
select,url-test, andfallback, where users or health checks choose them.
- It is not a subscription download: the WARP provider does not use subscription fields such as
url,path,format, andproxy; it builds local nodes from WARP state.
- Avoid configuration ambiguity: if
proxies[].type=warpwere allowed, users would assume it behaves like a normal protocol with only one fixed server/port. In reality, WARP must first determine the transport and state source.
Most common example:
proxy-providers:
warp:
type: warp
mode: auto
transports:
- masque
- wireguard
proxy-groups:
- name: WARP
type: select
use: [warp]
proxies:
- DIRECT
rules:
- MATCH,WARP
Meaning of this configuration:
- The
warpprovider generates WARP nodes.
transportsspecifies which types to generate. It supportsmasqueandwireguard.
- If both transports have available state, nodes similar to
warp MASQUEandwarp WIREGUARDwill appear in the group.
- The
WARPpolicy group lets users choose a specific WARP transport, or work with an automatic group for health-based selection.
WARP auto Mode Fields#
| Field | Default/Limit | Actual Effect |
|---|---|---|
type | Must be warp | Declares this as a WARP provider. |
mode | Defaults to auto | Automatically loads/generates WARP state. |
transports | Defaults to masque + wireguard | Specifies which candidates to materialize; only masque and wireguard are supported. |
license-key | Supported only in mode=auto | Uses the specified WARP license. It is rejected in manual mode. |
endpoint-host / endpoint-port | auto uses the default endpoint | Specifies the WARP endpoint. |
mtu | Default WARP MTU | Affects the generated tunnel MTU. |
persistent-keepalive | Default WARP keepalive | WireGuard NAT keepalive. |
dialer-proxy | Optional | Passed to the generated WireGuard/MASQUE nodes so they use a fronting egress when connecting to the WARP endpoint. |
Discovery fields that are no longer supported: probe-timeout, count, wg-candidates, masque-candidates. These fields belong to the old discovery design and will be rejected if written in the configuration.
WARP manual Mode Fields#
manual mode is suitable when you already have complete WARP parameters and do not want Link1 to automatically generate state.
proxy-providers:
warp-manual:
type: warp
mode: manual
transports: [wireguard, masque]
wireguard:
private-key: xxxxx
public-key: xxxxx
ip: 172.16.0.2
ipv6: 2606:4700::1
reserved:
bytes: [0, 0, 0]
server: engage.cloudflareclient.com
port: 2408
allowed-ips:
- 0.0.0.0/0
- ::/0
mtu: 1280
persistent-keepalive: 25
masque:
private-key: xxxxx
public-key: xxxxx
ip: 172.16.0.2
ipv6: 2606:4700::1
server: masque.cloudflareclient.com
port: 443
uri: https://masque.cloudflareclient.com/
sni: masque.cloudflareclient.com
dns:
- 1.1.1.1
remote-dns-resolve: true
mtu: 1280
congestion-controller: bbr
| Sub-block | Field | Actual Effect |
|---|---|---|
wireguard | private-key, public-key | Local private key and peer public key for WARP/WireGuard. |
wireguard | ip, ipv6 | Local tunnel address; at least one is required. |
wireguard | reserved.bytes | WARP reserved bytes, required for some accounts. |
wireguard | server, port | WARP WireGuard endpoint. |
wireguard | allowed-ips | Allowed prefixes entering the tunnel. If omitted, it defaults to all IPv4 globally, and also includes ::/0 when IPv6 is present. |
wireguard | mtu, persistent-keepalive | MTU and NAT keepalive. |
masque | private-key, public-key, ip, ipv6 | MASQUE account and tunnel addresses. |
masque | server, port, uri, sni | MASQUE HTTP/3 endpoint and TLS name. |
masque | dns, remote-dns-resolve | MASQUE internal DNS and remote resolution behavior. |
masque | skip-cert-verify | Skips certificate verification for the MASQUE endpoint. Not recommended for production. |
masque | mtu, congestion-controller, cwnd, up, down | QUIC/tunnel performance parameters. |
manual mode rules:
- When
transportsincludeswireguard, thewireguardsub-block must be provided.
- When
transportsincludesmasque, themasquesub-block must be provided.
license-keycan only be used in auto mode.
- Top-level
handshake-modeis not supported. WARP MASQUE internally uses fixed compatible handshake semantics.
What Nodes the provider Generates#
The WARP provider eventually generates normal Link1 outbound nodes:
| WARP transport | Generated leaf type | User-visible Behavior |
|---|---|---|
wireguard | wireguard | Forwards like a normal WireGuard tunnel. |
masque | masque | Forwards like a MASQUE/HTTP3 tunnel, with UDP enabled by default. |
Therefore, subsequent policy groups, rules, and health checks operate on these generated nodes, not directly on warp. This is also the fundamental reason why warp must be placed under a provider.
Common WARP Issues#
| Symptom | Common Cause | Action |
|---|---|---|
proxies[].type=warp is rejected | WARP cannot be used as a leaf | Change it to proxy-providers.<name>.type: warp |
| The provider does not generate nodes | auto state is empty, or the specified transport has no available state | Check the App Provider page and logs to confirm whether WARP state has been generated |
url/path/format is rejected | The WARP provider is not a subscription provider | Remove these fields |
manual mode reports missing wireguard/masque | The corresponding transport is enabled in transports | Complete the corresponding sub-block or remove it from transports |
| MASQUE is unreachable, but WireGuard works | Local or network restrictions on HTTP/3/QUIC | Switch to WireGuard in the policy group, or check UDP/QUIC |
| WireGuard is unreachable, but MASQUE works | WireGuard endpoint/UDP is blocked | Use the MASQUE transport or check the endpoint/UDP |
Enterprise VPN Protocols#
Enterprise VPN protocols depend on the target server version, login policy, CAPTCHA, device binding, and enterprise security policy. They are more like “using an enterprise VPN as a Link1 outbound” than ordinary subscription nodes.
Enterprise VPNs usually return two types of dynamic information:
- Enterprise DNS: used to resolve domain names that exist only on the corporate intranet.
- Enterprise routes: used to determine which intranet IPs should go through the VPN.
Therefore, these protocols are often used together with dns.nameserver-policy, route-rule-set, and policy groups, instead of blindly sending all traffic to the enterprise VPN.
atrust#
proxies:
- name: atrust-node
type: atrust
server: vpn.example.com
username: alice
password: secret
auth-type: auth/psw
remote-dns-resolve: true
route-rule-set: corp-routes
Key fields:
| Field | Effect |
|---|---|
server | ATrust service address |
username / password | Login credentials |
auth-type | auth/psw, auth/cas, auth/smsCheckCode |
phone / code / cas-ticket | Parameters for the corresponding authentication method |
remote-dns-resolve | Defaults to true; target domains are resolved remotely using the VPN DNS |
session-persist | Session persistence |
route-rule-set | Defaults to $<proxy-name>; enterprise route rule set name |
request-timeout | Login/request timeout |
Limitations: does not support fields for ordinary proxies such as TLS/QUIC/network. dialer-proxy applies to both the login control plane and the underlying enterprise tunnel connection.
feilian#
proxies:
- name: feilian-node
type: feilian
server: vpn.example.com
company-name: example
username: alice
password: secret
vpn-select-strategy: default
remote-dns-resolve: true
Key fields:
| Field | Effect |
|---|---|
company-name / server | At least one is used to locate the enterprise |
username / password | Login credentials |
vpn-server-name | Specifies the VPN gateway |
vpn-select-strategy | Gateway selection strategy |
remote-dns-resolve | Defaults to true; target domains are resolved remotely using the VPN DNS |
session-persist | Session persistence |
dialer-proxy | The Feilian control plane, VPN ping/connect requests, and WireGuard underlay all use the specified front outbound; UDP mode requires the front outbound to support UDP. |
easyconnect#
proxies:
- name: easyconnect-node
type: easyconnect
server: vpn.example.com
port: 443
username: alice
password: secret
remote-dns-resolve: true
Key fields:
| Field | Effect |
|---|---|
server / port | EasyConnect service address |
username / password | Login credentials |
remote-dns-resolve | Defaults to true; target domains are resolved remotely using the VPN DNS |
auto-setup-routes | Automatically sets VPN routes |
route-rule-set | Defaults to $<proxy-name>; enterprise route rule set name |
request-timeout | Request timeout |
Automatic injection of dynamic enterprise VPN route-rule-set follows the general rule syntax as well. If the proxy name or rule set name contains a comma, the corresponding field is automatically quoted.
Limitations: does not support fields for ordinary proxies such as TLS, QUIC, and network. dialer-proxy applies to both the login control plane and tunnel data connection.
Inbound Protocol Listeners#
Although this chapter mainly covers outbounds, Link1 can also act as a server for some protocols.
VLESS listener#
listeners:
- name: vless-in
type: vless
listen: 0.0.0.0
port: 443
certificate: ./certs/server.crt
private-key: ./certs/server.key
users:
- username: alice
uuid: 00000000-0000-0000-0000-000000000000
flow: xtls-rprx-vision
ws-path: /ws
proxy: PROXY
Key fields: users, uuid, certificate, private-key, ws-path, grpc-service-name, decryption, reality-config, proxy.
Hysteria2 listener#
listeners:
- name: hy2-in
type: hysteria2
listen: 0.0.0.0
port: 443
certificate: ./certs/server.crt
private-key: ./certs/server.key
users:
alice: password1
bob: password2
up: 100 Mbps
down: 500 Mbps
obfs: salamander
obfs-password: secret
alpn: [h3]
masquerade: https://www.example.com
proxy: PROXY
Key fields: users, certificate, private-key, up, down, obfs, obfs-password, max-idle-time, alpn, ignore-client-bandwidth, masquerade, proxy.
Protocol Selection Recommendations#
| Scenario | Recommendation |
|---|---|
| First-time validation | direct or socks5 |
| General remote proxy | hysteria2, tuic, vless, trojan, ss |
| UDP/gaming/mobile networks | Prefer hysteria2, tuic, wireguard, masque |
| Corporate intranet access | openvpn, tailscale, atrust, feilian, easyconnect |
| Router transparent proxy | A protocol that supports UDP + DNS/Fake-IP/TUN |
| Need a WARP outbound | proxy-providers.type=warp |
Compatibility Boundaries#
- A field appearing in the unified
ProxyConfigdoes not mean every protocol supports it.
- Link1 will try to report “unsupported fields” at compile time.
- Enterprise VPN protocols are affected by server-side policies, so availability across all enterprise versions cannot be guaranteed.
skip-cert-verifyis recommended only for testing or self-signed certificate scenarios.
dialer-proxychanges the dial chain. After it is configured for some protocols, direct-dial fields such asip-version,interface-name, androuting-markare disabled.