Operate a DNS seeder¶
A DNS seeder is the lookup service a brand-new Bitcoin Gold (BTG) node uses to find its first peers. Every bgoldd instance, when starting with an empty peers.dat, queries the official seed domains (e.g. dnsseed.bitcoingold.dev, dnsseed.bitcoingold.services) for an A record, then connects to one of the returned addresses. The hardcoded seed list in chainparams.cpp also includes dnsseed.bitcoingold.org, eu-dnsseed.bitcoingold-official.org, dnsseed.btgofficial.org, and dnsseed.4btg.org — but as of 2026-06-06 none of those resolve; see the warning below.
This page walks through standing up the sipa/bitcoin-seeder C++ seeder for Bitcoin Gold (BTG) — the same binary family used by Bitcoin Core, Dogecoin, and most Bitcoin-derived networks. The walkthrough mirrors what runs in production at dnsseed.bitcoingold.services.
Most of the seed hostnames bgoldd ships with are currently dead
As of 2026-06-06, only the *.dev and dnsseed.bitcoingold.services hostnames actually answer. Everything else in the hardcoded vSeeds list in bgoldd's src/chainparams.cpp is broken for one of two reasons:
bitcoingold.orgdomain hijacked on 2024-07-15 (see Notable security incidents) —dnsseed.bitcoingold.org,test-dnsseed.bitcoingold.org, and any subdomain ofbitcoingold-official.orgregistered through the compromised registrar (e.g.eu-dnsseed.bitcoingold-official.org).- Subdomains that simply do not exist on their parent zones —
dnsseed.btgofficial.org,dnsseed.4btg.org,test-dnsseed.btgofficial.org,tdnsseed.4btg.org. Thebtgofficial.organd4btg.orgzones exist (Cloudflare-fronted) but the seed subdomains are not delegated to anything.
If you are deploying a new seeder, also publish a *.dev (or other neutral) hostname for it, and document it on the Network spec page, so the network still has at least one good seed.
Also note: the production seeder advertises a -m contact of privacy.bitcoingold.services, but as of this writing that hostname does not resolve. Treat it as a known, non-fatal warning in the seeder log, not a deploy blocker — the seeder still answers queries.
Who this is for¶
You are running a public infrastructure service for the Bitcoin Gold (BTG) network. Operating a seeder is not the same as running a node — you don't need chain data, but you do need a dedicated host, a static IP, and a delegated DNS zone.
What you'll build¶
- A compiled
dnsseedbinary at/opt/sipa-seeder/dnsseed. - A dedicated
dnsseedsystem user. - A
systemdunit that runs the seeder underProtectSystem=strict. - A delegated NS record (
ns1.bitcoingold.services) pointing at the seeder host. - Verification with
dig,drill, and a packet capture.
Requirements¶
| Resource | Minimum | Recommended |
|---|---|---|
| OS | Ubuntu 22.04 LTS | Ubuntu 22.04 / 24.04 LTS |
| CPU | 1 core | 2 cores |
| RAM | 512 MB | 1 GB |
| Disk | 5 GB | 10 GB (peers cache + logs) |
| Network | 1 Gbps unmetered | 1 Gbps unmetered, no NAT |
| Ports | UDP/53 inbound + TCP/53 inbound | (allow ICMP for monitoring) |
| DNS | A static IP + a delegated NS record | Use a registrar that supports NS delegation (Cloudflare, Gandi, etc.) |
Why a dedicated host?
DNS seeders are prime targets for amplification/reflection attacks. Running it on a single-purpose VM (no other services, no users, no wallet) is the single biggest hardening step.
1. Build the seeder¶
The seeder source has only two dependencies: a C++ compiler and libcurl (for the optional peer crawler).
sudo apt update
sudo apt install -y build-essential libcurl4-openssl-dev
sudo mkdir -p /opt/sipa-seeder
sudo chown -R "$USER":"$USER" /opt/sipa-seeder
cd /opt/sipa-seeder
git clone https://github.com/sipa/bitcoin-seeder.git .
make
ls -lh dnsseed
You should now have a dnsseed binary of ~260 KB. Static build, no other artifacts.
2. Create the system user¶
sudo useradd --system --home /opt/sipa-seeder --shell /usr/sbin/nologin dnsseed
sudo chown -R dnsseed:dnsseed /opt/sipa-seeder
3. Run it manually first¶
This is the command line used in production at bitcoingold.services. Walk through each flag:
sudo -u dnsseed /opt/sipa-seeder/dnsseed \
-h dnsseed.bitcoingold.services \
-n ns1.bitcoingold.services \
-m privacy.bitcoingold.services \
--magic e1476d44 \
--p2port 8338 \
-s dnsseed.bitcoingold.dev \
-t 10 \
--peers-file /opt/sipa-seeder/peers.txt
| Flag | Meaning |
|---|---|
-h |
The hostname the seeder publishes as the source of the A records. Pick something that ends in your delegated zone. |
-n |
The NS hostname for the delegated zone. Must be in your registrar's glue records. |
-m |
Abuse contact email (shown in the SOA record). |
--magic |
Bitcoin Gold (BTG) network magic: e1 47 6d 44 → e1476d44 (no spaces). |
--p2port |
Bitcoin Gold (BTG) P2P port: 8338. |
-s |
Optional second seeder hostname to also crawl (gives the crawler more bootstrap peers). |
-t |
Number of crawler threads. 10 is plenty on a 2-core VM. |
--peers-file |
Where the seeder persists its known-peer cache. |
After a few minutes you should see something like:
Hit Ctrl-C once you've confirmed it crawls successfully (look for the peer count growing in peers.dat).
4. systemd unit¶
sudo tee /etc/systemd/system/dnsseed.service > /dev/null <<'EOF'
[Unit]
Description=Bitcoin Gold DNS seeder (sipa)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=dnsseed
Group=dnsseed
WorkingDirectory=/opt/sipa-seeder
ExecStart=/opt/sipa-seeder/dnsseed \
-h dnsseed.bitcoingold.services \
-n ns1.bitcoingold.services \
-m privacy.bitcoingold.services \
--magic e1476d44 \
--p2port 8338 \
-s dnsseed.bitcoingold.dev \
-t 10 \
--peers-file /opt/sipa-seeder/peers.txt
Restart=always
RestartSec=10
LimitNOFILE=65536
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
# --- hardening ---
NoNewPrivs=yes
ProtectSystem=strict
ReadWritePaths=/opt/sipa-seeder
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now dnsseed.service
sudo journalctl -u dnsseed.service -f
Why CAP_NET_BIND_SERVICE?
The seeder binds UDP/53, which is a privileged port. We grant the CAP_NET_BIND_SERVICE capability instead of running as root. ProtectSystem=strict makes the rest of the filesystem read-only.
5. Firewall¶
Only DNS needs to be reachable from the internet. The seeder also makes outbound Bitcoin Gold (BTG) P2P connections to crawl the network.
sudo ufw allow 53/udp comment "DNS"
sudo ufw allow 53/tcp comment "DNS (large replies)"
sudo ufw allow out 8338/tcp comment "Bitcoin Gold (BTG) P2P crawler"
sudo ufw status verbose
6. Delegate the zone¶
This is the step most operators miss. For the seeder to actually answer queries for dnsseed.bitcoingold.services, your registrar must delegate the parent zone to your seeder's NS.
At the registrar (Cloudflare / Gandi / Namecheap), create a glue record:
- Name:
dnsseed.bitcoingold.services - Type:
NS - Value:
ns1.bitcoingold.services
And the corresponding glue A record:
- Name:
ns1.bitcoingold.services - Type:
A - Value:
<your-seeder-public-ip> - TTL: 300
Glue records must match the seeder host
The seeder's -n ns1.bitcoingold.services must resolve to the same IP as the host where dnsseed is running. If the IP is wrong, every recursive resolver will get an empty response.
7. Verification¶
Wait ~5 minutes for the SOA/NS records to propagate, then:
# NS delegation visible
dig NS dnsseed.bitcoingold.services @8.8.8.8
# expect: dnsseed.bitcoingold.services. 300 IN NS ns1.bitcoingold.services.
# Glue record resolves
dig A ns1.bitcoingold.services @8.8.8.8
# expect: ns1.bitcoingold.services. 300 IN A <your-ip>
# Seeder answers
dig A dnsseed.bitcoingold.services @ns1.bitcoingold.services +short
# expect: a handful of A records
# SOA record
dig SOA dnsseed.bitcoingold.services @8.8.8.8
If the NS record is wrong, fix it at the registrar and wait the TTL. If the seeder itself doesn't answer, check journalctl -u dnsseed.service and the firewall.
8. Operating¶
Peers cache¶
peers.dat is the persistent peer cache. It survives restarts and is the single most important file. Back it up.
Crawler stats¶
The seeder writes dnsstats.log with crawler reachability. Useful for monitoring which subnets are well-connected.
Restart behaviour¶
Type=simple + Restart=always means systemd will relaunch the seeder within 10 seconds if it crashes. The peer cache makes this cheap — first crawl after restart reuses everything from peers.dat.
Updating¶
The seeder doesn't need frequent updates; the sipa/bitcoin-seeder source changes maybe once or twice a year. When you do update:
cd /opt/sipa-seeder
sudo systemctl stop dnsseed.service
sudo -u dnsseed cp peers.dat peers.dat.bak
git pull && make
sudo systemctl start dnsseed.service
Troubleshooting¶
Seeder answers queries but always returns 0 A records¶
The crawler hasn't seen any peers yet. Wait 5–10 minutes; if still empty, the outbound 8338/tcp may be blocked.
If you see outgoing SYNs but no replies, the upstream network is filtering Bitcoin Gold (BTG). Move to a more permissive host.
"permission denied" binding to UDP/53¶
The capability is set but not active in the running service. Restart the service, not the unit file.
"Address family not supported by protocol"¶
You're trying to listen on IPv6 but the host has no IPv6 address. Add --ipv4 to the command line, or enable IPv6 on the host.
Recursive resolvers don't trust the seeder¶
The seeder must serve an SOA record (the dnsseed binary does this automatically). Verify:
What to do next¶
- Add a second seeder at a different IP / datacenter for resilience.
- Cross-link with the Blockbook course if you also want to expose an explorer.
- Harden the host following Hardening.
- Publish your seeder hostname in the Network spec so other operators can include it in their
bitcoingold.conf.
Source / further reading¶
- sipa/bitcoin-seeder — the C++ source.
- Bitcoin Core DNS seed policy — applicable rules of behaviour for seeders.
- Bitcoin Gold (BTG) Network spec — official seed hostnames and ports.