Overview

Orange uses TOML format for configuration. The configuration file controls all aspects of the network engine including DNS resolution, proxy services, routing rules, and TUN mode settings.

Quick start

Copy the bundled example to start from a known-good baseline, then edit as needed.

Copy example-config.toml to config.toml
cp example-config.toml config.toml

General

[general]

Global settings for the Orange engine including logging and IP address family policy.

Option Type Description Default
log_level
string
Log level: error | warn | info | debug | trace
error: production, info: default, debug: development, trace: profiling
"info"
log_fileoptional
string
File path for JSON-formatted log output. Logs are also written to the console. Relative paths resolve against the config file directory; ~ expands to the user home directory. The directory is created automatically if missing.
ip_versionoptional
string
IP address family policy. Controls DNS record types queried and Happy Eyeballs connect order.
dual: both A + AAAA, RFC 8305 default order (IPv6 first, parallel IPv4 after 250ms).
prefer-ipv4: dual-stack resolve, force IPv4 first for connect.
prefer-ipv6: dual-stack resolve, prefer IPv6 primary IP.
ipv4: A records only, IPv4 only.
ipv6: AAAA records only, IPv6 only.
"dual"
Note: dns.rules host overrides are explicit user mappings and are not constrained by ip_version. URL host literals (IPv4/IPv6 written directly in URLs) that conflict with the policy are rejected.

DNS service

[dns]

Core DNS server settings — listener, concurrency, and cache. Other DNS concerns are covered in their own sections: Reverse Cache, Rate Limit, Bootstrap, Local Network, DoT, DoH, Rules, and Fake-IP.

OptionTypeDescriptionDefault
server_enabled
boolean
Enable DNS server port listening. Set to false for iOS/macOS NetworkExtension sandbox.
true
bind_addr
string
DNS server listen address (UDP/TCP). Format: IP:Port
concurrent_limit
integer
Maximum concurrent DNS queries. Recommended: 64 (2-core), 128 (4-core), 256+ (8-core)
max_stream_message_size
integer
Maximum TCP/DoT message size in bytes.
4096
fallback_to_system_dns
boolean
Fallback to system DNS when upstreams unavailable. Keep false if Orange is the system DNS.
false
hosts_fileoptional
string
System hosts file to load. Reloaded every 5 seconds on change. Precedence: dns.rules > hosts file > upstream DNS. Empty string disables.
Default: "/etc/hosts" on macOS/Linux; disabled on iOS/Android sandbox.
"/etc/hosts"
cache_size
integer
DNS cache entries count. FFI memory-constrained environments may lower to 500.
1000

DNS reverse cache

[dns.reverse_cache] optional

IP-to-domain reverse lookup cache. Used by TUN mode to recover the original hostname from a destination IP so that domain-based routing rules and logging still work after DNS has been resolved. Set either threshold to 0 to disable.

OptionTypeDescriptionDefault
per_ip_max
integer
Maximum records retained per IP. The least-recently-accessed entries are evicted first. Set to 0 to disable reverse caching.
16
global_max
integer
Global record cap that bounds total memory. On cleanup Orange uses a budget strategy: budget = global_max / ip_count, and each IP keeps min(per_ip_max, budget). FFI memory-constrained environments: 2000. Set to 0 to disable.
10000

DNS rate limit

[dns.rate_limit] optional

Defends against DNS amplification attacks by limiting requests per client IP over a sliding time window.

OptionTypeDescriptionDefault
max_requests
integer
Maximum requests per window per client IP. Example: 200 with window_ms = 1000 caps each IP at 200 queries/second.
window_ms
integer
Size of the sliding window in milliseconds.
max_entries
integer
Maximum distinct client IPs tracked; oldest entries are evicted when full. FFI memory-constrained: 2000.
10000

DNS bootstrap

[dns.bootstrap]

DNS servers used to resolve infrastructure hostnames (upstream proxies, DoH/DoT providers, WireGuard endpoints). Bootstrap queries are forced to bypass the TUN tunnel and go out on the physical interface, preventing circular routing. Static hostname-to-IP mappings for infrastructure are now unified under [dns.rules].

OptionTypeDescriptionDefault
servers
string[]
Bootstrap DNS servers. Must be literal IPs, not hostnames, to avoid circular resolution. Format: IP (port 53) or IP:Port. Defaults include both IPv4 and IPv6 addresses for NAT64 / IPv6-only networks.
["1.1.1.1:53", "8.8.8.8:53", "223.5.5.5:53", "[2606:4700:4700::1111]:53", "[2001:4860:4860::8888]:53"]

