SNIPROXY.CONF(5)

NAME
sniproxy.conf - sniproxy configuration file

SYNOPSIS
/etc/sniproxy.conf

DESCRIPTION
/etc/sniproxy.conf is the configuration file for sniproxy. Statements are separated by either a new line or semi-colon. Lines starting with # are comments. The configuration is broken down into stanzas delimited by curly braces. Characters may be escaped using \. Configuration directives may be shortened as long as they are unambiguous e.g. user daemon instead of username daemon.

  USERNAME

username daemon

Specify the user sniproxy will run as. When sniproxy is launched as super user, it will drop permissions to this user.

  GROUPNAME

groupname _sniproxy

Specify the group sniproxy will run as after dropping privileges. Either the full groupname directive or the short group form may be used.

  PIDFILE

pidfile /var/run/sniproxy.pid

Specify the path to the pid file, the directory must be writeable by the user sniproxy runs as.

  MAX_CONNECTIONS

max_connections 20000

Limit the maximum number of simultaneously active connections accepted across all listeners. Once this threshold is reached new connections are closed immediately until existing ones complete. The default value of 0 lets sniproxy derive a ceiling from the configured RLIMIT_NOFILE value while holding roughly 20% of available descriptors in reserve for listeners, DNS sockets, and internal bookkeeping.

  PER_IP_CONNECTION_RATE

per_ip_connection_rate 20

Limit how many new TCP connections and UDP sessions a single source IP address may open per second. The value is interpreted as connections per second and is applied globally across all listeners (both TCP and DTLS) using a token-bucket policy that allows short bursts up to the configured rate. The default is 30 connections per second. Set the value to 0 to disable per-IP rate limiting entirely.

  PER_IP_MAX_CONNECTIONS

per_ip_max_connections 100

Limit the maximum number of simultaneously active TCP connections and UDP sessions from a single source IP address. When an IP reaches the limit, new connections from that address are closed immediately until existing ones complete. TCP and UDP sessions share the same counter. The default value of 0 disables the per-IP connection cap. This is distinct from per_ip_connection_rate, which limits the rate of new connections per second. per_ip_max_connections limits how many connections may be open at the same time.

  CONNECTION_BUFFER_LIMIT

connection_buffer_limit 4M

Cap the amount of buffered data a single connection may hold on either side. The value applies to both the client and server buffers, accepts optional K, M, or G suffixes (powers of 1024), and must fall between 8 KiB and 1 GiB. The default is 1 MiB per side. Tighter caps protect the proxy from slow clients pinning unbounded RAM.

  CLIENT_BUFFER_LIMIT

client_buffer_limit 8M

Override the client-side buffer cap independently using the same syntax and range as connection_buffer_limit. The most recent directive for each side wins, so a configuration may set a shared limit and then override only one direction.

  SERVER_BUFFER_LIMIT

server_buffer_limit 8M

Override the server-side buffer cap independently. This is useful for backends that return large responses relative to request size. Limits are applied to new connections immediately and propagated to existing connections during a configuration reload.

  HTTP_MAX_HEADERS

http_max_headers 200

Limit how many HTTP headers are accepted per request. The default is 100. Setting this value prevents CPU exhaustion attacks that send requests with an excessive number of headers. Values must be between 1 and 4096.

  BACKEND_ACL

backend_acl deny_except {
    10.0.0.0/8
    172.16.0.0/12
    192.168.0.0/16
}

Restrict which backend addresses sniproxy is allowed to connect to after DNS resolution. The directive takes a policy of allow_except (allow all backends except those listed) or deny_except (deny all backends except the listed ranges). When omitted all resolved addresses are permitted. This prevents abuse of sniproxy as an open proxy to reach arbitrary internal hosts. Only one backend_acl block may appear in the configuration. IPv4 and IPv6 ranges may be mixed freely, and IPv4-mapped IPv6 addresses are matched against IPv4 rules. Connections denied by the backend ACL are logged and closed immediately. The backend ACL is reloaded on SIGHUP.

  TCP_FASTOPEN

tcp_fastopen on

Enable TCP Fast Open on listener sockets (server side) and backend connect sockets (client side). When enabled, clients that support TFO can establish connections with reduced latency, and sniproxy can connect to backends faster on subsequent connections to the same host. Requires Linux 3.7+ for server-side TFO and Linux 4.11+ for client-side TFO. FreeBSD 12+ supports server-side TFO. Disabled by default. Silently ignored on platforms without TFO support.

  MAINLOOP

io_collect_interval 0.0005
timeout_collect_interval 0.005

Tune how libev batches readiness notifications. io_collect_interval delays the next poll by up to the specified number of seconds so that multiple sockets can become ready before the kernel is queried again. timeout_collect_interval performs the same batching for timers. Small non-zero values reduce system call pressure and improve throughput on busy instances at the cost of a few hundred microseconds of additional latency. Set either value to 0 to disable batching.

  ERROR_LOG

error_log {
    syslog daemon
    priority notice
}

