shoes uses YAML configuration files. Multiple configuration types can be combined in a single file or split across multiple files.
- Configuration Structure
- Server Config
- Server Protocols
- TUN Config
- Client Config
- Client Protocols
- Rules System
- Named Groups
- Named PEMs
- Advanced Features
- Command Line
A configuration file is a YAML array containing one or more configuration entries. Each entry can be:
- Server Config - Defines a proxy server instance
- TUN Config - Defines a TUN/VPN device for transparent proxying
- Client Config Group - Defines reusable upstream proxy configurations
- Rule Config Group - Defines reusable routing rules
- Named PEM - Defines reusable certificate/key data
# Server configs have 'address' or 'path'
- address: "0.0.0.0:8080"
protocol: ...
# TUN configs have 'device_name' or 'device_fd'
- device_name: "tun0"
address: "10.0.0.1"
...
# Client config groups have 'client_group'
- client_group: my-upstream
client_proxy: ...
# Rule config groups have 'rule_group'
- rule_group: my-rules
rules: ...
# Named PEMs have 'pem'
- pem: my-cert
path: /path/to/cert.pem# Bind to IP address and port
address: "0.0.0.0:8080" # IPv4
address: "[::]:8080" # IPv6
address: "0.0.0.0:443-445" # Port range
# OR bind to Unix socket (TCP only)
path: "/tmp/shoes.sock"
# Protocol configuration (required)
protocol: ServerProxyConfig
# Transport layer (default: tcp)
transport: tcp | quic
# TCP settings (only when transport: tcp)
tcp_settings:
no_delay: true # Default: true
# QUIC settings (required when transport: quic)
quic_settings:
cert: string # TLS certificate (path or named PEM)
key: string # TLS private key (path or named PEM)
alpn_protocols: [string] # Optional ALPN protocols
client_ca_certs: [string] # Optional client CA certificates
client_fingerprints: [string] # Optional client certificate fingerprints
num_endpoints: int # Optional, 0 = auto (based on thread count)
# Routing rules (default: allow-all-direct)
rules: string | [RuleConfig]protocol:
type: http
username: string? # Optional authentication
password: string?protocol:
type: socks # Aliases: socks5
username: string?
password: string?
udp_enabled: true # Default: true (enables UDP ASSOCIATE)protocol:
type: mixed # Aliases: http+socks, socks+http
username: string?
password: string?
udp_enabled: true # Default: true (enables UDP ASSOCIATE for SOCKS5)Auto-detects HTTP or SOCKS5 protocol from the first byte of the connection.
protocol:
type: shadowsocks # Aliases: ss
cipher: string # See supported ciphers below
password: string
# Supported ciphers:
# - aes-128-gcm
# - aes-256-gcm
# - chacha20-ietf-poly1305
# - 2022-blake3-aes-128-gcm
# - 2022-blake3-aes-256-gcm
# - 2022-blake3-chacha20-ietf-poly1305protocol:
type: vmess
cipher: string # aes-128-gcm, chacha20-poly1305, none
user_id: string # UUID
udp_enabled: true # Default: true (enables XUDP)Note: VMess AEAD mode is always enabled. The legacy force_aead field is deprecated and non-AEAD mode is no longer supported.
protocol:
type: vless
user_id: string # UUID
udp_enabled: true # Default: true (enables XUDP)
fallback: string? # Optional fallback destination for failed auth (e.g., "127.0.0.1:80")protocol:
type: trojan
password: string
shadowsocks: # Optional encryption layer
cipher: string
password: stringprotocol:
type: snell
cipher: string # aes-128-gcm, aes-256-gcm, chacha20-ietf-poly1305
password: string
udp_enabled: true # Default: true
udp_num_sockets: 1 # Default: 1, sockets per UDP sessionprotocol:
type: tls
# Standard TLS targets (by SNI)
tls_targets: # Aliases: sni_targets, targets
"example.com":
cert: string # Certificate (path or named PEM)
key: string # Private key (path or named PEM)
alpn_protocols: [string] # Optional ALPN
client_ca_certs: [string] # Optional client CA certs
client_fingerprints: [string] # Optional client cert fingerprints
vision: false # Enable Vision (requires VLESS inner protocol)
protocol: ServerProxyConfig
override_rules: [RuleConfig] # Optional rule override
# Default TLS target (for unmatched/no SNI)
default_tls_target: # Aliases: default_target
cert: string
key: string
# ... same fields as tls_targets
# Reality targets (by SNI)
reality_targets:
"www.cloudflare.com":
private_key: string # X25519 private key (base64url)
short_ids: [string] # Valid client IDs (hex, 0-16 chars)
dest: string # Fallback destination (e.g., "example.com:443")
dest_client_chain: ClientChain? # Optional proxy chain for reaching dest
max_time_diff: 60000 # Max timestamp diff in ms (default: 60000)
min_client_version: [1, 8, 0] # Optional [major, minor, patch]
max_client_version: [2, 0, 0] # Optional [major, minor, patch]
cipher_suites: [string] # Optional TLS 1.3 cipher suites (see below)
vision: false # Enable Vision (requires VLESS inner protocol)
protocol: ServerProxyConfig
override_rules: [RuleConfig]
# ShadowTLS v3 targets (by SNI)
shadowtls_targets:
"example.com":
password: string
handshake:
# Local handshake (with own certificate):
cert: string
key: string
alpn_protocols: [string]
client_ca_certs: [string]
client_fingerprints: [string]
# OR Remote handshake (proxy to real server):
address: string # e.g., "google.com:443"
client_proxies: [ClientConfig] # Optional proxies for handshake
protocol: ServerProxyConfig
override_rules: [RuleConfig]
# Buffer size for TLS (optional, min 16384)
tls_buffer_size: intprotocol:
type: websocket # Aliases: ws
targets:
- matching_path: string? # Optional path filter (e.g., "/ws")
matching_headers: # Optional header filters
X-Custom-Header: "value"
protocol: ServerProxyConfig
ping_type: ping-frame # disabled | ping-frame | empty-frame
override_rules: [RuleConfig]protocol:
type: forward # Aliases: port_forward, portforward
targets: string | [string] # Target address(es)protocol:
type: hysteria2
password: string
udp_enabled: true # Default: trueprotocol:
type: tuic # Aliases: tuicv5
uuid: string # UUID
password: string
zero_rtt_handshake: false # Default: false (enables 0-RTT for lower latency)protocol:
type: anytls
users: # One or more users
- name: string? # Optional display name
password: string # User password
udp_enabled: true # Default: true (enables UDP over TCP)
padding_scheme: [string]? # Optional custom padding (e.g., ["stop=8", "0=30-30"])
fallback: string? # Optional fallback destination for failed authAnyTLS is a TLS-based multiplexing proxy protocol with traffic obfuscation. Should be used within TLS or Reality.
protocol:
type: naiveproxy # Aliases: naive
users: # One or more users
- name: string? # Optional display name
username: string # Basic Auth username
password: string # Basic Auth password
padding: true # Default: true (enables padding protocol)
udp_enabled: true # Default: true (enables UDP over TCP)
fallback: string? # Optional path to serve static files for probe resistanceNaiveProxy implements HTTP/2 CONNECT with padding for censorship resistance. Should be used within TLS with alpn_protocols: ["h2"].
TUN (network TUNnel) devices operate at the IP layer (Layer 3), allowing shoes to act as a transparent VPN.
# Linux: Create TUN device by name
device_name: string # Device name (e.g., "tun0")
address: string # Device IP address (e.g., "10.0.0.1")
netmask: string? # Netmask (e.g., "255.255.255.0")
destination: string? # Gateway/destination (Linux only)
# iOS/Android: Use existing file descriptor
device_fd: int # FD from VpnService (Android) or NEPacketTunnelProvider (iOS)
# Common settings
mtu: 1500 # Default: 1500 (Linux), 9000 (Android), 4064 (iOS)
tcp_enabled: true # Default: true
udp_enabled: true # Default: true
icmp_enabled: true # Default: true
# Routing rules
rules: [RuleConfig]Platform notes:
- Linux: Requires root or
CAP_NET_ADMIN. Creates device with specified name/address. - Android: Use
device_fdfromVpnService.Builder.establish(). Routes configured via VpnService. - iOS: Use
device_fdfromNEPacketTunnelProvider.packetFlow.
Example (Linux):
- device_name: "tun0"
address: "10.0.0.1"
netmask: "255.255.255.0"
mtu: 1500
tcp_enabled: true
udp_enabled: true
rules:
- masks: "0.0.0.0/0"
action: allow
client_chain:
address: "proxy.example.com:443"
protocol:
type: tls
protocol:
type: vless
user_id: "uuid"Used in rules to specify upstream proxies.
address: string # Proxy server address (e.g., "proxy.example.com:1080")
protocol: ClientProxyConfig
transport: tcp | quic # Default: tcp
bind_interface: string # Optional, Linux/Android/Fuchsia only
tcp_settings:
no_delay: true
quic_settings:
verify: true # Default: true
server_fingerprints: [string]
sni_hostname: string
alpn_protocols: [string]
cert: string # Client certificate for mTLS
key: string # Client key for mTLSprotocol:
type: directprotocol:
type: http
username: string?
password: string?protocol:
type: socks
username: string?
password: string?protocol:
type: shadowsocks
cipher: string
password: stringprotocol:
type: snell
cipher: string
password: stringprotocol:
type: vmess
cipher: string
user_id: string
h2mux: # Optional h2mux multiplexing (see below)
max_connections: 4
min_streams: 4
max_streams: 0
padding: falseNote: VMess AEAD mode is always enabled. The legacy aead field is deprecated.
protocol:
type: vless
user_id: string
h2mux: # Optional h2mux multiplexing (see below)
max_connections: 4
min_streams: 4
max_streams: 0
padding: falseprotocol:
type: trojan
password: string
shadowsocks: # Optional
cipher: string
password: string
h2mux: # Optional h2mux multiplexing (see below)
max_connections: 4
min_streams: 4
max_streams: 0
padding: falseH2MUX multiplexes multiple proxy streams over a single HTTP/2 connection, reducing connection overhead. Compatible with sing-box. Available for VMess, VLESS, and Trojan client protocols.
h2mux:
max_connections: 4 # Maximum connections to maintain (default: 4)
min_streams: 4 # Min streams before opening new connection (default: 4)
max_streams: 0 # Max streams per connection, 0 = unlimited (default: 0)
padding: false # Enable padding for traffic obfuscation (default: false)Server support: H2MUX is auto-detected on servers. No configuration needed.
protocol:
type: tls
verify: true # Default: true
server_fingerprints: [string]
sni_hostname: string
alpn_protocols: [string]
tls_buffer_size: int
cert: string # Client certificate for mTLS
key: string # Client key for mTLS
vision: false # Enable Vision (requires VLESS inner protocol)
protocol: ClientProxyConfigprotocol:
type: reality
public_key: string # Server's X25519 public key (base64url)
short_id: string # Your client ID (hex, 0-16 chars)
sni_hostname: string # SNI to send (must match server's reality_targets key)
cipher_suites: [string] # Optional TLS 1.3 cipher suites (see below)
vision: false # Enable Vision (requires VLESS inner protocol)
protocol: ClientProxyConfig # Inner protocol (typically VLESS)Reality cipher suites: Valid values are TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256. If not specified, all three are offered/supported.
protocol:
type: shadowtls
password: string
sni_hostname: string? # Optional SNI override
protocol: ClientProxyConfigprotocol:
type: websocket
matching_path: string?
matching_headers:
header_name: string
ping_type: ping-frame # disabled | ping-frame | empty-frame
protocol: ClientProxyConfigprotocol:
type: portforward # Aliases: noopPasses through the raw connection without protocol wrapping. Useful for testing or transparent proxying.
protocol:
type: anytls
password: string # User password
udp_enabled: true # Default: true (enables UDP over TCP)
padding_scheme: [string]? # Optional custom padding schemeprotocol:
type: naiveproxy # Aliases: naive
username: string # Basic Auth username
password: string # Basic Auth password
padding: true # Default: true (enables padding protocol)Rules determine how incoming connections are routed.
rules:
- masks: string | [string] # IP/CIDR or hostname masks
action: allow | block
# For action: allow
override_address: string? # Optional address override
client_chain: ClientChain | [ClientChain] # Proxy chain(s) for routingClient chains define how traffic is routed through upstream proxies. Each chain is a sequence of "hops" - proxies that traffic passes through in order.
# Single proxy (simplest form)
client_chain: my-proxy-group # Reference a named group
client_chain: # Or inline config
address: "proxy.example.com:1080"
protocol:
type: socks
# Multi-hop chain (traffic goes: client -> hop1 -> hop2 -> target)
client_chain:
chain:
- first-proxy-group
- second-proxy-group
# Multiple chains (round-robin selection)
client_chains:
- us-proxy-group # Chain 1: single hop
- chain: [proxy1, proxy2] # Chain 2: multi-hop
# Load balancing at a hop (pool)
client_chain:
chain:
- pool: [us-proxies, eu-proxies] # Round-robin between pool members
- final-proxyMigration note: The client_proxy / client_proxies fields still work but are deprecated. Please migrate to client_chain / client_chains.
# IP/CIDR masks
masks: "0.0.0.0/0" # All IPv4
masks: "::/0" # All IPv6
masks: "192.168.0.0/16" # Subnet
masks: "10.0.0.1:80" # Specific IP and port
# Hostname masks
masks: "*.google.com" # Wildcard subdomain
masks: "example.com" # Exact match
# Multiple masks
masks:
- "192.168.0.0/16"
- "10.0.0.0/8"
- "*.internal.com"allow-all-direct- Allow all connections, direct routingblock-all- Block all connections
rules:
# Direct connection for local networks
- masks: ["192.168.0.0/16", "10.0.0.0/8", "172.16.0.0/12"]
action: allow
client_chain:
protocol:
type: direct
# Block specific domains
- masks: ["*.ads.example.com", "tracking.example.com"]
action: block
# Route through upstream proxy
- masks: "0.0.0.0/0"
action: allow
client_chain:
address: "proxy.example.com:1080"
protocol:
type: socks- client_group: my-upstream
client_proxies: # Define proxies in this group
- address: "proxy1.example.com:1080"
protocol:
type: socks
- address: "proxy2.example.com:1080"
protocol:
type: socks
# Reference in rules
- address: "0.0.0.0:8080"
protocol:
type: http
rules:
- masks: "0.0.0.0/0"
action: allow
client_chain: my-upstream # Reference by name- rule_group: standard-rules
rules:
- masks: ["192.168.0.0/16"]
action: allow
client_chain:
protocol:
type: direct
- masks: "0.0.0.0/0"
action: allow
client_chain: my-upstream
# Reference in server config
- address: "0.0.0.0:8080"
protocol:
type: http
rules: standard-rules # Reference by nameDefine certificates once and reference throughout configuration.
# From file
- pem: my-cert
path: /path/to/certificate.pem
# Inline data
- pem: my-key
data: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
# Reference in config
- address: "0.0.0.0:443"
protocol:
type: tls
tls_targets:
"example.com":
cert: my-cert # Reference by name
key: my-key
protocol:
type: httpVision optimizes TLS-in-TLS scenarios by detecting inner TLS traffic and switching to direct mode for zero-copy performance.
Requirements:
- Inner protocol MUST be VLESS
- Works with both TLS and Reality
# TLS + Vision
protocol:
type: tls
tls_targets:
"example.com":
cert: cert.pem
key: key.pem
vision: true
alpn_protocols: ["http/1.1"]
protocol:
type: vless
user_id: "uuid"
# Reality + Vision
protocol:
type: tls
reality_targets:
"www.google.com":
private_key: "..."
short_ids: ["..."]
dest: "www.google.com:443"
vision: true
protocol:
type: vless
user_id: "uuid"Automatically enabled for VMess and VLESS when udp_enabled: true. Multiplexes UDP traffic over a single connection.
Protocol nesting (wrap one protocol in another):
client_chain:
address: "proxy.example.com:443"
protocol:
type: tls
protocol:
type: vmess
cipher: aes-128-gcm
user_id: "uuid"Multi-hop chains (route through multiple proxies sequentially):
client_chain:
chain:
- address: "proxy1.example.com:1080"
protocol:
type: socks
- address: "proxy2.example.com:443"
protocol:
type: tls
protocol:
type: vless
user_id: "uuid"Configuration changes are automatically detected and applied without restarting. Disable with --no-reload flag.
Require client certificates for authentication:
# Server side
protocol:
type: tls
tls_targets:
"example.com":
cert: server.crt
key: server.key
client_ca_certs: [ca.crt] # Required CA
client_fingerprints: ["sha256:..."] # Optional specific certs
protocol: ...
# Client side
client_chain:
address: "example.com:443"
protocol:
type: tls
cert: client.crt
key: client.key
protocol: ...shoes [OPTIONS] <config.yaml> [config.yaml...]
OPTIONS:
-t, --threads NUM Worker threads (default: CPU count)
-d, --dry-run Parse config and exit
--no-reload Disable hot-reloading
COMMANDS:
generate-reality-keypair Generate Reality X25519 keypair
generate-shadowsocks-2022-password <cipher> Generate Shadowsocks 2022 passwordReality keypair:
shoes generate-reality-keypairShadowsocks 2022 password:
shoes generate-shadowsocks-2022-password 2022-blake3-aes-256-gcmUUID:
uuidgenTLS certificate fingerprint:
openssl x509 -in cert.pem -noout -fingerprint -sha256- Use strong, random passwords
- Keep private keys secure
- Use
127.0.0.1instead of0.0.0.0for local-only access - Use firewall rules to restrict access
- Enable client certificate authentication for sensitive services
- Use Vision with Reality for maximum privacy
- Enable
vision: truefor TLS-in-TLS scenarios - Use
tcp_settings.no_delay: truefor low latency - Set
quic_settings.num_endpointsto match worker threads - Use QUIC transport for high-latency or lossy networks
- "Address already in use": Change port or stop conflicting service
- "Permission denied": Ports < 1024 require root/admin
- Reality connection fails: Verify keys match, UUID matches, SNI matches server's reality_targets key
- Vision not working: Ensure inner protocol is VLESS
- Config validation fails: Run with
--dry-runfor detailed errors