Rule-Based Routing
Configure rule-based traffic routing with GeoIP, domain, and CIDR matching
trojan-rs supports rule-based routing to direct connections through different outbound connectors based on domain names, IP addresses, GeoIP country codes, and more.
Overview
The routing system evaluates rules in order (first match wins). Each rule maps to an outbound connector that determines how the connection is handled.
Connection ──▶ Rule Engine ──▶ Match? ──▶ Outbound Connector ──▶ Target
│ │
│ DOMAIN-SUFFIX .cn ├── DIRECT (direct connection)
│ GEOIP CN ├── REJECT (block)
│ RULE-SET blocked ├── proxy-jp (trojan proxy)
│ FINAL └── proxy-us (trojan proxy)Configuration
Step 1: Define Outbound Connectors
# Direct outbound (bypass proxy)
[server.outbounds.direct-out]
type = "direct"
# bind = "0.0.0.0" # Optional: bind to specific local IP
# Trojan proxy outbound
[server.outbounds.proxy-jp]
type = "trojan"
addr = "jp-server.example.com:443"
password = "proxy-password"
sni = "jp-server.example.com"
# Another proxy
[server.outbounds.proxy-us]
type = "trojan"
addr = "us-server.example.com:443"
password = "proxy-password"
sni = "us-server.example.com"Outbound types:
direct— Connect directly to the targettrojan— Forward through another trojan-serverreject— Block the connection
Step 2: Configure GeoIP (Optional)
[server.geoip]
source = "geolite2-country" # Built-in CDN source
auto_update = true # Background updates
interval = 604800 # 7 days
cache_path = "/var/cache/trojan/geoip.mmdb"Available sources: geolite2-country, geolite2-city, dbip-country, dbip-city, geolite2-asn, dbip-asn, iptoasn-country, iptoasn-asn.
You can also provide a local file:
[server.geoip]
path = "/path/to/GeoLite2-Country.mmdb"Step 3: Add Rule Providers (Optional)
Load external rule sets from local files or remote URLs:
# Surge-format rule list
[server.rule-providers.china-domains]
format = "surge"
source = "file"
path = "/etc/trojan/rules/china-domains.list"
# Clash-format rule provider with HTTP auto-update
[server.rule-providers.gfw-list]
format = "clash"
behavior = "domain"
source = "http"
url = "https://example.com/gfw-domains.yaml"
interval = 86400
path = "/var/cache/trojan/gfw-list.yaml"Rule provider formats:
- Surge: One rule per line (
TYPE,VALUEformat) - Clash: YAML
payloadlist with behavior hints (domain,ipcidr,classical,domain-set)
Step 4: Define Routing Rules
Rules are evaluated in order. The first matching rule determines the outbound.
# Direct connection for Chinese domains
[[server.rules]]
rule-set = "china-domains"
outbound = "DIRECT"
# Block ads
[[server.rules]]
rule-set = "ad-block"
outbound = "REJECT"
# Direct for Chinese IPs
[[server.rules]]
type = "GEOIP"
value = "CN"
outbound = "DIRECT"
# Direct for private networks
[[server.rules]]
type = "IP-CIDR"
value = "10.0.0.0/8"
outbound = "DIRECT"
[[server.rules]]
type = "IP-CIDR"
value = "192.168.0.0/16"
outbound = "DIRECT"
# Proxy everything else through Japan
[[server.rules]]
type = "FINAL"
outbound = "proxy-jp"Supported Rule Types
| Type | Value Example | Description |
|---|---|---|
DOMAIN | example.com | Exact domain match |
DOMAIN-SUFFIX | .google.com | Match domain and all subdomains |
DOMAIN-KEYWORD | youtube | Match if domain contains keyword |
IP-CIDR | 10.0.0.0/8 | IPv4 CIDR range |
IP-CIDR6 | 2001:db8::/32 | IPv6 CIDR range |
GEOIP | CN | GeoIP country code (ISO 3166-1 alpha-2) |
DST-PORT | 443 | Destination port |
SRC-IP-CIDR | 192.168.1.0/24 | Source IP range |
RULE-SET | provider name | Match against a rule provider |
FINAL | (none) | Default action, must be last |
IP Resolution
Some rules require resolving the target IP address (e.g., GEOIP, IP-CIDR). The engine uses a two-phase matching approach:
- Domain-based rules are evaluated first (no DNS needed)
- If no domain rule matches, the engine returns
NeedIp— the server resolves the domain and re-evaluates IP-based rules
This avoids unnecessary DNS lookups for connections that match domain rules.
Surge Rule Format
# Comment
DOMAIN,example.com
DOMAIN-SUFFIX,google.com
DOMAIN-KEYWORD,youtube
IP-CIDR,10.0.0.0/8
IP-CIDR6,2001:db8::/32Clash Rule Format
payload:
- 'example.com'
- '+.google.com'
- '.youtube.com'Clash prefixes:
+.domain.com— domain suffix match.domain.com— domain suffix matchdomain.com— exact match (fordomainbehavior)