DNS local network

[dns.local_network] optional

Opts local-network domains (mDNS, LAN suffixes, service discovery) out of upstream DNS so they stay on the local link and do not leak to external resolvers. Matched queries return NoError + empty Answer (not NXDOMAIN) so that RFC 2308 negative caching does not block subsequent mDNS attempts.

OptionTypeDescriptionDefault
bypass_private_ptr
boolean
Intercept PTR queries for private IP ranges so LAN addresses are never leaked to upstream DNS.
bypass_suffixes
string[]
Domain patterns to bypass. Suffix match (.local) matches anything ending in .local; mid-string pattern match (._dns-sd.) matches anything containing the substring. Set to [] to disable.
[".local", ".loc", "._dns-sd."]

DNS over TLS (DoT)

[dns.dot] optional

Exposes the DNS service over TLS, typically on port 853. Requires a valid TLS certificate and private key in PEM format.

OptionTypeDescriptionDefault
bind_addr
string
DoT listen address (default port 853).
cert_path
string
TLS certificate path (PEM format).
key_path
string
TLS private key path (PEM format).

DNS over HTTPS (DoH)

[dns.doh] optional

Exposes the DNS service over HTTPS, typically on port 443. Standard query path is /dns-query (RFC 8484).

OptionTypeDescriptionDefault
bind_addr
string
DoH listen address (default port 443).
cert_path
string
TLS certificate path (PEM format).
key_path
string
TLS private key path (PEM format).
path
string
DoH query path. Standard clients expect /dns-query.
"/dns-query"

DNS rules

[dns.rules]

Unified DNS routing table. The same rule set applies to every inbound (TUN, HTTP, SOCKS). Shorthand syntax covers reject and simple host mappings; the full { ... } form is required for DNS upstreams, conditional matches, and rewrites. Infrastructure hostnames (upstream proxies, DoH/DoT providers, WireGuard endpoints) should use { host = "..." } mappings here so they resolve without a circular lookup.

Match patterns
PatternTypeMeaningExample match
"google.com"
exact
Exact match — only matches google.com.
google.com
".cn"
suffix
Suffix match — matches *.cn but not cn itself.
foo.cn
"+.cn"
suffix+root
Suffix + root — matches cn and every *.cn.
cn, foo.cn
"*.baidu.com"
wildcard
Single-level wildcard — only matches one subdomain level.
a.baidu.com
"@geosite:cn"
geosite
Matches every domain in the GeoSite cn category.
Dataset entries
"default"
fallback
Fallback rule used when no pattern matches.
*
Rule values & conditions

Rule values can be a shorthand string ("reject" or a literal IP hosts mapping), a single full-form object, or an array of objects evaluated top-to-bottom. Conditions use the when object; today the supported field is src (CIDR, supports negation with ! and multi-value with ,).

dns.rules examples TOML
# Shorthand — reject
"*.ads.com" = "reject"

# Shorthand — hosts mapping
"example.com" = "127.0.0.1"

# Full form — hosts mapping
"example.com" = { host = "127.0.0.1" }

# DNS upstream
"@geosite:cn" = { to = ["223.5.5.5"] }

# Multiple upstreams (concurrent)
"example.com" = { to = ["8.8.8.8", "1.1.1.1"] }

# With specific outbound
"*.internal" = { to = ["10.0.0.53"], via = "wg-home" }

# Conditional rules (by source IP)
"*.corp" = [
  { when = { src = "10.0.0.0/8" },  to     = ["10.0.0.53"] },
  { when = { src = "!10.0.0.0/8" }, reject = true },
]

# Suffix rewrite — ask the router for .loc while the client queries .local
# rewrite requires a wildcard pattern (*.local / +.local) and must start with '.'
"*.local" = [
  { when = { src = "192.168.0.0/16" }, to = ["192.168.1.2"], rewrite = ".loc" },
]

# Default upstream (required)
"default" = { to = ["8.8.8.8"] }

Fake-IP

[dns.fake-ip] optional

Assigns virtual IPs from 198.18.0.0/15 to hostnames so that clients can start a connection immediately; Orange then recovers the hostname at the TUN/proxy boundary to make routing decisions. Best suited to TUN transparent proxy mode. IPv4 only — AAAA queries return empty responses, and the 198.18.0.0/15 range must not be used for anything else.

