Keyboard shortcuts

Press โ† or โ†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Config File

Full reference for the config.toml file with all fields, defaults, and accepted values.

File Location

Default: ~/.config/xrat/config.toml

Resolution order:

  1. --config <path> CLI flag
  2. XRAT_PATH/config.toml environment variable
  3. ~/.config/xrat/config.toml

Top-Level Structure

[paths]
[database]
[server]
[runtime]
[routing]
[geo]
[parser]
[dns]
[testing]

[paths]

Binary paths for proxy engines. All fields are optional (defaults to $PATH).

[paths]
# Database file path (deprecated, use [database.sqlite].path)
database = "db.sqlite"

# Binary paths (optional, defaults to PATH lookup)
xray = "/usr/local/bin/xray"
v2ray = "/usr/local/bin/v2ray"
sing_box = "/usr/local/bin/sing-box"
FieldTypeDefaultDescription
databasestring-Database path (deprecated, use [database.sqlite].path)
xraystringxrayXray-core binary path
v2raystringv2rayV2Ray binary path
sing_boxstringsing-boxsing-box binary path

[database]

Database backend selection and connection settings.

[database]
backend = "sqlite"  # "sqlite" | "postgres"

[database.sqlite]
path = "db.sqlite"

[database.postgres]
user = { env = "XRAT_POSTGRES_USER" }
password = { env = "XRAT_POSTGRES_PASSWORD" }
host = "localhost"
port = 5432
db_name = "xrat"
max_connections = 10
min_connections = 1
connect_timeout_secs = 10
FieldTypeDefaultDescription
backendenumsqlitesqlite or postgres
[sqlite].pathstringdb.sqliteSQLite database file path
[postgres].userstring/env-PostgreSQL username
[postgres].passwordstring/env-PostgreSQL password
[postgres].hoststringlocalhostPostgreSQL host
[postgres].portinteger5432PostgreSQL port
[postgres].db_namestring-PostgreSQL database name
[postgres].max_connectionsinteger10Connection pool max size
[postgres].min_connectionsinteger1Connection pool min size
[postgres].connect_timeout_secsinteger10Connection timeout

[server]

HTTP API server configuration.

[server]
enabled = false
host = "127.0.0.1"
port = 8080
key = { env = "XRAT_API_KEY" }
FieldTypeDefaultDescription
enabledbooleanfalseEnable daemon-hosted API
hoststring127.0.0.1Bind host
portinteger8080Bind port
keystring/env-API key for authentication

[runtime]

Runtime engine and proxy process configuration.

[runtime]
engine = "xray"     # "xray" | "v2ray" | "sing-box"
replace_active_session = true
FieldTypeDefaultDescription
engineenumxrayManaged runtime engine. Xray/V2Ray are currently used for connect; sing-box is parse/preview oriented.
replace_active_sessionbooleantrueAuto-disconnect on new connect

[runtime.rotation]

Proxy auto-rotation settings.

[runtime.rotation]
enabled = false
interval_secs = 1800
health_trigger_enabled = true
cooldown_secs = 300
test_concurrency = 0
test_stages = ["real_delay", "download"]
FieldTypeDefaultDescription
enabledbooleanfalseEnable scheduled rotation
interval_secsinteger1800Rotation interval in seconds
health_trigger_enabledbooleantrueTrigger rotation on health failure
cooldown_secsinteger300Minimum time between rotations
test_concurrencyinteger0Test workers (0 = auto)
test_stagesstring[]["real_delay", "download"]Candidate test stages

[runtime.log]

Proxy process logging.

[runtime.log]
enabled = true
mask = "none"     # "quarter" | "half" | "full" | "none"
dir = "logs"
dns_log = false
level = "warning" # "debug" | "info" | "warning" | "error"
keep = true
FieldTypeDefaultDescription
enabledbooleantrueEnable logging to files
maskenumnoneIP address masking
dirstringlogsLog directory
dns_logbooleanfalseEnable DNS query logging
levelenumwarningLog level
keepbooleantrueKeep logs after session stop

[runtime.socks]

SOCKS5 inbound configuration.

[runtime.socks]
enabled = true
host = "0.0.0.0"
port = 1080
udp = true
auth = { enabled = true, username = "xrat", password = { env = "XRAT_SOCKS_PASSWORD" } }
FieldTypeDefaultDescription
enabledbooleantrueEnable SOCKS inbound
hoststring0.0.0.0Bind address
portinteger1080Bind port
udpbooleantrueEnable UDP support
auth.enabledbooleanfalseEnable authentication
auth.usernamestringxratSOCKS username
auth.passwordstring/env-SOCKS password

