Dynamic DNS
Automatically update DNS records when your server's public IP changes
trojan-rs includes a built-in DDNS client that detects public IP changes and updates DNS records automatically. This is useful when running a server on a dynamic IP address (home network, some VPS providers).
How It Works
trojan-server
│
├── [every 300s] GET https://api.ipify.org → current IP
│
├── IP changed?
│ ├── No → skip
│ └── Yes → update DNS records via Cloudflare API
│
└── continue serving connectionsThe DDNS updater runs as a background task inside the server process. It shares the same graceful shutdown mechanism — when the server stops, the DDNS loop stops too.
Cloudflare Setup
1. Create an API Token
- Go to Cloudflare Dashboard
- Click Create Token
- Use the Edit zone DNS template, or create a custom token with:
- Permissions: Zone → DNS → Edit
- Zone Resources: Include → Specific zone → your domain
- Copy the generated token
2. Configure the Server
[ddns]
enabled = true
interval = 300
[ddns.cloudflare]
api_token = "your-api-token-here"
zone = "example.com"
records = ["example.com", "*.example.com"]
proxied = false
ttl = 13. Start the Server
trojan server -c server.tomlOn startup you will see:
INFO starting DDNS update task
INFO DDNS update loop started zone="example.com" records=["example.com", "*.example.com"]
INFO detected IPv4 address ip=203.0.113.42
INFO DNS record updated name="example.com"
INFO DNS record created name="*.example.com"Configuration Reference
[ddns]
| Option | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Enable DDNS updates |
interval | int | 300 | Seconds between IP checks |
ipv4_urls | string[] | ["https://api.ipify.org", ...] | URLs to detect public IPv4 address |
ipv6_urls | string[] | [] | URLs to detect public IPv6 address (empty = disabled) |
[ddns.cloudflare]
| Option | Type | Default | Description |
|---|---|---|---|
api_token | string | required | Cloudflare API token with DNS edit permission |
zone | string | required | Domain name (Cloudflare zone) |
records | string[] | required | DNS record names to create/update |
proxied | bool | false | Enable Cloudflare CDN proxy (orange cloud) |
ttl | int | 1 | DNS record TTL in seconds. 1 = automatic |
IP Detection
The DDNS client detects your public IP by querying external HTTP endpoints. URLs are tried in order — the first successful response is used.
Default IPv4 detection URLs:
ipv4_urls = [
"https://api.ipify.org",
"https://ifconfig.me/ip",
"https://ip.sb",
]You can customize or replace these:
[ddns]
ipv4_urls = ["https://checkip.amazonaws.com"]IPv6 Support
IPv6 is disabled by default. To enable it, configure IPv6 detection URLs:
[ddns]
ipv6_urls = ["https://api6.ipify.org", "https://ifconfig.me/ip"]When enabled, both A (IPv4) and AAAA (IPv6) records are managed for each configured record name.
Update Behavior
- First run: Detects IP and creates or updates all configured records
- Subsequent runs: Only calls the Cloudflare API when the IP actually changes
- Partial failures: Successfully updated records are skipped on retry; only failed records are retried on the next cycle
- Zone ID caching: The Cloudflare zone ID is resolved once and cached for the lifetime of the process
- Record existence: If a record does not exist, it is created automatically. If it already exists with the correct IP, no API call is made
Example: Full Server with DDNS
[server]
listen = "0.0.0.0:443"
fallback = "127.0.0.1:80"
[tls]
cert = "/etc/trojan/cert.pem"
key = "/etc/trojan/key.pem"
alpn = ["h2", "http/1.1"]
[auth]
passwords = ["my-secret-password"]
[ddns]
enabled = true
interval = 300
[ddns.cloudflare]
api_token = "cf-api-token"
zone = "example.com"
records = ["trojan.example.com"]
proxied = false
ttl = 1
[logging]
level = "info"