OptionTypeDescriptionDefault
enabled
boolean
Enable Fake-IP.
false
store_path
string
Persistent storage path. Relative paths resolve against the config file directory; ~ expands to user home.
"fake-ip.redb"
save_interval_secs
integer
Auto-save interval in seconds. 0 disables the timer; saves still happen when changes accumulate.
60
max_entries
integer
Maximum in-memory mappings. Overflow falls back to normal DNS resolution.
100000
expire_days
integer
Mappings not accessed for this many days are cleaned up.
15
access_update_interval
integer
Minimum seconds between last_access write-backs. Larger values reduce IO pressure.
3600
mode
string
blacklist: every hostname uses Fake-IP except those matched by rules.
whitelist: only hostnames matched by rules use Fake-IP.
"blacklist"
rules
string[]
Domain patterns filtered by mode. Supports exact (example.com), suffix (.local), suffix+root (+.example.com), and @geosite:tag. Default blacklist mode already skips localhost, *.local, *.lan, *.home.arpa, and PTR ranges.

Proxy core

[proxy]

Top-level settings that apply across every inbound proxy: shared authentication, domain-resolution policy for IP-based rule matching, and the routing-rule match cache. Inbound listeners (HTTP, SOCKS5, Mixed), TLS, Physical interface binding, Upstreams, Upstream Health Check, and Routing Rules each have their own section.

OptionTypeDescriptionDefault
authoptional
string
Inbound authentication shared across HTTP, SOCKS5, and Mixed proxies. Format: username:password. When unset all inbound proxies are open (default).
Strongly recommended when any proxy binds to a non-localhost address.
resolve_domain_for_ip_rules
boolean
Resolve domain to IP during routing for IP/GeoIP rule matching. May add DNS latency. Per-rule resolve_ip = true can override.
true
rule_match_cache_size
integer
Routing rule match cache size (entries). 0 is treated as 1 to avoid perf regressions. FFI memory-constrained: 2000.
10000

HTTP proxy

[proxy.http]

HTTP/HTTPS proxy on a single port. Handles HTTP forward proxy, HTTPS CONNECT tunnels, and WebSocket upgrades from the same listener.

OptionTypeDescriptionDefault
bind_addr
string
Listen address, format IP:Port.
concurrent_limit
integer
Maximum concurrent connections. Each connection uses ~1 MB. Sizing guidance: 256 (4 GB RAM), 512 (8 GB), 1024+ (16 GB).
Upstream connection pool [proxy.http.pool]

Optional connection reuse to reduce handshake overhead to upstream HTTP/HTTPS proxies.

OptionTypeDescriptionDefault
max_idle_per_upstream
integer
Maximum idle connections retained per upstream host.
32
idle_timeout_secs
integer
Idle connections are closed after this many seconds.
30
max_hosts
integer
Maximum upstream hosts tracked (LRU eviction). Protects against unbounded growth on high-cardinality destinations.
1024

SOCKS5 proxy

[proxy.socks]

RFC 1928 SOCKS5 implementation focused on the CONNECT command. Supports domain, IPv4, and IPv6 targets. Authentication is either none or RFC 1929 username/password (configured via [proxy] auth). The BIND command is not supported.

OptionTypeDescriptionDefault
bind_addr
string
Listen address, format IP:Port.
concurrent_limit
integer
Maximum concurrent SOCKS5 connections.

Mixed proxy

[proxy.mixed]

Serves HTTP and SOCKS5 on the same port. Orange sniffs the first byte: 0x05 routes into the SOCKS5 handler, anything else is treated as HTTP (including CONNECT tunnels). The mixed listener can run alongside dedicated HTTP/SOCKS5 listeners. Routing rules apply uniformly to every inbound.

OptionTypeDescriptionDefault
bind_addr
string
Listen address, format IP:Port.
concurrent_limit
integer
Maximum concurrent connections (HTTP + SOCKS5 share the quota).
512

TLS

[proxy.tls]

TLS settings that apply to upstream encrypted connections.

OptionTypeDescriptionDefault
allow_invalid_certs
boolean
Accept invalid or self-signed upstream certificates. Must be false in production. Intended for internal test environments or self-hosted proxies where the certificate has been manually vetted.
false