[runtime.http]

HTTP proxy inbound configuration.

[runtime.http]
enabled = false
host = "0.0.0.0"
port = 8080
FieldTypeDefaultDescription
enabledbooleanfalseEnable HTTP inbound
hoststring0.0.0.0Bind address
portinteger8080Bind port

[runtime.shadowsocks]

Shadowsocks inbound configuration.

[runtime.shadowsocks]
enabled = false
host = "0.0.0.0"
port = 1081
method = "aes-128-gcm"
password = { env = "XRAT_SHADOWSOCKS_PASSWORD" }
network = "tcp,udp"
FieldTypeDefaultDescription
enabledbooleanfalseEnable Shadowsocks inbound
hoststring0.0.0.0Bind address
portinteger1081Bind port
methodstringaes-128-gcmEncryption method
passwordstring/env-Shadowsocks password
networkstringtcp,udpNetwork type

[runtime.sniffing]

Traffic sniffing configuration.

[runtime.sniffing]
enabled = true
dest_override = ["http", "tls", "quic"]
route_only = true
metadata_only = false
domains_excluded = []
ips_excluded = []
FieldTypeDefaultDescription
enabledbooleantrueEnable traffic sniffing
dest_overridestring[]["http", "tls", "quic"]Protocols for destination override
route_onlybooleantrueOnly sniff for routing
metadata_onlybooleanfalseOnly sniff metadata
domains_excludedstring[][]Excluded domains
ips_excludedstring[][]Excluded IPs

[routing]

Routing configuration.

[routing]
domain_strategy = "IPIfNonMatch" # "AsIs" | "IPIfNonMatch" | "IPOnDemand"

[routing.direct]
domain = []
ip = []
geosite = []
geoip = []

[routing.block]
domain = []
ip = []
geosite = []
geoip = []
FieldTypeDefaultDescription
domain_strategyenumIPIfNonMatchXray domain resolution strategy
[direct].domainstring[][]Direct-route domains
[direct].ipstring[][]Direct-route IPs
[direct].geositestring[][]Direct-route geosite categories
[direct].geoipstring[][]Direct-route geoip categories
[block].domainstring[][]Blocked domains
[block].ipstring[][]Blocked IPs
[block].geositestring[][]Blocked geosite categories
[block].geoipstring[][]Blocked geoip categories

[geo]

GeoIP/geosite asset management.

[geo]
auto_update = false
update_interval_hours = 168

[[geo.profiles]]
name = "default"
geosite = "https://example.com/geosite.dat"
geoip = "https://example.com/geoip.dat"

[[geo.profiles]]
name = "local"
geosite = "geo/local/geosite.dat"
geoip = "geo/local/geoip.dat"
FieldTypeDefaultDescription
auto_updatebooleanfalseEnable periodic geo asset updates
update_interval_hoursinteger168Update interval in hours
[[profiles]].namestring-Profile name
[[profiles]].geositestring-Geosite file path or URL
[[profiles]].geoipstring-GeoIP file path or URL

[parser]

Xray JSON schema validation mode.

[parser]
parse_mode = "strict" # "strict" | "lenient" | "auto"
FieldTypeDefaultDescription
parse_modeenumstrictXray JSON validation mode

[dns]

DNS configuration for generated Xray configs.

[dns]
query_strategy = "UseSystem" # "UseIP" | "UseIPv4" | "UseIPv6" | "UseSystem"
servers = [
    "8.8.8.8",
    "https://1.1.1.1/dns-query",
]
use_system_hosts = true
disable_cache = false
disable_fallback = false
enable_parallel_query = true

[dns.hosts]
"domain:example.test" = "127.0.0.1"
"domain:lan.test" = ["192.168.1.10", "192.168.1.11"]
FieldTypeDefaultDescription
query_strategyenumUseSystemDNS query strategy
serversstring[]-DNS server list
use_system_hostsbooleantrueUse system hosts file
disable_cachebooleanfalseDisable DNS cache
disable_fallbackbooleanfalseDisable fallback DNS
enable_parallel_querybooleantrueEnable parallel queries
[hosts]map-Static DNS entries

[mmdb]

Dedicated MaxMind MMDB asset configuration, separate from [geo] routing assets.

