OpenSnell

Server Configuration

Every key in snell-server.conf, what it does, and the defaults you usually want.

snell-server.conf is passed via -c <path>. All keys live under the [snell-server] section.

Full example

[snell-server]
listen = 0.0.0.0:2333
psk = your-shared-secret
obfs = off
udp = true
quic = true
egress-interface =
ipv6 = true
dns =
tfo = false

Run it:

./snell-server -c snell-server.conf       # info level logs
./snell-server -c snell-server.conf -v    # debug level logs

Keys

listen (required)

Bind address(es). Set to 0.0.0.0:<port> to accept from anywhere, or 127.0.0.1:<port> when fronted by another reverse proxy. Use [::]:<port> for v6 dual-stack inbound.

When quic = true (default) the server additionally listens for UDP on the same port for QUIC proxy mode — make sure both TCP/<port> and UDP/<port> are open in any firewall in front of the host.

psk (required)

Pre-shared key. Treated as a raw UTF-8 string (not base64-decoded) — keep this exactly as configured on the client side.

obfs (optional, default off)

Obfuscation layer wrapping the snell stream.

ValueBehavior
offNo obfuscation. Recommended — the v4/v5 frame format already uses per-frame padding for traffic-shape obfuscation.
httpFake HTTP/1.1 Upgrade handshake.
tlsFake TLS ClientHello/ServerHello handshake.

udp (optional, default true)

Accept UDP-over-TCP from clients — snell's own datagram-in-stream protocol, distinct from QUIC mode below.

quic (optional, default true)

QUIC proxy mode (v5 only). When enabled, the server additionally listens on UDP/<port> from listen and accepts snell-encrypted envelopes that wrap a QUIC Initial packet; once the (src_ip, src_port) → upstream mapping is established, all subsequent UDP packets are forwarded as raw QUIC in both directions.

Required for HTTP/3 acceleration with Surge clients that have block-quic=off. See the QUIC page for the wire-level details.

egress-interface (optional, default empty)

Outbound interface binding. When set, all upstream sockets — TCP dials, UDP-over-TCP listeners, and QUIC upstream dials — are pinned to this interface via SO_BINDTODEVICE on Linux or IP_BOUND_IF on macOS. Other platforms reject this at dial time.

ipv6 (optional, default true)

Whether outbound dials may use IPv6 destinations. Matches the official Surge snell-server's ipv6 = true. When false, the dialer is constrained to tcp4 / udp4 — Go's resolver only considers A records and AAAA lookups are skipped. Useful on hosts whose IPv6 path is broken or slow.

This only affects outbound; what addresses the server listens on is still controlled by listen (write [::]:2333 for v6 dual-stack inbound).

dns (optional, default empty)

Comma-separated list of upstream DNS servers used to resolve client-requested hostnames. Empty means use the host's system resolver via /etc/resolv.conf.

Each entry is an IP literal (v4 or v6) with an optional :port suffix; if no port is given, 53 is assumed. Servers are tried in order on each lookup. Matches the official Surge snell-server's dns = … directive added in v4.1.0.

Each configured server is logged at startup as:

level=INFO msg="effective DNS" server=<addr>

tfo (optional, default false)

TCP Fast Open (RFC 7413). When enabled, both the inbound TCP listener and outbound upstream TCP dials get TFO setsockopt, allowing the snell client's first data write to ride along in the SYN packet — saving one RTT per fresh TCP connection.

Linux only (uses TCP_FASTOPEN / TCP_FASTOPEN_CONNECT). Requires the kernel sysctl net.ipv4.tcp_fastopen to have bit 1 set for the server side:

sysctl -w net.ipv4.tcp_fastopen=3

On other platforms this option is a silent no-op.

Alpha-only keys

These keys exist only on the alpha branch and have no equivalent in the official Surge snell-server. See TCP Brutal for the full deep dive.

brutal = false
brutal-mbps = 100       ; required when brutal = true
brutal-cwnd-gain = 15   ; optional; tenths (15 = 1.5x)

On this page