Skip to content

Configuration Reference

These are the global settings in exfilguard.toml. ExfilGuard reads them at startup.


Core Settings

These settings are required.

Field Type Required Description
listen String Yes Listen address and port (e.g., "127.0.0.1:3128")
proxy_protocol String "off" PROXY protocol mode: "off", "optional", or "required"
proxy_protocol_allowed_cidrs Array None CIDR allowlist for peers allowed to send PROXY headers (required when proxy_protocol is "optional" or "required")
ca_dir Path Yes Directory containing CA certificate and private key for TLS interception
clients Path Yes Path to clients configuration file
policies Path Yes Path to policies configuration file
clients_dir Path No Directory containing additional client config files (*.toml)
policies_dir Path No Directory containing additional policy config files (*.toml)

Note

Relative paths are resolved from the directory containing the main config file.

Note

Use ExfilGuard as an explicit proxy. Clients should know they are talking to one.

Note

When proxy_protocol is "optional" or "required", ExfilGuard auto-detects PROXY protocol v1 or v2 headers for peers in proxy_protocol_allowed_cidrs.

In "optional" mode, peers outside that allowlist are treated as normal client connections.

In "required" mode, peers outside that allowlist are rejected before HTTP parsing, and allowlisted peers must send a valid PROXY header.

Note

Set proxy_protocol_allowed_cidrs when PROXY protocol is enabled.

Note

ExfilGuard reads exfilguard.toml only at startup. SIGHUP reloads only the client and policy data read from the configured clients, clients_dir, policies, and policies_dir paths. If you change fields in exfilguard.toml itself, including listen, metrics, cache, TLS, logging, and timeout settings, restart the server.


TLS / Certificate Settings

These settings control TLS interception and leaf certificate generation.

Field Type Default Description
cert_cache_dir Path None Directory to cache dynamically generated TLS certificates
leaf_ttl u64 86400 TLS certificate leaf TTL in seconds (must be > 0)

CA Directory Structure

ExfilGuard uses a root CA plus an intermediate CA. ca_dir must contain:

ca_dir/
├── root.crt           # Root CA certificate
├── root.key           # Root CA private key (optional when using external CA)
├── intermediate.crt   # Intermediate CA certificate (signed by root)
└── intermediate.key   # Intermediate CA private key
  • The intermediate CA signs leaf certificates.
  • ExfilGuard sends the chain Leaf -> Intermediate -> Root to clients.
  • Clients only need to trust the root CA.
  • If you use an externally signed intermediate, root.key may be omitted.

If ca_dir is empty, ExfilGuard generates all four files automatically on first startup.

Note

If you change files under ca_dir, restart the server. If you replace the signing CA and use cert_cache_dir, clear the cached leaf certificates before restart if you need clients to see the new issuer right away.

Using Your Corporate CA