Physical interface binding

[proxy.bypass]

Prevents routing loops in TUN mode by binding upstream connections to the physical network interface rather than the TUN device. Only relevant when TUN mode is active; HTTP/SOCKS-only deployments do not need this. On macOS/iOS the recommended alternative is Swift-side excludedRoutes.

OptionTypeDescriptionDefault
enabled
boolean
Enable physical interface binding. Only needed in TUN mode.
false
auto_detect
boolean
Auto-detect the default interface. macOS picks en0 (WiFi/Ethernet); Linux reads /proc/net/route; iOS falls back to system protection; Android needs manual config or VpnService.protect().
true
interface_index
integer
macOS/iOS. Manual interface index, overrides auto_detect. Use ifconfig to list interfaces (typically en0 is 4 or 5).
interface
string
Linux/Android. Manual interface name, overrides auto_detect. Use ip link show to list interfaces (e.g. eth0, wlan0, enp0s3).

Upstreams

[[proxy.upstreams]]

Define the upstream proxies Orange can route traffic through. Each upstream is referenced from [[proxy.rules]] by its name. The primary types are https and wireguard; trojan and shadowsocks (SIP022) are also available for specific deployments. Every upstream can override the global health check with its own health_check block or disable probing entirely via health_check = { disabled = true }.

HTTPS upstream
HTTPS upstream exampleTOML
[[proxy.upstreams]]
type = "https"
name = "http-us"

[proxy.upstreams.config]
addr = "gateway.example.com:443"
auth = "user:pass"

# H2 connection pool (optional)
[proxy.upstreams.config.h2]
soft_max_age_secs = 120    # Soft TTL, no new requests after
idle_timeout_secs = 30     # Close idle connections
max_streams       = 100    # Max concurrent streams per conn
max_conns         = 2      # Max H2 connections per upstream
Trojan upstream

Encrypted TLS transport authenticated by password. Available for deployments that already use a compatible upstream.

Trojan upstream exampleTOML
[[proxy.upstreams]]
type = "trojan"
name = "trojan-01"

[proxy.upstreams.config]
addr     = "gateway.example.com:443"
password = "your-password-here"
Shadowsocks 2022 upstream

Encrypted transport with a pre-shared key (SIP022). Available for deployments that already use a compatible upstream.

Shadowsocks upstream exampleTOML
[[proxy.upstreams]]
type = "shadowsocks"
name = "ss-01"

[proxy.upstreams.config]
addr   = "gateway.example.com:8388"
method = "2022-blake3-aes-256-gcm"
psk    = "your-base64-encoded-psk"
WireGuard upstream feature
WireGuard upstream exampleTOML
[[proxy.upstreams]]
type = "wireguard"
name = "wg-home"

[proxy.upstreams.config]
endpoint   = "vpn.example.com:51820"
publicKey  = "xxxxxxxxxxx="
privateKey = "yyyyyyyyyyy="
address    = "10.0.0.2/24"
allowedIPs = "0.0.0.0/0,::/0"
dns        = "10.0.0.1"
# mode = "auto"  # auto (default) | userspace | kernel
# mtu  = 1420    # Default 1420. PPPoE: 1412. Range: 576-9000.

Kernel mode requires privileges: Linux needs CAP_NET_ADMIN and the ip command; macOS needs sudo, ifconfig, and route; Windows is not supported. Userspace mode has no such requirements but needs separate route setup.

Per-upstream health check override
Override exampleTOML
# Override target and timeout
health_check = { url = "http://cp.cloudflare.com", timeout_secs = 3 }

# WireGuard probe uses IP:Port
health_check = { url = "1.1.1.1:443" }

# Disable probing for this upstream
health_check = { disabled = true }
Security: upstream credentials and private keys are stored in plaintext in the config file. Protect it with chmod 600.

Upstream health check

[proxy.health_check]

Periodically probes each upstream and exposes the result through /health, Prometheus metrics, and logs. The values here form the global default; any upstream can override them inline (see the Upstreams section).

OptionTypeDescriptionDefault
enabled
boolean
Enable health checking globally.
false
interval_secs
integer
Seconds between probes.
30
timeout_secs
integer
Seconds before a probe is considered failed.
5
url
string
Probe target. For HTTPS upstreams, an HTTP URL such as http://www.gstatic.com/generate_204. For WireGuard, an IP or IP:Port (default port 443).
"http://www.gstatic.com/generate_204"

