Documentation

Last updated: 2026-08-11

How to host a root domain on a public static IP

This walkthrough hosts a root domain like jens.dev on a single Everlock instance that has a public static IP — a typical VPS, dedicated server, or paid static line. No NAT, no IP changes, no glue games. This is the simplest possible production setup.

If your hosting situation is different, see the companions:


What you need

  • A registered domain (jens.dev in this walkthrough). Any registrar works; the steps below show the GoDaddy panel but the fields are the same everywhere (Cloudflare, Namecheap, INWX, Porkbun, …).
  • A host with a static public IPv4 (and ideally IPv6 too). A €3/month VPS at Hetzner / OVH / Scaleway is plenty.
  • UDP and TCP port 53 open inbound on the host's firewall.

1. Open port 53 on the host

On the VPS, allow inbound DNS:

# ufw
sudo ufw allow 53/udp
sudo ufw allow 53/tcp

# or nftables / iptables / cloud-firewall — whichever you use.

For Hetzner Cloud, OVH, Scaleway: add 0.0.0.0/0 and ::/0 rules for ports 53/udp and 53/tcp in the cloud firewall on top of the host firewall.


2. Install and start Everlock

Drop the binary on the host, then start it:

everlock serve \
  --frontend-ssh \
  --backend-admin-ssh \
  --frontend-dns \
  --frontend-dns-listen-udp 0.0.0.0:53,[::]:53 \
  --frontend-dns-listen-tcp 0.0.0.0:53,[::]:53 \
  --backend-dns-dns \
  --admin-user admin \
  --admin-password change-me

Binding port 53 needs root or CAP_NET_BIND_SERVICE:

sudo setcap CAP_NET_BIND_SERVICE=+eip ./everlock

3. Tell Everlock its public IPs

Edit data/everlock-system/config/dns.toml:

enabled = true
listen_udp = "0.0.0.0:53,[::]:53"
listen_tcp = "0.0.0.0:53,[::]:53"
address_mode = "static"
default_ipv4 = "203.0.113.42"     # your VPS's IPv4
default_ipv6 = "2001:db8::42"     # your VPS's IPv6, if any

static mode tells Everlock "these values never change; don't probe external services, don't fall back to the local interface." If your routable IPs are already on the local interface (most VPSes), you can use address_mode = "interface" instead and skip the explicit default_ipv4 / default_ipv6 lines — Everlock will pick them up.

Either works. static is more explicit about your intent.

Reload:

ssh -p 2222 admin@<your-vps-ip>
/dns reload
/dns info

/dns info should show address mode = static (or interface) and your public IPv4 / IPv6 under public ipv4 / public ipv6.


4. Create the zone

/users grant admin ssh/dns/* owner
/dns zones create jens.dev

Everlock generates the implicit SOA / NS / glue records pointing at the IPs from step 3:

/dns records list jens.dev

You should see:

  • SOA jens.dev
  • NS jens.dev → ns1.jens.dev, NS jens.dev → ns2.jens.dev
  • A ns1.jens.dev → 203.0.113.42 (and ns2)
  • AAAA ns1.jens.dev → 2001:db8::42 (and ns2)

Both NS names resolve to the same host. That's normal for a single-instance setup; the TLD registry only requires two distinct NS names in the delegation.


5. Verify Everlock answers locally

From any external machine:

dig @203.0.113.42 jens.dev SOA
dig @203.0.113.42 jens.dev NS
dig @203.0.113.42 ns1.jens.dev A

You should see authoritative answers (AA flag).


6. Register the delegation at the registrar

The names of the fields differ by registrar; the values are the same everywhere.

a) Set the nameservers

In the registrar's panel for jens.dev, switch from the registrar's default nameservers to "Custom" and enter:

  • ns1.jens.dev
  • ns2.jens.dev

b) Register glue records

Because both NS hostnames live inside the zone they delegate to, the registry needs A/AAAA glue records to break the chicken-and-egg. Most registrars call this "Host Records", "Glue Records", or "Child Nameserver IPs".

Add:

HostIPv4IPv6 (optional)
ns1203.0.113.422001:db8::42
ns2203.0.113.422001:db8::42

Save. The registry propagates glue within minutes to a few hours depending on TLD.


7. Verify the public path

Once the parent zone has the new delegation:

dig @8.8.8.8 jens.dev SOA
dig @1.1.1.1 jens.dev NS
dig +trace jens.dev

+trace walks from the root to your nameservers and is the gold test that delegation is wired correctly.


8. Add real records

/users grant admin ssh/dns/jens.dev writer
/dns records create jens.dev name=@ type=A value=203.0.113.42 ttl=300
/dns records create jens.dev name=www type=CNAME value=jens.dev ttl=300
/dns records create jens.dev name=@ type=MX value="10 mail.jens.dev." ttl=3600

/dns records list jens.dev shows the effective view. Explicit records merge over the derived ones; for example the apex A you just added overrides any synthesised one for the same (name, type).


What you don't have to worry about in this topology

  • The IP never changes, so glue at the registrar never needs to follow.
  • No port-forward, no NAT, no Fritzbox UI.
  • No replication keys, no peers.

If you want a site, mail, or container registry on the same domain, follow How to combine DNS, site, and mail in one zone.


dns howto static-ip vps