| Crates.io | lazy-dns |
| lib.rs | lazy-dns |
| version | 1.0.14 |
| created_at | 2025-09-05 08:37:35.567782+00 |
| updated_at | 2025-09-07 02:57:04.435178+00 |
| description | A lazy DNS server with GeoIP routing. Only SOA, NS, A, AAAA, CNAME, MX, and TXT are supported; everything else is dropped, by design. |
| homepage | |
| repository | https://github.com/canmi21/lazy-dns |
| max_upload_size | |
| id | 1825266 |
| size | 85,427 |
A lightweight, plug-and-play DNS server with auto-reload configuration and GeoIP-based routing capabilities. Designed for simplicity, Lazy DNS supports only A, AAAA, and CNAME records, intentionally dropping all other record types.
lazy-mmdb).~/lazy-dns/config.toml.lazy-mmdb service must be running and accessible via a Unix socket at /tmp/lazy-mmdb.sock.Clone the repository:
git clone https://github.com/canmi21/lazy-dns.git
cd lazy-dns
Build and run the project:
cargo build --release
cargo run --release
(Optional) Install the binary:
cargo install --path .
This makes the lazy-dns command available globally.
Lazy DNS uses a TOML configuration file to define DNS records and settings. By default, it looks for ~/lazy-dns/config.toml. You can override this by setting the CONFIG_PATH environment variable.
The default configuration is created automatically if no config file is found. Below is an example from .env.example and the default config.toml:
# Default TTL for all records in minutes, if not specified per domain.
default_ttl = 5
[domains]
# Simple domain with A and AAAA records.
[domains."test.local"]
a = ["127.0.0.1"]
aaaa = ["::1"]
# Domain with multiple A records for random selection (load balancing).
[domains."roundrobin.local"]
a = ["192.168.1.10", "192.168.1.20"]
ttl = 1
# Domain with GeoIP routing rules.
[domains."geo.local"]
a = ["8.8.8.8"]
cname = ["default.geo.local"]
[domains."geo.local".country]
US = { a = ["1.1.1.1", "1.0.0.1"], cname = ["us.geo.local"] }
CN = { a = ["114.114.114.114"], aaaa = ["2400:3200::1"] }
JP = { cname = ["jp.geo.local"] }
Configuration can be customized via environment variables, as shown in .env.example:
LOG_LEVEL: Set logging verbosity (debug, info, warn, error). Default: info.BIND_PORT: Port for the DNS server. Default: 53 (requires root privileges for ports < 1024).CONFIG_PATH: Path to the TOML config file. Default: ~/lazy-dns/config.toml.GEOIP_RECONNECT_SECONDS: Interval to retry connecting to the GeoIP service. Default: 300 seconds.Example .env file:
LOG_LEVEL=debug
BIND_PORT=5353
CONFIG_PATH=/path/to/custom/config.toml
GEOIP_RECONNECT_SECONDS=600
Ensure the configuration file is set up as needed.
Start the DNS server:
lazy-dns
Or specify a custom port:
BIND_PORT=5353 lazy-dns
Test the server using a DNS client like dig:
dig @127.0.0.1 -p 5353 test.local
For GeoIP routing, ensure the lazy-mmdb service is running and accessible at /tmp/lazy-mmdb.sock.
lazy-dns/
├── src/
│ ├── config.rs # Configuration loading and parsing
│ ├── dns_server.rs # DNS server implementation
│ ├── geoip.rs # GeoIP client for country-based routing
│ ├── main.rs # Entry point
│ ├── resolver.rs # DNS query resolution logic
├── .env.example # Example environment variables
├── Cargo.toml # Rust project configuration
├── LICENSE # MIT License
Lazy DNS relies on the following Rust crates:
dotenvy: For environment variable parsing.fancy-log: For colorful and leveled logging.hickory-proto: For DNS protocol handling.lazy-motd: For a startup message.tokio: For asynchronous runtime.serde and toml: For configuration parsing.rand: For random record selection (load balancing).dirs: For finding the home directory.serde_json: For GeoIP response parsing.parking_lot: For thread-safe locking.This project is licensed under the MIT License. See the LICENSE file for details.
Contributions are welcome! Please open an issue or submit a pull request on the GitHub repository.
For questions or feedback, open an issue on the GitHub repository or contact the maintainer at the repository's listed contact information.