Routing rules

[[proxy.rules]]

Decides what each connection does: stay direct, take a tunnel, or be rejected. Rules can match on domain, IP CIDR, GeoSite tag, or GeoIP tag, and can be filtered by a when object covering source IP, port, inbound type, and ALPN.

Match dimensions
FieldTypeDescriptionExample
domain
string
Domain match. Supports exact (example.com), +.example.com, *.example.com, and @geosite:tag.
"*.home.lab"
ip_cidr
string
IP range in CIDR notation.
"192.168.0.0/16"
geosite
string
GeoSite dataset tag.
"category-ads-all"
geoip
string
GeoIP dataset tag.
"private"
port
integer
Destination port literal (use when.port for ranges).
22
inbound
string
Match by inbound type without a when wrapper.
"udp"
resolve_ip
boolean
Force domain resolution for this rule, overriding the global resolve_domain_for_ip_rules switch.
false
Conditions when = { ... }
FieldTypeDescriptionExample
src
string
Source IP CIDR. Supports negation (!) and multi-value (,).
"!10.0.0.0/8"
port
string
Destination port. Supports ranges and negation.
"443,8000-9000"
inbound
string
Inbound types: tcp | udp | tun | h3 | mixed.
"tcp,tun"
alpn
string
ALPN protocols: h2 | http/1.1 | h3.
"h2"
Actions
SyntaxTypeDescriptionExample
reject = true
boolean
Reject the connection.
true
direct = true
boolean
Connect directly to the target.
true
to = "upstream-name"
string
Forward to the named upstream.
"wg-home"
Routing rules examplesTOML
# Exact domain match — office intranet
[[proxy.rules]]
domain = "api.internal.corp"
to     = "wg-office"

# Wildcard domain — home network
[[proxy.rules]]
domain = "*.home.lab"
to     = "wg-home"

# Reject ad subdomains (does not match the apex)
[[proxy.rules]]
domain = "+.ads.example.com"
reject = true

# Conditional: home network direct, others via WireGuard
[[proxy.rules]]
domain = "*.home.lab"
when   = { src = "192.168.1.0/24" }
direct = true

[[proxy.rules]]
domain = "*.home.lab"
to     = "wg-home"

# GeoSite match — block ads
[[proxy.rules]]
geosite = "category-ads-all"
reject  = true

# GeoIP private IPs direct
[[proxy.rules]]
geoip  = "private"
direct = true

# SSH direct
[[proxy.rules]]
port   = 22
direct = true

# Force resolve so IP/GeoIP rules can match this domain
[[proxy.rules]]
domain     = "audit.example"
resolve_ip = true
to         = "http-us"

# Fallback (no match condition) — auto moved to end
[[proxy.rules]]
direct = true
Priority: within the same rule type (e.g. domain vs domain) Orange sorts by specificity — exact > long suffix > short suffix; +. outranks *. of the same length. Across rule types (domain vs geosite, ip_cidr vs geoip) configuration order applies. Fallback rules without a match condition are automatically moved to the end of the list.

TUN device

[tun]

System-level network gateway over a virtual interface. Captures all OS-level traffic and feeds it into the routing engine. Requires admin privileges on Linux/macOS and is not supported on Windows. SNI/HTTP sniffing lives in its own section.

