You hold foo.whatever. This is how you put something behind it.
The machine serving the name never resolves it. Every machine visiting it must.
Almost every "my Moshpit site doesn't work" is this, in one of its two directions — a resolver installed on the server where it does nothing, or the site declared broken from a laptop that never had one.
needs moshcode dns? |
its job | |
|---|---|---|
| the box serving the name | no | Caddy matches a Host header. That is all it ever does. |
| the registry (the Pit) | — | holds the address the name points at |
| every visitor | yes | sudo moshcode dns enable, or the name resolves to nothing |
A Moshpit ending is not in the public DNS root. Nothing on the internet resolves it, and nothing ever will. The resolver is what makes the name mean something, and it is a per-machine choice made by whoever wants to visit.
moshcode template list
moshcode template install bun-caddy-sqliteThat writes a Caddyfile, systemd units and a Bun + SQLite service already wired the way this page describes. Nothing in a template runs on install — read it, then decide.
In the Pit, set points at to the machine's public IPv6 address. Bare — no scheme, no brackets, no port:
2606:4700:4700::1111
Find yours:
ip -6 addr show scope global | grep inet6Pick the globally routable one. An address starting fd or fc is
unique-local — that is where Tailscale and friends live — and the registry
refuses it, because a name pointed at one resolves somewhere only you can reach.
IPv4 literals are refused. An A record on a small host is usually leased,
NATed, or shared, and a name pointed at one goes stale without telling anyone. A
hostname (box.example.com) is accepted instead: keeping the address behind it
current is then someone else's job.
The web server needs a block that answers to the name, on port 80.
Caddy:
http://foo.whatever {
reverse_proxy 127.0.0.1:3000
}The http:// is required and is not a style choice. Leave it off and Caddy
tries to provision a TLS certificate for foo.whatever, fails — no CA will
issue for an ending outside the DNS root — and the site never comes up. This is
the single most common way this goes wrong.
nginx:
server {
listen [::]:80;
server_name foo.whatever;
root /srv/foo.whatever;
}Then open the port. On ufw this covers v6 as well:
sudo ufw allow 80/tcpBind your app to loopback, not the public address. Caddy is its only client, and binding it publicly publishes it on a port nothing virtual-hosts — which hands anyone scanning the box the app with the name stripped off the front.
On every machine that should see the name:
sudo moshcode dns enableThat does two things: writes a systemd-resolved drop-in routing Moshpit
endings at the bridge, and starts the bridge. The drop-in is a file and survives
a reboot. The bridge process does not — so after a restart the routing
points at a port with nothing behind it, and every Moshpit name stops resolving
with no obvious cause. The bundled deploy/moshcode-dns.service is the missing
half:
sudo cp deploy/moshcode-dns.service /etc/systemd/system/
sudo systemctl enable --now moshcode-dnsEvery layer fails identically in a browser, so do not debug from one.
# 1. Server only — no DNS involved at all.
# Proves Caddy, the firewall, and the app.
curl -6 -H "Host: foo.whatever" http://[YOUR:V6:ADDR]/
# 2. Resolver only. Proves the registry and the bridge.
moshcode dns resolve foo.whatever
# 3. Both together.
curl -6 http://foo.whatever/If 1 passes and 3 fails, it is DNS. If 1 fails, stop looking at DNS.
| target | resolver path | /n/ gateway |
|---|---|---|
2606:4700:4700::1111 |
AAAA record | fetched, bracketed |
box.example.com |
not answered — the bridge does no clearnet DNS | resolved, then fetched |
[2606:...]:8080 |
port dropped — browsers go to 80 | fetched on 8080 |
203.0.113.7 |
refused when saved | refused when saved |
DNS carries an address and has nowhere to put a port. A target naming a non-default port therefore works only through the gateway, and a browser using the resolver will go to port 80 regardless of what the target says.
- No HTTPS, ever. No CA will issue for an ending outside the DNS root. That rules out secure cookies, service workers, and WebCrypto in the browser. Everything at a Moshpit name is plain HTTP.
- Only machines running the resolver can reach the name. Not phones, not a
colleague who hasn't installed it, not Googlebot, not a webhook from a payment
provider.
pit.moshcode.sh/n/foo.whateveris the URL to send people who have installed nothing — it fetches the target server-side and hands back the page. - One level deep.
foo.whateverresolves;www.foo.whateverdoes not. Moshpit names are exactly one label and one ending. - The gateway is not a file host. It gives the origin 10 seconds and caps
the body at 5 MB, strips cookies and
Authorizationin both directions, and sandboxes the result with CSP.