tobaru uses YAML configuration files. Multiple configuration types can be combined in a single file or split across multiple files.
- Configuration Structure
- Server Config
- TCP Targets
- Server TLS
- Client TLS
- HTTP Routing
- HTTP Actions
- UDP Targets
- IP Groups
- URL-Based Configuration
- Command Line
A configuration file is a YAML array containing one or more entries. Each entry can be:
- Server Config -- defines a listener with one or more forwarding targets
- IP Group -- defines a reusable named set of IP ranges
# Server config (has 'address')
- address: "0.0.0.0:443"
transport: tcp
targets:
- location: backend:443
allowlist: 0.0.0.0/0
# IP group (has 'group')
- group: internal
ip_masks:
- 192.168.0.0/16
- 10.0.0.0/8Multiple config files can be passed on the command line and are merged together. This is useful for separating IP group definitions from server definitions.
- YAML:
.ymlor.yamlextension (recommended) - JSON:
.jsonextension, with optional//single-line comments
address: "0.0.0.0:8080" # Bind address (required)
transport: tcp | udp # Default: tcp
# TCP-specific settings (only when transport: tcp)
tcp_nodelay: true # Disable Nagle's algorithm (default: true)
tcp_keepalive: true | false | null | { idle_secs: int, interval_secs: int }
use_iptables: false # Auto-configure iptables rules (default: false)
# One or more targets
target: TcpTargetConfig # Single target
targets: [TcpTargetConfig] # Multiple targetsaddress: "0.0.0.0:8080" # IPv4
address: "[::]:8080" # IPv6Controls TCP keepalive probes on the server-side (client-facing) socket.
# Use defaults (idle: 300s, interval: 60s)
tcp_keepalive: true # or omit the field
# Disable keepalive
tcp_keepalive: false
tcp_keepalive: null
# Custom values
tcp_keepalive:
idle_secs: 120
interval_secs: 30When use_iptables: true, tobaru automatically configures iptables/ip6tables rules to drop packets from IPs not in the allowlist at the kernel level, before they reach the application.
Requires root or CAP_NET_RAW + CAP_NET_ADMIN capabilities. Supported on Linux only.
# Clear all tobaru-managed iptables rules
sudo tobaru --clear-iptables-all
# Clear rules for specific config files only
sudo tobaru --clear-iptables-matching config.yamlEach TCP target defines a forwarding destination with access control and optional TLS.
targets:
- allowlist: string | [string] # IP masks or group names (required)
location: string # Single backend address (e.g., "backend:8080")
locations: [string | object] # Multiple backends (round-robin)
server_tls: ServerTlsConfig # Optional incoming TLS config
tcp_nodelay: true # Default: true
tcp_keepalive: ... # Same options as server-level (default idle: 120s, interval: 30s)target (singular) is an alias for a single-element targets array.
Locations specify where to forward traffic. Each location is either a plain address string or an object with additional settings.
# Simple string address
location: backend:8080
# UNIX domain socket path
location:
path: /run/app.sock
# Address with outgoing TLS
location:
address: upstream.example.com:443
client_tls:
verify: true
# Multiple backends (round-robin load balancing)
locations:
- backend1:8080
- backend2:8080
- backend3:8080The address and addresses field names are accepted as aliases for location and locations.
Controls which source IPs may connect to this target. Connections from IPs not matching any allowlist entry are rejected.
# Allow all IPv4
allowlist: 0.0.0.0/0
# Multiple CIDR ranges
allowlist:
- 192.168.1.0/24
- 10.0.0.0/8
# Specific addresses
allowlist:
- 1.2.3.4
- 2001:db8::1
# Named IP groups
allowlist:
- internal
- trusted
# Mix of literals and groups
allowlist:
- internal
- 203.0.113.0/24When multiple targets are defined, they are evaluated in order. The first target whose allowlist matches the client IP (and whose TLS settings match the connection, if applicable) handles the connection.
targets:
# Internal users get admin backend
- location: admin-backend:8080
allowlist: 10.0.0.0/8
server_tls:
mode: passthrough
sni_hostnames: app.example.com
# Everyone else gets public backend
- location: public-backend:8080
allowlist: 0.0.0.0/0
server_tls:
mode: passthrough
sni_hostnames: app.example.comConfigures TLS handling for incoming connections.
server_tls:
mode: terminate | passthrough # Default: terminate
# SNI hostname matching
sni_hostnames: string | [string] # Hostname patterns (see below)
# ALPN protocol matching
alpn_protocols: string | [string]
# Certificate (required for terminate mode)
cert: string # Path to certificate file
key: string # Path to private key file
# Client certificate authentication (terminate mode only)
client_ca_certs: [string] # Paths to CA certificate PEM files
client_fingerprints: [string] # SHA256 fingerprints
# Deprecated
optional: false # Auto-migrated to two separate targetsPassthrough -- reads the SNI and ALPN from the TLS ClientHello without decrypting. The raw TLS stream is forwarded transparently to the backend. No certificate or key is needed on the proxy.
Terminate (default) -- performs a full TLS handshake, decrypts the traffic, and can inspect HTTP content before forwarding. Requires cert and key.
Both modes can coexist on the same port for different SNI hostnames:
targets:
# Passthrough for public API
- location: api-backend:443
allowlist: 0.0.0.0/0
server_tls:
mode: passthrough
sni_hostnames: api.example.com
# Terminate for admin panel
- location: admin-backend:8080
allowlist: 10.0.0.0/8
server_tls:
mode: terminate
cert: admin.crt
key: admin.key
sni_hostnames: admin.example.comsni_hostnames: example.com # Exact match only
sni_hostnames: "*.example.com" # Any subdomain, but NOT example.com itself
sni_hostnames: ".example.com" # example.com AND all subdomains
sni_hostnames: any # Any SNI value
sni_hostnames: none # Connections with no SNI
sni_hostnames: # Multiple patterns
- api.example.com
- "*.cdn.example.com"
- any
- noneMatching priority: exact match > deepest wildcard > shallower wildcard.
Hostnames are case-insensitive. Trailing dots are stripped.
In passthrough mode, ALPN protocols from the ClientHello are matched against the configured list. In terminate mode, the configured protocols are advertised in the ServerHello.
alpn_protocols: h2 # Single protocol
alpn_protocols: # Multiple protocols
- h2
- http/1.1
alpn_protocols: any # Match any ALPN
alpn_protocols: none # Match only when no ALPNRequires clients to present a valid certificate. Only available in terminate mode (TLS 1.3 sends client certificates inside the encrypted tunnel, so passthrough mode cannot inspect them).
Two methods are supported and can be combined:
client_ca_certs-- accept any client certificate that chains to one of the provided CA certificatesclient_fingerprints-- accept client certificates matching specific SHA256 fingerprints
When both are configured, a certificate is accepted if it passes either check.
server_tls:
mode: terminate
cert: server.crt
key: server.key
sni_hostnames: secure.example.com
# Accept any cert signed by this CA
client_ca_certs:
- /path/to/ca.crt
# Also accept these specific self-signed certs
client_fingerprints:
- "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
- "1122334455667788990011223344556677889900112233445566778899001122"Fingerprints accept both colon-separated and plain hex formats.
# Generate a CA and client certificate
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
-nodes -keyout ca.key -out ca.crt -days 365 -subj "/CN=MyCA"
openssl ecparam -genkey -name prime256v1 -out client.key
openssl req -new -key client.key -out client.csr -subj "/CN=Client"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out client.crt -days 365
# Get a certificate's SHA256 fingerprint
openssl x509 -in client.crt -noout -fingerprint -sha256Configures TLS for outgoing connections to backend servers. Set within a location object.
location:
address: upstream.example.com:443
client_tls:
verify: true # Verify server cert via WebPKI (default: true)
cert: string # Client certificate for mTLS
key: string # Client private key for mTLS
sni_hostname: string | null # SNI to send (default: derived from address, null to disable)
alpn_protocols: [string] # ALPN protocols to negotiate
server_fingerprints: [string] # SHA256 fingerprints for cert pinning# Enable with defaults (verify: true)
client_tls: true
# Enable with verification disabled
client_tls: "no-verify"
# Full object form
client_tls:
verify: true
sni_hostname: custom.example.com
server_fingerprints:
- "AA:BB:CC:..."client_tls cannot be used with passthrough mode (would cause TLS-in-TLS).
client_tls:
server_fingerprints:
- "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"# Get a server's certificate fingerprint
openssl s_client -connect example.com:443 < /dev/null 2>/dev/null | openssl x509 -outform PEM > server.crt
openssl x509 -in server.crt -noout -fingerprint -sha256HTTP path-based routing is available when TLS is terminated (or for plain HTTP). A target with http_paths and/or default_http_action is treated as an HTTP target.
target:
allowlist: 0.0.0.0/0
http_paths:
/api/:
http_action:
type: forward
addresses:
- api-backend:8080
/static/:
http_action:
type: serve-directory
path: /var/www/static
default_http_action:
type: forward
addresses:
- default-backend:8080Paths are matched by longest prefix. A trailing / in the path key matches that prefix and everything below it.
http_paths:
/api/: # matches /api/, /api/users, /api/v2/foo, etc.
/health: # matches /health exactlyEach path entry can require specific HTTP headers to match. Header keys are case-insensitive.
http_paths:
/:
- required_request_headers:
x-api-key: secret123
http_action:
type: forward
addresses: [backend:8080]
- required_request_headers:
host: app.example.com
http_action:
type: forward
addresses: [app-backend:8080]When multiple entries exist under the same path, they are evaluated in order. The first match wins.
The host key in required_request_headers supports the same wildcard patterns as sni_hostnames. Port suffixes in the Host header (e.g., example.com:8080) are automatically stripped before matching.
http_paths:
/:
# Exact match
- required_request_headers:
host: app.example.com
http_action:
type: forward
addresses: [app-backend:8080]
# Wildcard subdomains
- required_request_headers:
host: "*.api.example.com"
http_action:
type: forward
addresses: [api-backend:8080]
# Base domain + all subdomains
- required_request_headers:
host: ".example.com"
http_action:
type: forward
addresses: [default-backend:8080]
default_http_action:
type: serve-message
status_code: 404When possible, prefer SNI-level routing (sni_hostnames) over Host header matching. SNI routing operates at the TLS layer before HTTP parsing, avoiding the overhead of decryption and request parsing. Host header routing is useful for plain HTTP, or when multiple virtual hosts share the same TLS certificate.
Forwards the HTTP request to one or more backend servers. Supports connection keep-alive, WebSocket upgrades, and header manipulation.
http_action:
type: forward
locations: [string | object] # Backend address(es) -- round-robin if multiple
replacement_path: string # Rewrite the request path
request_header_patch: # Modify request headers
default_headers: # Add if not already present
X-Forwarded-For: "..."
overwrite_headers: # Set unconditionally
Host: backend.internal
remove_headers: # Remove
- X-Debug
response_header_patch: # Modify response headers (same structure)
overwrite_headers:
X-Served-By: tobaru
request_id_header_name: string # Add a unique request ID header to the request
response_id_header_name: string # Add a unique request ID header to the responseThe address, addresses, and location field names are accepted as aliases for locations.
Returns a static HTTP response.
http_action:
type: serve-message
status_code: 200 # HTTP status code (required)
status_message: "OK" # Custom status text (optional)
content: "Hello, world!" # Response body (default: "")
response_headers: # Custom response headers
Content-Type: "text/plain"
response_id_header_name: string # Add a unique request ID headerServes static files from a directory. MIME types are automatically detected.
http_action:
type: serve-directory
path: /var/www/static # Directory path (required)
response_headers: # Custom response headers
Cache-Control: "max-age=3600"
response_id_header_name: string # Add a unique request ID headerImmediately closes the connection.
http_action:
type: close
# Shorthand string form
http_action: closeUDP forwarding with round-robin load balancing and stateful association tracking.
- address: 0.0.0.0:53
transport: udp
target:
addresses: [string] # Backend address(es) -- round-robin
allowlist: string | [string] # IP masks or group names
association_timeout_secs: 200 # Timeout for UDP associations (default: 200, min: 5)The address, location, and locations field names are accepted as aliases for addresses.
Named, reusable sets of IP ranges. Define groups before referencing them in server configs (ordering within the file matters).
# Define groups
- group: internal
ip_masks:
- 192.168.0.0/16
- 10.0.0.0/8
- 172.16.0.0/12
- group: trusted
ip_masks:
- 1.2.3.4
- 5.6.7.8
- internal # Groups can reference other groups
# Use in server config
- address: 0.0.0.0:8080
transport: tcp
target:
location: backend:8080
allowlist:
- internal
- trustedThe built-in group all is equivalent to 0.0.0.0/0 (all IPv4).
ip_mask (singular) is accepted as an alias for ip_masks.
For simple forwarding, configs can be specified as URLs on the command line instead of YAML files.
# TCP forwarding
tobaru tcp://127.0.0.1:8080?target=192.168.1.10:80
# Multiple targets (round-robin)
tobaru "tcp://127.0.0.1:8080?target=backend1:80&target=backend2:80"
# Forward to UNIX socket
tobaru tcp://127.0.0.1:8080?target-path=/run/app.sock
# UDP forwarding
tobaru udp://127.0.0.1:53?target=8.8.8.8:53&target=8.8.4.4:53URL configs always use allowlist: 0.0.0.0/0 (allow all). For access control, use a YAML config file.
| Scheme | Parameter | Description |
|---|---|---|
tcp |
target or target-address |
Backend TCP address |
tcp |
target-path |
Backend UNIX socket path |
udp |
target or target-address |
Backend UDP address |
tobaru [OPTIONS] <CONFIG PATH or CONFIG URL> [CONFIG PATH or CONFIG URL] ...
OPTIONS:
-t, --threads NUM Worker threads (default: auto-detected from CPU count)
--clear-iptables-all Clear all tobaru iptables rules and exit
--clear-iptables-matching Clear iptables rules for specified config files and exit
-h, --help Show help
# Run with a single config file
tobaru config.yaml
# Run with multiple config files (merged together)
tobaru servers.yaml ip_groups.yaml
# Simple TCP forwarding via URL
tobaru tcp://127.0.0.1:8080?target=192.168.1.10:80
# Custom thread count
tobaru --threads 4 config.yaml
# Clear iptables rules
sudo tobaru --clear-iptables-matching config.yaml
sudo tobaru --clear-iptables-allConfiguration files are automatically watched for changes and reloaded without restart.
These fields are accepted with a deprecation warning and will be removed in a future version.
| Deprecated | Replacement |
|---|---|
serverTls |
server_tls |
bindAddress |
address |
addresses (in targets) |
locations |
optional (in server_tls) |
Split into two explicit targets (auto-migrated) |