[mmdb]
dir = "mmdb"
download_url = "https://github.com/P3TERX/GeoLite.mmdb/releases/latest/download/{edition}.mmdb"
timeout_secs = 60
default_editions = ["country", "city", "asn"]
auto_update = false
update_interval_hours = 168
FieldTypeDefaultDescription
dirstringmmdbMMDB directory (absolute, or relative to the xrat runtime root)
download_urlstringhttps://github.com/P3TERX/GeoLite.mmdb/releases/latest/download/{edition}.mmdbDownload URL template. {edition} is replaced with edition name
timeout_secsinteger60HTTP request timeout for downloads
default_editionsstring[]["country", "city", "asn"]Editions downloaded when no --edition or --all flag given
auto_updatebooleanfalseEnable periodic update checks
update_interval_hoursinteger168Update interval in hours

The dir field is resolved relative to the xrat runtime root (XRAT_PATH when set, otherwise the default app root). Absolute paths are used as-is. The default per-edition MMDB paths under [testing.geoip] also resolve through this MMDB directory; custom relative per-edition paths are resolved relative to the config file directory.


[testing]

Connection testing configuration.

[testing]
concurrency = 0  # 0 = auto
order = ["icmp", "real_delay", "download"]
failure_policy = "continue"  # "continue" | "skip_remaining" | "mark_failed"

[testing.real_delay]
enabled = true
url = "https://www.gstatic.com/generate_204"
timeout = 10_000

[testing.icmp]
enabled = true
timeout = 3000
attempts = 3

[testing.download]
enabled = false
url = "https://cachefly.cachefly.net/50mb.test"
timeout = 30_000

[testing.tcp]
enabled = true
timeout = 5000

[testing.geoip]
enabled = false
backend = "mmdb"
fallback = "none"
country_path = "mmdb/GeoLite2-Country.mmdb"
city_path = "mmdb/GeoLite2-City.mmdb"
asn_path = "mmdb/GeoLite2-ASN.mmdb"

[testing.geoip.remote]
provider = "ipwhois"
endpoint = ""
timeout_ms = 5000
api_key = ""
rate_limit_per_minute = 30

[testing.geoip.cache]
enabled = true
ttl_secs = 86400
max_entries = 10000
SectionFieldTypeDefaultDescription
[testing]concurrencyinteger0Test workers (0 = auto)
[testing]orderstring[]["icmp", "real_delay", "download"]Stage execution order
[testing]failure_policyenumcontinueBehavior on stage failure
[icmp]enabledbooleantrueEnable ICMP stage
[icmp]timeoutinteger3000ICMP timeout (ms)
[icmp]attemptsinteger3ICMP attempt count
[tcp]enabledbooleantrueEnable TCP stage
[tcp]timeoutinteger5000TCP timeout (ms)
[real_delay]enabledbooleantrueEnable real-delay stage
[real_delay]urlstringhttps://www.gstatic.com/generate_204Test URL
[real_delay]timeoutinteger10000HTTP request timeout (ms)
[download]enabledbooleanfalseEnable download stage
[download]urlstring-Download URL
[download]timeoutinteger30000Download timeout (ms)
[testing.geoip]enabledbooleanfalseEnable GeoIP enrichment
[testing.geoip]backendenummmdbLookup backend: mmdb, ipwhois, ip-api, chain
[testing.geoip]fallbackenumnoneFallback backend when primary is chain: ipwhois, ip-api, none
[testing.geoip]country_pathstringmmdb/GeoLite2-Country.mmdbCountry MMDB path (relative to config)
[testing.geoip]city_pathstringmmdb/GeoLite2-City.mmdbCity MMDB path (relative to config)
[testing.geoip]asn_pathstringmmdb/GeoLite2-ASN.mmdbASN MMDB path (relative to config)
[remote]providerenumipwhoisRemote provider: ipwhois, ip-api
[remote]endpointstring"" (uses provider default)Remote API endpoint override
[remote]timeout_msinteger5000Remote request timeout in milliseconds
[remote]api_keystring""API key (provider-specific)
[remote]rate_limit_per_minuteinteger30Max remote requests per minute
[cache]enabledbooleantrueEnable in-memory caching
[cache]ttl_secsinteger86400Cache entry TTL in seconds
[cache]max_entriesinteger10000Maximum cache entries

Upload tests are enabled per invocation with xrat test --upload-url <url>. There is no [testing.upload] config section; --upload-timeout overrides the default 30-second upload timeout.


Environment Variable References

Sensitive fields accept environment variable references:

# Literal value
password = "my-secret-password"

# Environment variable
password = { env = "XRAT_SOCKS_PASSWORD" }

Supported on these fields:

SectionField
[server]key
[runtime.socks]auth.password
[runtime.shadowsocks]password
[database.postgres]user
[database.postgres]password

Example Config

See testdata/config.example.toml in the repository for a complete example with all sections and comments.