Specify how error messages should be handled. Messages can be either logged to syslog using the syslog directive, which sends logs to a given syslog facility. Alternatively the filename directive may be specified to log to file, and these two options are mutually exclusive. The priority directive indicates what severity of messages should be logged. Accepted priorities are the standard syslog priorities, in increasing verbosity: emergency, alert, critical, error, warning, notice, info, and debug.

  ACCESS_LOG

access_log {
    filename /var/log/sniproxy/access.log
}

Specify how connections should be logged, and this may be overridden in a specific listener. Connections are logged after both the client and server sockets have been closed. The syslog and priority directive may be used here as in error_log.

  RESOLVER

resolver {
    nameserver 127.0.0.1
    mode ipv6_first
    max_concurrent_queries_per_client 16
}

Specify how DNS queries should be resolved, which is only required if using hostnames as addresses in the configuration or using wildcard backends. If not specified the IPv4 only queries will be performed using the system default name servers. Multiple nameserver directives may be supplied. Optional search directives append the given domain to hostnames that do not already end with a trailing dot before resolution. Nameservers may point at DNS-over-TLS upstreams using the dot://ADDRESS/SNI[/tls1.2|tls1.3] form. ADDRESS can be an IP literal or hostname; when using an IP literal you must also supply a TLS hostname or the literal insecure segment to disable verification. TLS 1.2 is the default minimum; append /tls1.3 to require TLS 1.3 on builds that support it. On OpenSSL without TLS 1.3, /tls1.3 is ignored with a warning and TLS 1.2 is enforced. Four modes are supported: ipv4_only: query for any A records, use the first A record returned (following CNAME records). ipv6_only: query for any AAAA records, use the first AAAA record returned (following CNAME records). ipv4_first: query for both A and AAAA records, wait for both queries to complete, use the first A record if any, otherwise use the first AAAA record. ipv6_first: query for both A and AAAA records, wait for both queries to complete, use the first AAAA record if any, otherwise use the first A record. The optional max_concurrent_queries directive limits how many DNS lookups may be in flight at once (default 512). Lower values cap resolver resource usage, while higher values increase throughput for configurations that rely on wildcard or hostname targets. The optional max_concurrent_queries_per_client directive limits how many DNS lookups a single source IP may have in flight at once (default 16). Set to 0 to disable the per-client guard. Set dnssec_validation to one of 'off', 'relaxed', or 'strict'. The default is relaxed, which requests DNSSEC data but falls back to unsigned answers when your resolver cannot authenticate the response. The strict mode requires the AD flag, so unsigned zones fail to resolve and a c-ares build with DNSSEC/Trust AD support is mandatory. Use 'off' to disable DNSSEC entirely if your upstream resolvers do not support it. It is strongly recommended to use a local name server, since a single socket is reused for all DNS queries and thus the UDP port number is predictable, leaving the query only protected from spoofed replies by the 16 bit query ID. Additionally, since no internal DNS caching is performed, a local resolver can improve performance.

  LISTENER

listener 192.0.2.10:80 {
    protocol http
    reuseport yes
    table http_hosts
    fallback 192.0.2.100:80
    bad_requests log
    source 192.0.2.10
    access_log {
        filename /var/log/sniproxy/http_access.log
    }
}
listener [::]:80 {
    protocol http
    ipv6_v6only yes
    table http_hosts
    fallback unix:/var/run/http_fallback_unix.sock
}
listener 0.0.0.0 4443 {
    protocol dtls
    table dtls_backends
}

