feat(tunnel): add per-subnet DNS proxy - #3279
Merged
Merged
Conversation
Each WireGuard subnet picks a DNS mode — default (the VPS's own resolvers), device (a selected device on the subnet), or custom (up to 3 servers) — and clients receive `DNS = <subnet .1>` so they resolve through the tunnel. A forward-only hickory proxy binds per subnet to the in-tunnel address (10.59.x.1:53), reachable only over WireGuard, and forwards to the configured upstreams. DNS is configured in the add/edit subnet form and surfaced in the subnets table. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Private domains were gated to router gateways because StartTunnel had no DNS. Now that StartTunnel proxies DNS per subnet, a private domain resolves for tunnel clients (their DNS forwards to this server, which answers with the gateway's tunnel address). The backend already accepted any gateway, so drop the UI-only restriction: all gateways now use the public/private domain picker. The "DNS Server Config" guidance is now gateway-aware — for a tunnel gateway it instructs the user to point the StartTunnel subnet's DNS at this server. Removes the now-unused isWireguard flag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dr-bonez
approved these changes
May 29, 2026
dr-bonez
requested changes
May 29, 2026
dr-bonez
left a comment
Member
There was a problem hiding this comment.
We might need handling for if the system doesn't use systemd-resolved (probably just fall back to parsing /etc/resolv.conf)
The "default" DNS mode prefers systemd-resolved's upstreams (/run/systemd/resolve/resolv.conf, the real servers rather than the 127.0.0.53 stub) and now falls back to /etc/resolv.conf (via read_system_conf) whenever that file is absent, unreadable, or yields no usable servers — covering systems that don't run systemd-resolved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dr-bonez
previously approved these changes
Jun 1, 2026
# Conflicts: # web/projects/shared/src/i18n/dictionaries/de.ts # web/projects/shared/src/i18n/dictionaries/en.ts # web/projects/shared/src/i18n/dictionaries/es.ts # web/projects/shared/src/i18n/dictionaries/fr.ts # web/projects/shared/src/i18n/dictionaries/pl.ts
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.
Summary
Two related changes that give StartTunnel DNS and unify domain UX across gateway types.
1. Per-subnet DNS proxy in StartTunnel
Operators pick a DNS mode per WireGuard subnet, and clients resolve DNS through the tunnel.
Modes (per subnet):
/run/systemd/resolve/resolv.conf, with the127.0.0.53stub filtered out to avoid a loop):port)How it works
DNS = <subnet .1>, so clients send DNS into the tunnel.hickoryproxy (one rootForwardAuthorityper subnet) binds to that subnet's in-tunnel address (10.59.x.1:53, UDP + TCP). Binding to the in-tunnel address — never0.0.0.0— keeps it reachable only over WireGuard, never the WAN (no open resolver).wg-quickwhenever subnets change;subnet set-dnsre-syncs only the proxy (no tunnel bounce, since theDNS=line is mode-independent).hickory-serveralready links into the binary; the forwarding path mirrors StartOS'snet/dns.rs.New
DnsConfigmodel onWgSubnetConfigand asubnet set-dnsRPC/CLI command, with regenerated TS bindings, i18n (all 5 locales), and man pages. No migration needed —#[serde(default)]covers existing data. Web: DNS is configured in the add/edit subnet form (overflow action is now "Edit"); the subnets table shows a DNS column; all StartTunnel select dropdowns disable the textfield clear-✕ (tuiTextfieldCleaner), matching StartOS'sform-select.2. Private domains on StartTunnel gateways (StartOS UI)
Private domains were gated to router gateways because StartTunnel had no DNS. Now that StartTunnel proxies DNS (above), a private domain resolves for tunnel clients — their DNS forwards to this server, which answers with the gateway's tunnel address. The backend already accepted any gateway (no type check in
add_private_domain;check_dnsworks over the tunnel interface), so this drops the UI-only restriction:isWireguardflag).Upgrade note
Existing subnets migrate to
default. Already-deployed client.conffiles are unaffected until re-downloaded; once re-downloaded they begin sending DNS into the tunnel (→ the VPS's resolvers). To resolve private domains on a tunnel gateway, set that subnet's DNS to this server in StartTunnel.🤖 Generated with Claude Code