OptionTypeDescriptionDefault
enabled
boolean
Enable TUN mode. Requires root or CAP_NET_ADMIN.
false
name
string
TUN device name. Linux: tun0, macOS: utun0.
ipv4_address
string
TUN device IPv4 address.
ipv4_prefix
integer
IPv4 subnet prefix length. 24 = /24 (255.255.255.0).
ipv6_address
string
TUN device IPv6 address (optional).
ipv6_prefix
integer
IPv6 subnet prefix length.
mtu
integer
Maximum transmission unit. Standard: 1500, WireGuard: 1420.
routes
string[]
IP ranges routed through the TUN device. ["0.0.0.0/0"] captures all IPv4. macOS benefits from a split-range alternative to avoid default-route conflicts.
exclude_routesoptional
string[]
IP ranges that must bypass the TUN device. Orange probes the default gateway at startup and installs more-specific system routes for each excluded CIDR; they are removed on shutdown. Typical uses: excluding upstream server IPs, LAN networks, or ranges that should stay on the physical interface.
[]
driver
string
TUN driver: "tun-rs".
"tun-rs"
netstack
string
Network stack: "smoltcp" (userspace TCP/IP).
"smoltcp"
tcp_concurrent_limit
integer
Max concurrent TCP connections. Each uses 2 fds.
2048
udp_session_limit
integer
Max UDP sessions (Hybrid NAT shares sockets).
2048
tcp_idle_timeout_secs
integer
TCP idle timeout in seconds.
300
udp_idle_timeout_secs
integer
UDP session idle timeout in seconds.
60
udp_socket_pool_size
integer
UDP global socket pool size (per IPv4/IPv6).
8
udp_force_ephemeral_ports
integer[]
Ports that force ephemeral socket (source entropy).
[53]
udp_quic_sniff
boolean
Enable QUIC SNI sniffing for routing.
true
udp_route_by_ip
boolean
Force UDP routing by destination IP only.
false
dns
string[]
DNS servers for TUN device.
dns_hijack
string[]
Hijack DNS traffic. Format: "*:53", "IP:Port".
[]
dns_worker_count
integer
DNS hijack worker count.
4
dns_queue_size
integer
DNS request queue size.
1024
udp_worker_count
integer
UDP packet worker count. Recommended: CPU cores × 2–4.
16
udp_queue_size
integer
UDP packet queue capacity. Packets are dropped when full. ~1.5 KB per slot; defaults peak near 12 MB. FFI memory-constrained: 1024–2048 (~1.5–3 MB).
8192
ffi_input_queue_size
integer
FFI-only. Capacity of the Swift/Kotlin → Rust inbound packet queue. Packets are dropped when full. FFI memory-constrained environments should lower this to 256–512.
1024
ffi_output_backlog_hwm
integer
FFI-only. Outbound packet queue high-water mark in bytes. Once reached, Orange stops reading from the TCP/IP stack until drain falls below the low-water mark. FFI memory-constrained: 2097152 (2 MB).
8388608
ffi_output_backlog_lwm
integer
FFI-only. Outbound packet queue low-water mark in bytes. Reads resume once the queue drains below this value. Must be strictly less than ffi_output_backlog_hwm. FFI memory-constrained: 1048576 (1 MB).
4194304

SNI / HTTP sniffing

[tun.sniff]

Extracts TLS SNI or HTTP Host from the first bytes of a TCP connection so that domain-based routing rules still work when only an IP destination is visible. Sniffing requires the client to speak first; enabling it on server-first protocols (MySQL, SMTP, SSH) introduces timeout delays. The default port allow-list keeps it limited to HTTP/HTTPS-style traffic.

OptionTypeDescriptionDefault
enabled
boolean
Enable TCP sniffing for SNI / HTTP Host.
true
timeout_ms
integer
Maximum wait time (ms) for the first client packet. Only affects connections whose hostname cannot be recovered via DNS reverse lookup (Fake-IP / DNS cache). Fake-IP connections skip sniffing entirely and are not subject to this timeout.
150
ports
array
Port allow-list for sniffing. Each entry can be a literal port (443), a range (8080-9999), or a comparison expression (<1000, <=1024, >1000, >=1024). Mix forms freely.
[80, 443, 8080, 8443]

Timeouts

[timeouts]

Connection timeout settings.

OptionTypeDescriptionDefault
connect_ms
integer
TCP connection timeout in ms. Fast: 3000, Standard: 5000, Slow: 10000.

Health API

[health]

HTTP endpoints for health, metrics, live streams, and configuration reload. Target: Kubernetes liveness/readiness probes, load balancer checks, monitoring systems, and real-time dashboards.

OptionTypeDescriptionDefault
bind_addr
string
Health API listen address. Serves all endpoints listed below.
Endpoints
MethodPath & description
GET
JSON
/health — JSON health status, including per-upstream latency and availability.
GET
text
/metrics — Prometheus scrape endpoint. Requires prometheus-exporter feature.
GET
SSE
/api/metrics/live — Server-Sent Events stream of live metrics (push model, long-lived connection).
POST
/reload — Trigger configuration hot-reload without restarting the engine.
/health response exampleJSON
{
  "status": "ok",
  "upstreams": [
    {
      "name":                 "http-us",
      "type":                 "https",
      "latency_ms":           120,
      "average_latency_ms":   115,
      "available":            true,
      "last_check_ago_secs":  15
    }
  ]
}
CLI examplesshell
curl http://127.0.0.1:9898/health | jq
curl http://127.0.0.1:9898/metrics
curl -N http://127.0.0.1:9898/api/metrics/live
Security: No authentication and no encryption on any of these endpoints. Bind to 127.0.0.1 or a private network, and keep them off the public internet.