Define a listening address to accept new connections from clients on. Addresses may be specified as an IPv4 literal followed by a port number, an IPv6 literal followed by a port number, a bare port number, or a unix socket path prefixed with 'unix:'. Protocol defines how the client request should be parsed to obtain the requested hostname. Five protocols are supported: tls, http, xmpp, minecraft, and dtls. The minecraft protocol defaults to port 25565. The dtls protocol proxies DTLS (TLS over UDP) connections by extracting the SNI extension from the DTLS ClientHello, enabling proxying of WebRTC, OpenConnect VPN, CoAP, and other UDP/DTLS protocols by hostname without decryption. To prevent UDP reflection/amplification attacks, new DTLS sessions require a retransmission from the client before the backend is contacted (DTLS clients retransmit by design per RFC 6347). Spoofed sources never retransmit and are silently dropped after a 3-second validation timeout. Reuseport directive controls if the port is opened in SO_REUSEPORT mode, which allows one to run several sniproxy instances on the same ip:port pair. This enables evenly load-balancing incoming connections between these instances without the use of any external load-balancing proxy. Requires Linux kernel 3.9+. Setting reuseport to "yes" enables this functionality. The ipv6_v6only directive controls whether listening on the IPv6 any address '::' will accept connections to any IPv4 address as well as an IPv6 address. This is useful if the user wants different configurations for IPv4 and IPv6 or wishes to handle IPv4 traffic with another server/proxy entirely. This directive applies only to IPv6 listeners and is ignored on other listeners. Table specifies the name of the table used to look up which server to forward the connection to based on the hostname extracted from the initial client request. If no table directive is specified the default, unnamed, table will be used. The fallback directive specifies a server to be used if the client request cannot be parsed, a server cannot be found in the table for the hostname, or the hostname cannot be resolved. This should be an IP address and port or a unix socket path. When using TLS listeners the fallback still terminates the client TLS handshake and forwards the traffic unmodified to the configured destination. Issuing a second fallback directive with the literal argument proxy_protocol after the address instructs sniproxy to prepend an HAProxy PROXY protocol v1 (text) header whenever the fallback path is taken, allowing the backend to recover the original client IP and port. Use proxy_protocol_v2 instead to send the binary v2 format. The bad_requests directive allows logging the contents of the client request if it is not parsable. This is useful for debugging. The proxy_protocol directive enables acceptance of incoming HAProxy PROXY protocol headers (both v1 text and v2 binary formats are auto-detected). When enabled, sniproxy parses the PROXY header from the upstream proxy or load balancer, extracts the original client address, and uses it for access logging and any outgoing PROXY protocol headers to backends. This allows chaining sniproxy behind load balancers (e.g. AWS NLB, HAProxy) or other sniproxy instances while preserving the real client IP. Note that ACL and per-IP rate limiting are applied to the direct peer address (the upstream proxy for TCP, or the UDP source address for DTLS), not the address from the PROXY header. The source directive allows specifying an address to bind to before connecting to the backend server. In most cases it is better to omit this option and allow the operating system to select the outgoing address automatically. Do not include a port number in this address, because doing so will limit the proxy to one simultaneous connection to each server at a time. The special argument client enables transparent proxy mode (IP_TRANSPARENT) where supported, preserving the original source address when connecting to the backend. This mode requires root privileges and an operating system that implements transparent sockets (such as Linux). An optional acl block restricts which clients may connect to a listener based on CIDR ranges. The directive takes a default policy of either allow_except (the default, accept every client except those listed) or deny_except (deny every client except the listed ranges):
    acl deny_except {
        10.0.0.0/8
        2001:db8::/32
    }
When an acl block is omitted every client is accepted. Multiple statements may be provided in a block. IPv4 and IPv6 ranges may be mixed freely, and IPv4-mapped IPv6 addresses are matched against IPv4 ranges. The policy choice is global: mixing allow_except and deny_except blocks anywhere in the configuration causes sniproxy to exit with a configuration error. The access log configuration may be overridden on each listener.

  TABLE

table http_hosts {
    example.com 192.0.2.101
    example.net 192.0.2.102
    example.org 192.0.2.103 proxy_protocol
}

Tables define how to map each hostname to a backend server. Each request's hostname is matched against entries in the table in order until a match is found and that server is used. The server address may be either an IP, an IP and port, a unix socket path, a hostname, or '*'. If no port is specified, the port of the listener that received the connection will be used. Table entries that contain no regex metacharacters (\ * + ? [ ] ( ) { } ^ $ |) are treated as literal hostnames: dots are escaped and the pattern is anchored with ^ and $ automatically. For example, example.com is compiled as ^example\.com$ and will only match the exact hostname "example.com", not "sub.example.com". When auto-anchoring is applied a notice-level log message is emitted showing the original and rewritten pattern. Entries that contain any regex metacharacter are compiled as-is, giving full PCRE2 regex control. The optional proxy_protocol option will prepend a HAProxy PROXY v1 (text) protocol header to the proxied connection, allowing supporting webservers to obtain the source and destination IP and port of the original incoming TCP connection. Use proxy_protocol_v2 instead to send the binary v2 format. The backend_affinity directive enables consistent backend selection based on the client's IP address. When a DNS lookup for a wildcard or hostname backend returns multiple A/AAAA records, the record is chosen by hashing the client IP so the same client always reaches the same backend. This is useful for session persistence with DNS round-robin backends. The default is off (first DNS result is always used).

CAVEATS

  HTTP/2 CONNECTION COALESCING
HTTP/2 clients may reuse an existing TLS connection for a different hostname when both names resolve to the same IP and the server certificate covers both (e.g. a wildcard certificate). Since all proxied hostnames point at the sniproxy address, the IP condition is always satisfied. When the backend presents a shared certificate the browser multiplexes requests for several hostnames over a single TCP connection. Because sniproxy routes once per connection based on the SNI in the TLS ClientHello and cannot inspect encrypted HTTP/2 frames, those extra hostnames are silently delivered to the wrong backend. Symptoms include 404 errors, CORS failures, or content served from the wrong origin.

Workarounds:

•   Use per-domain certificates instead of wildcard or multi-SAN certificates.

•   Assign a separate IP address to each proxied hostname.

•   Disable HTTP/2 on the backend by removing h2 from ALPN negotiation.

•   Configure backends to return HTTP 421 (Misdirected Request) for hostnames they do not serve (RFC 9110).

SEE ALSO

sniproxy(8)