A decentralized DNS system that resolves blockchain-based domain names by querying smart contracts on NEAR Protocol.
NEAR DNS enables domain name resolution for NEAR ecosystem TLDs (.near, .testnet, etc.) by storing DNS records in smart contracts. Each NEAR account can deploy a DNS contract as a subaccount (dns.<account>.<tld>) to manage their domain's DNS records.
Key Design Principle: NEAR DNS is not intended to be a centralized DNS provider. Since all DNS records are stored on the NEAR blockchain, the DNS server itself is essentially a stateless gateway that translates DNS queries into blockchain lookups. Self-hosting is encouraged — you can run your own instance and get the exact same results as any other instance, because the source of truth is always the blockchain.
- DNS Query: Client queries
example.nearA record - TLD Detection: Server identifies
.nearas a NEAR TLD - Contract Lookup: Server queries
dns.example.nearcontract for records - Response: DNS records are returned from the blockchain
For traditional domains (.com, .org, etc.), queries are forwarded to upstream DNS servers (Google/Cloudflare).
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ DNS Client │────▶│ NEAR DNS Server │────▶│ NEAR Blockchain│
│ (dig) │◀────│ (Rust/Hickory) │◀────│ (DNS Contract) │
└─────────────┘ └──────────────────┘ └─────────────────┘
│
▼
┌───────────────┐
│ Upstream DNS │
│ (Google/CF) │
└───────────────┘
- For developers with or without web3 background: NEAR DNS - DNS records stored on blockchain and served over DNS protocol
- For developers with web3 background: NEAR DNS - DNS records stored on NEAR and served over DNS protocol
There is currently one publicly available NEAR DNS server connected to mainnet:
DNS Server: 185.149.40.161 (port 53)
Try it out:
# Query a mainnet domain
dig @185.149.40.161 neardns.near A
# Expected response:
# neardns.near. 1 IN A 185.149.40.161Note: This public server is provided for convenience, but self-hosting is encouraged. Since NEAR DNS is stateless (all data comes from the blockchain), running your own instance gives you the same results with better privacy and no single point of failure.
A Rust DNS server built with Hickory DNS that:
- Resolves NEAR domains by querying smart contracts via RPC
- Forwards non-NEAR domains to upstream DNS servers
- Supports hierarchical subdomain resolution
- Implements wildcard record matching
- Caches responses for performance
A NEAR smart contract that stores DNS records with:
- Support for common record types (A, AAAA, CNAME, MX, TXT, etc.)
- Owner-only record management (parent account controls records)
- Wildcard record support (
*entries) - Iterable storage for listing all records
- Rust 1.86
- NEAR CLI
- A NEAR account (testnet or mainnet)
# Clone and build
git clone https://github.com/frol/near-dns
cd near-dns
cargo build --release --package near-dns-server
# Run the server (mainnet)
RUST_LOG=info ./target/release/near-dns-server \
--bind 127.0.0.1:5355 \
--rpc-url https://rpc.mainnet.near.org
# Test with dig
dig @127.0.0.1 -p 5355 neardns.near A# Run the server (testnet)
RUST_LOG=info ./target/release/near-dns-server \
--bind 127.0.0.1:5355 \
--rpc-url https://rpc.testnet.near.org
# Test with dig
dig @127.0.0.1 -p 5355 near-dns.testnet A
dig @127.0.0.1 -p 5355 near-dns.testnet TXTNon-NEAR domains are forwarded to upstream DNS servers:
dig @127.0.0.1 -p 5355 google.com A # Forwarded upstream# Run with mainnet RPC (default)
docker run -d --name near-dns \
-p 53:53/udp \
-p 53:53/tcp \
frolvlad/near-dns
# Test it
dig @localhost neardns.near A# Run with testnet RPC
docker run -d --name near-dns-testnet \
-p 5355:53/udp \
-p 5355:53/tcp \
frolvlad/near-dns \
--bind 0.0.0.0:53 \
--rpc-url https://rpc.testnet.near.org
# Test it
dig @localhost -p 5355 near-dns.testnet A# Run with custom log level
docker run -d --name near-dns \
-e RUST_LOG=debug \
-p 53:53/udp \
-p 53:53/tcp \
frolvlad/near-dns
# View logs
docker logs -f near-dnsdocker build -t near-dns .
docker run -d -p 5355:53/udp -p 5355:53/tcp near-dnsBuild the contract first using cargo near:
cd dns-contract
cargo near build# Create a subaccount for DNS
near account create-account fund-myself dns.youraccount.near '2.1 NEAR' \
autogenerate-new-keypair save-to-keychain \
sign-as youraccount.near network-config mainnet sign-with-keychain send
# Build the contract
cd dns-contract
cargo near build non-reproducible-wasm
# Deploy with initialization
near contract deploy dns.youraccount.near \
use-file target/near/dns_contract.wasm \
with-init-call new json-args '{}' \
prepaid-gas '30 Tgas' attached-deposit '0 NEAR' \
network-config mainnet sign-with-keychain sendUnlike mainnet, you can create a new account and get some free NEAR tokens on testnet using this simple command:
near account create-account sponsor-by-faucet-service# Create a subaccount for DNS
near account create-account fund-myself dns.youraccount.testnet '2.1 NEAR' \
autogenerate-new-keypair save-to-keychain \
sign-as youraccount.testnet network-config testnet sign-with-keychain send
# Deploy with initialization
near contract deploy dns.youraccount.testnet \
use-file target/near/dns_contract.wasm \
with-init-call new json-args '{}' \
prepaid-gas '30 Tgas' attached-deposit '0 NEAR' \
network-config testnet sign-with-keychain sendThe examples below use testnet. For mainnet, replace .testnet with .near and network-config testnet with network-config mainnet.
# Add an A record
near contract call-function as-transaction dns.youraccount.testnet dns_add \
json-args '{"name": "@", "record": {"record_type": "A", "value": "1.2.3.4", "ttl": 300, "priority": null}}' \
prepaid-gas '30 Tgas' attached-deposit '0 NEAR' \
sign-as youraccount.testnet network-config testnet sign-with-keychain send
# Add a subdomain
near contract call-function as-transaction dns.youraccount.testnet dns_add \
json-args '{"name": "www", "record": {"record_type": "A", "value": "1.2.3.5", "ttl": 300, "priority": null}}' \
prepaid-gas '30 Tgas' attached-deposit '0 NEAR' \
sign-as youraccount.testnet network-config testnet sign-with-keychain send
# Add a wildcard record (matches any subdomain)
near contract call-function as-transaction dns.youraccount.testnet dns_add \
json-args '{"name": "*", "record": {"record_type": "A", "value": "1.2.3.100", "ttl": 300, "priority": null}}' \
prepaid-gas '30 Tgas' attached-deposit '0 NEAR' \
sign-as youraccount.testnet network-config testnet sign-with-keychain send
# Query records
near contract call-function as-read-only dns.youraccount.testnet dns_query \
json-args '{"name": "@", "record_type": "A"}' \
network-config testnet now
# List all records
near contract call-function as-read-only dns.youraccount.testnet dns_list_all \
json-args '{}' network-config testnet now| Method | Arguments | Description |
|---|---|---|
dns_query |
name: String, record_type: String |
Query specific record type for a name |
dns_query_all |
name: String |
Get all record types for a name |
dns_list_names |
- | List all DNS names with records |
dns_list_all |
- | List all records in the contract |
get_owner |
- | Get the contract owner |
| Method | Arguments | Description |
|---|---|---|
dns_add |
name: String, record: DnsRecord |
Add a DNS record |
dns_update |
name: String, records: Vec<DnsRecord> |
Replace all records of a type |
dns_delete |
name: String, record_type: Option<String> |
Delete records |
transfer_ownership |
new_owner: AccountId |
Transfer contract ownership |
{
"record_type": "A",
"value": "192.168.1.1",
"ttl": 300,
"priority": null
}Supported record types: A, AAAA, CNAME, MX, TXT, NS, SRV, SOA, PTR, CAA
For a query like sub.example.near:
- Check if
nearis a known NEAR TLD - Try
dns.sub.example.nearwith name@ - Try
dns.example.nearwith namesub - Try
dns.example.nearwith name*(wildcard) - Return NXDOMAIN if no records found
The DNS server recognizes these NEAR TLDs:
near(mainnet)testnetauroratgsweatkaichingsharddog
All other TLDs are forwarded to upstream DNS servers.
- Contract:
dns.neardns.near - Owner:
neardns.near
- Contract:
dns.near-dns.testnet - Owner:
near-dns.testnet
# Run DNS server tests
cd dns-server
cargo test
# Run contract tests
cd dns-contract
cargo test
# Build contract WASM
cd dns-contract
cargo near build non-reproducible-wasmLicensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
See CONTRIBUTING.md for guidelines.