Use this flow if you want clients to trust ExfilGuard through your existing PKI:

  1. Let ExfilGuard generate its keys:

    # Creates root.crt, root.key, intermediate.crt, intermediate.key
    exfilguard --config exfilguard.toml
    
    Start with an empty ca_dir, then stop the process after it creates the files.

  2. Create a CSR from the generated intermediate key:

    openssl req -new -key ca_dir/intermediate.key \
      -out intermediate.csr \
      -subj "/CN=ExfilGuard Intermediate CA"
    

  3. Get your corporate CA to sign the CSR:

    # Example using openssl (adjust to your CA's process)
    openssl x509 -req -in intermediate.csr \
      -CA corporate-ca.crt -CAkey corporate-ca.key \
      -CAcreateserial -out intermediate-signed.crt \
      -days 365 -sha256 \
      -extfile <(echo "basicConstraints=CA:TRUE,pathlen:0
    keyUsage=keyCertSign,cRLSign")
    

  4. Replace the certificates:

    cp corporate-ca.crt ca_dir/root.crt
    cp intermediate-signed.crt ca_dir/intermediate.crt
    # Keep the original intermediate.key - it matches the CSR
    # root.key is no longer needed (can be removed or kept)
    

  5. Restart ExfilGuard. Clients that trust your corporate CA will then trust intercepted connections.

Note

The private key (intermediate.key) stays the same. Only the certificate changes.


Logging Settings

Field Type Default Description
log String "json" Log format: "json" or "text"
log_queries Boolean false Whether to log each request query

Timeout Settings

All timeout values are in seconds. Use 0 to disable request_total_timeout and connect_tunnel_max_lifetime.

Field Type Default Description
dns_resolve_timeout u64 2 Maximum time to resolve DNS for upstream hosts
upstream_connect_timeout u64 5 Maximum time to establish upstream TCP connections
tls_handshake_timeout u64 10 Maximum time for TLS handshakes (client or upstream)
request_header_timeout u64 10 Maximum time to read an HTTP request line + headers
request_body_idle_timeout u64 30 Maximum idle time between request body reads/writes
response_header_timeout u64 30 Maximum time to receive upstream response headers
response_body_idle_timeout u64 60 Maximum idle time between response body reads/writes
request_total_timeout u64 0 Maximum total time from request start until the response has been fully forwarded (0 disables)
client_keepalive_idle_timeout u64 30 Idle time before closing an idle client keep-alive connection
connect_tunnel_idle_timeout u64 60 Maximum idle time for CONNECT tunnels
connect_tunnel_max_lifetime u64 0 Maximum lifetime for CONNECT tunnels (0 disables)

Request Size Limits

All size values are in bytes. Header limits must be greater than 0. Set max_request_body_size = 0 to disable the global request-body cap.

Field Type Default Description
max_request_header_size usize 32768 (32 KiB) Maximum HTTP request header size, including bumped HTTP/2 header lists
max_response_header_size usize 32768 (32 KiB) Maximum HTTP response header size, including upstream HTTP/2 header lists
max_request_body_size usize 0 (unlimited) Maximum HTTP request body size during forwarding (0 disables the limit)

Connection Pool

Field Type Default Description
upstream_pool_capacity usize 32 Maximum number of upstream connections to pool (must be >= 1)

HTTP/2

Field Type Default Description
http2_max_concurrent_streams u32 100 Maximum concurrent bumped downstream HTTP/2 streams per connection (must be >= 1)

Metrics

Field Type Default Description
metrics_listen String None Optional listen address (e.g., "127.0.0.1:9090") to serve Prometheus metrics at /metrics
metrics_tls_cert Path None PEM certificate chain to enable HTTPS for /metrics
metrics_tls_key Path None PEM private key matching metrics_tls_cert

ExfilGuard exports counters and histograms for per-client and per-policy decisions, latency, cache activity, and upstream reuse, plus gauges for current downstream connections, in-flight requests, CONNECT tunnels, bumped TLS sessions, active HTTP/2 streams, upstream connections, cache usage, and the last successful policy reload time.


Cache Settings

Response caching is opt-in per rule. The settings here configure the shared cache storage.

Field Type Default Description
cache_dir Path None Directory for response cache storage
cache_max_entry_size u64 10485760 (10 MiB) Maximum size of individual cache entries
cache_max_entries usize 10000 Maximum number of cached responses (LRU)
cache_total_capacity u64 1073741824 (1 GiB) Total cache capacity
cache_sweeper_interval u64 300 Interval in seconds between cache sweeper runs
cache_sweeper_batch_size usize 1000 Maximum metadata entries inspected per sweep

Cache Behavior

The cache follows standard HTTP cache headers from upstream servers.

Scope

The cache is shared across all clients. Responses are keyed by method and absolute URI. Vary headers decide which request headers are part of the cache key. Enable caching only if cross-client sharing is acceptable in your environment.

Supported Headers

  • Cache-Control: max-age, s-maxage, public, private, no-cache, no-store
  • Expires: HTTP date for cache expiration
  • Vary: Cache keys include request headers specified by Vary

TTL Priority

Cache lifetime is chosen in this order:

  1. s-maxage (shared cache max-age) - highest priority
  2. max-age
  3. Expires header
  4. force_cache_duration from policy rule (fallback only)

What Gets Cached

  • Methods: Only GET and HEAD requests
  • Status codes: 200, 203, 204, 205, 206, 301, 302
  • Bypass: Requests with Authorization or Cookie headers are never served from cache and are not stored
  • Not cached: Responses with no-store, no-cache, or private directives, or any Set-Cookie header

Request Cache Directives

Request-side cache controls can force a bypass. If a request includes Cache-Control: no-cache, Cache-Control: no-store, Cache-Control: max-age=0, or Pragma: no-cache, the cache will not be used and the response will not be stored. Otherwise, caching follows the upstream response headers plus force_cache_duration from policy rules.

Eviction

The cache uses LRU eviction when capacity is reached. Expired entries are removed on lookup.

Layout and Sweeping

Cache entries live under a versioned subdirectory (v1 under the cache root). When the layout changes, old version directories are deleted asynchronously. A background sweeper runs every cache_sweeper_interval seconds and inspects up to cache_sweeper_batch_size entries, removing expired entries and pruning empty shard directories.

Note

The cache does not support conditional revalidation (ETag/If-None-Match, Last-Modified/If-Modified-Since). Stale entries are discarded and fetched fresh from upstream.


Environment Variables

You can override any setting with environment variables. Use the EXFILGUARD__ prefix and double underscores for nesting.

# Override listen address
EXFILGUARD__LISTEN="0.0.0.0:3128"

# Override log format
EXFILGUARD__LOG="text"

# Override timeouts
EXFILGUARD__CLIENT_KEEPALIVE_IDLE_TIMEOUT=60
EXFILGUARD__UPSTREAM_CONNECT_TIMEOUT=120

Complete Example

# Core settings
listen = "127.0.0.1:3128"
ca_dir = "./ca"
cert_cache_dir = "./cert_cache"
clients = "clients.toml"
policies = "policies.toml"
clients_dir = "clients.d"
policies_dir = "policies.d"

# Logging
log = "text"
log_queries = false

# TLS
leaf_ttl = 86400

# Timeouts (seconds)
dns_resolve_timeout = 2
upstream_connect_timeout = 5
tls_handshake_timeout = 10
request_header_timeout = 10
request_body_idle_timeout = 30
response_header_timeout = 30
response_body_idle_timeout = 60
request_total_timeout = 0
client_keepalive_idle_timeout = 30
connect_tunnel_idle_timeout = 60
connect_tunnel_max_lifetime = 0

# Connection pool
upstream_pool_capacity = 32

# HTTP/2
http2_max_concurrent_streams = 100

# Size limits (bytes)
max_request_header_size = 32768
max_response_header_size = 32768
max_request_body_size = 0

# Cache (optional)
cache_dir = "./cache"
cache_max_entry_size = 10485760
cache_max_entries = 10000
cache_total_capacity = 1073741824
cache_sweeper_interval = 300
cache_sweeper_batch_size = 1000