feat(dns): implement dns service, the half a reboot takes away - #458
Merged
Conversation
`dns service` has been listed in DNS_VERBS since the verb table was written,
so it appeared in `dns help` and in shell completion. It had no handler:
`moshcode dns service` printed "unknown: dns service" and the usage block.
That mattered more than a missing verb usually does, because it is the half of
`dns enable` that does not survive a restart. The resolved drop-in is a file
and comes back on its own; the bridge process does not. After a reboot the
routing points at a port with nothing behind it and every Moshpit name stops
resolving with no obvious cause. It is the whole reason Moshpit DNS holds on
servers, which got a unit installed by hand, and falls over on desktops, which
never did.
A unit file did exist, in examples/templates/*/deploy/moshcode-dns.service, and
it could not start on an ordinary install:
ExecStart=/usr/bin/env moshcode dns start --port 5354
DynamicUser=yes
ProtectHome=yes
Three independent reasons, each fatal on its own. `moshcode` is not on
systemd's PATH - it installs to ~/.local/bin. The `node` its wrapper execs is
not on it either, because on a mise, nvm or asdf box that is another shim under
$HOME. And ProtectHome hides the install from the service even if both had been
found. It starts only where moshcode and node are both installed system-wide,
which is the server case that was already working, so the unit meant to fix
desktops was the one thing guaranteed not to.
No static unit can be right here, so this one is generated. `process.execPath`
is an interpreter demonstrably able to run this code, because it is running it,
and the entry is the script the command was invoked from. Nothing is guessed
and nothing depends on PATH.
moshcode dns service print it, change nothing
moshcode dns service --write install and start it, as this user
moshcode dns service --system a system unit instead
moshcode dns service --remove stop it and take it away
The user scope is the default because it matches how moshcode is installed: it
runs as the user, so $HOME and the shims are reachable, and systemd sets
XDG_RUNTIME_DIR so the pidfile lands exactly where an unprivileged `dns status`
looks. Under a system unit those are two different paths.
Installing a service stays a separate verb rather than folding into `enable` -
nothing here starts a service that was not asked for, and `--remove` touches
the service only, never the routing.
Also fixed, both in the path of this change: `docs/hosting-a-moshpit-name.md`
and the `dns` examples in cli-schema told people to type `sudo moshcode dns
enable`. The CLI escalates the one step that needs root by itself, and
`sudo moshcode` takes every path from the wrong $HOME.
Verified on a live systemd user session: the generated unit starts, binds,
forwards clearnet, answers Moshpit names, and comes back after SIGKILL under
Restart=always. Install and removal were exercised end to end on a spare port
so the box's real bridge was never shadowed. Suite: 2707 tests, 0 failures.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ThnQwoieWt8VR6N7gtgnhp
ThreatCrush Security Scan4 finding(s) in the 8 file(s) this pull request changes. HIGH/CRITICAL: 1 | MEDIUM: 3
84 pre-existing finding(s) elsewhere in the repository — **HIGH/CRITICAL**: 4 | **MEDIUM**: 70 | **LOW**: 10Not introduced by this pull request. The full set is in the Security tab.
…and 64 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
This was referenced Aug 30, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the desktop half of the DNS story that v0.77.0 left open.
The verb was advertised and unimplemented
dns servicehas been inDNS_VERBSsince the verb table was written, so it showed up indns helpand in shell completion. It had no handler:That matters more than a missing verb usually would, because it is the half of
dns enablethat does not survive a restart. The resolved drop-in is a file and comes back on its own; the bridge process does not. After a reboot the routing points at a port with nothing behind it and every Moshpit name stops resolving with no obvious cause.This is the whole reason Moshpit DNS holds on servers — which got a unit installed by hand — and falls over on desktops, which never did.
The unit that shipped could not start
One did exist, in
examples/templates/*/deploy/moshcode-dns.service:Three independent reasons it fails on an ordinary install, each fatal alone:
moshcodeis not on systemd's PATH — it installs to~/.local/binnodeits wrapper execs is not on it either, because on any mise/nvm/asdf box that is another shim under$HOMEProtectHome=yeshides the install from the service even if both had been found, andDynamicUser=yesgives it a$HOMEthat has no moshcode in itIt starts only where moshcode and node are both installed system-wide — the server case that was already working. The unit meant to fix desktops was the one thing guaranteed not to.
So the unit is generated
No static file can be correct here.
process.execPathis an interpreter demonstrably able to run this code, because it is running it, and the entry is the script the command was invoked from. Nothing is guessed, nothing depends on PATH.The user scope is the default because it matches how moshcode is installed: it runs as you, so
$HOMEand the shims are reachable, and systemd setsXDG_RUNTIME_DIRso the pidfile lands exactly where an unprivilegeddns statuslooks. Under a system unit those are two different paths.Installing a service stays its own verb rather than folding into
enable. Nothing here starts a service that was not asked for, and--removetouches the service only — never the routing.Also fixed, both in the path of this change
docs/hosting-a-moshpit-name.mdand thednsexamples incli-schema.mjstold people to typesudo moshcode dns enable. The CLI escalates the one step that needs root by itself, andsudo moshcodetakes every path from the wrong$HOME.Verification
Exercised against a live systemd user session, not just mocked. On a spare port throughout, so this box's real bridge on 5354 was never shadowed:
example.com→ real A records)blue.eggs→69.46.46.103, the parking address)Restart=alwaysbrings it back afterSIGKILL, with a new PID--writewrites, reloads, enables and starts;--removedisables, deletes and reloads--removewith nothing installed is safe and idempotent9 new unit tests, deliberately mostly negative — the failure mode is a unit that looks plausible and dies at
203/EXECwith nothing useful in the journal.Full suite: 2707 tests, 0 failures, 334 skipped (the usual
apps/pwaguards).Not included
No release.
dns serviceneeds a version bump and a GitHub release to reach anyone, which is a separate call.🤖 Generated with Claude Code
https://claude.ai/code/session_01ThnQwoieWt8VR6N7gtgnhp