Metrics live stream

[health.metrics_live] optional

Tunes the Server-Sent Events push cadence for /api/metrics/live. Orange only computes and broadcasts when at least one subscriber is attached — no background work happens while idle. Subscribers that cannot handle 1 Hz (mobile apps in background, embedded devices) should throttle or pause on the client side; raise interval_ms only when that is not an option.

OptionTypeDescriptionDefault
interval_ms
integer
Push interval in milliseconds. Common values: 1000 (default), 2000, 5000.
1000

Tracing

[tracing]

Real-time request lifecycle tracing. Traces are pushed to UI clients over WebSocket so dashboards can observe every proxied request as it flows through the engine.

OptionTypeDescriptionDefault
enabled
boolean
Enable request tracing. Disable this in FFI memory-constrained environments when no UI is subscribed — traces carry a non-trivial memory cost.
true
capacity
integer
Maximum concurrent in-flight traces. Each trace is roughly 1 KB (~5 MB at the default cap). FFI memory-constrained: 500–1000, or disable tracing entirely.
5000

Tracing WebSocket

[tracing.websocket] optional

Controls how trace events are aggregated before being delivered to WebSocket subscribers. Tighter flush intervals reduce end-to-end latency; larger batches reduce frame overhead.

OptionTypeDescriptionDefault
flush_interval_ms
integer
Aggregation window in milliseconds before flushing a batch to subscribers.
100
max_batch_size
integer
Maximum trace entries per batch. Larger batches reduce overhead, smaller batches reduce latency.
50

Memory pressure

[memory_pressure]

Adaptive protection for memory-constrained environments (e.g. iOS NetworkExtension's ~50 MB limit). A background monitor polls the Rust allocator and triggers tiered mitigations when thresholds are crossed, preventing the process from being killed by the OS.

Default behaviour: omitting the entire [memory_pressure] block disables pressure management (desktop default). When present, at least one non-zero threshold must be set and thresholds must be strictly increasing. Pressure-level changes log a warn-level message for diagnostics. This block does not support hot-reload; restart is required to apply changes.
Pressure levels
LevelTriggerActionEffect
Warning
warning_bytes
Soft backpressure on new proxy connections.
Admission 50%
Critical
critical_bytes
Tighter admission, shorter idle timeouts.
Admission 25%, idle 15s
Emergency
emergency_bytes
Reject all new proxy connections (DNS hijack exempt).
Idle 3s
OptionTypeDescriptionDefault
warning_bytes
integer
Bytes threshold for entering the Warning level. Set to 0 to disable this level.
critical_bytes
integer
Bytes threshold for entering the Critical level. Must be greater than warning_bytes.
emergency_bytes
integer
Bytes threshold for entering the Emergency level. Must be greater than critical_bytes.
check_interval_ms
integer
Poll interval for the allocator in milliseconds (min 100). Shorter intervals keep a Tokio worker busy and hurt mobile battery life. The default 5 second delay is well within acceptable pressure latency for idle periods.
5000
iOS NetworkExtension (50 MB limit)TOML
[memory_pressure]
warning_bytes     = 31457280   # 30 MB
critical_bytes    = 39845888   # 38 MB
emergency_bytes   = 46137344   # 44 MB
check_interval_ms = 5000
DNS is exempt from pressure-induced rejection. DNS is infrastructure — blocking it would cause cascading failures in everything downstream.

Dataset

[dataset]

GeoSite and GeoIP datasets for large-scale domain/IP classification. Supports local files and HTTP URLs with automatic caching.

OptionTypeDescriptionDefault
geosite
string[]
GeoSite data sources (Protobuf). Local path or HTTP URL. First available is used.
geoip
string[]
GeoIP data sources (Protobuf). Local path or HTTP URL. First available is used.
Dataset configuration exampleTOML
[dataset]
geosite = ["./data/sites.dat"]
geoip   = ["./data/ips.dat"]
Caching: downloaded datasets are cached in .orange/dataset-cache/. Delete cache to force re-download.
CLI: use orange dataset --config config.toml to inspect loaded datasets.