ControlD DNS-over-HTTPS with per-device visibility for Alta Route 10

Hey folks,

I’ve been running ControlD on my Route 10 for a while and finally cleaned up my setup into something shareable. If you want encrypted DNS with actual device names
showing up in your ControlD dashboard instead of just the router IP, this does that.

It handles reboots and firmware updates without blowing away your config, keeps itself updated weekly, and if you ever want to remove it, uninstall puts everything back
the way it was.

Running on firmware 1.4z. Happy to help if anyone runs into issues, assuming time permits with my busy schedule.

Have you experienced any issues after installing and setting up Controld DOH?

None tbh…everything has been working fine!

Getting some error after installing the script. Did I install it properly?.


            |β€Ύ      β€Ύ|     /\   |   β€Ύβ€Ύ|β€Ύβ€Ύ  /\
            |   /\   |    /  \  |     |   /  \
            |  /  \  |   /   _\ |___  |  /_   \
            | /    \ |
            |_      _|         L  A  B  S

Shell access is provided solely for debugging assistance. Please
be aware that Alta Labs is not responsible for commands that may
damage the device, void the warranty, or extend functionality
beyond Alta Labs’ intended scope.

    Remember, with great power comes great responsibility.

root@ router:~# wget -O /tmp/setup.sh
Downloading ’ master/setup.sh’
Connecting to 2xx.x.x.x:443
Writing to β€˜/tmp/setup.sh’
/tmp/setup.sh 100% || 31348 0:00:00 ETA
Download completed (31348 bytes)
root@ router:~# sh /tmp/setup.sh
[!!] lib.sh not found in /tmp or /cfg/
root@ router:~# cd /tmp/
root@ router:/tmp# dir
-ash: dir: not found
root@ router:/tmp# cd ..
root@ router:/# ls
a cfg etc lib mnt proc root sys usr www
bin dev init lib64 overlay rom sbin tmp var
root@ router:/# cd tmp
root@ router:/tmp# ls
ban_runtime.json hosts localtime resolv.conf.d spool sysinfo
board.json lib lock run state tmp
dnsmasq.d lldpd.conf log setup.sh stats
etc lldpd.d resolv.conf shm stats.sql
root@ router:/tmp# se
sed seq set setsid setup
root@ router:/tmp# setup.sh
-ash: setup.sh: not found
root@ router:/tmp# ./setup.sh
-ash: ./setup.sh: Permission denied
root@ router:/tmp# sh /tmp/setup.sh
[!!] lib.sh not found in /tmp or /cfg/
root@ router:/tmp# ^C
root@ router:/tmp# wget -O lib.sh
Downloading ’
Connecting to 2xx.xx.xx.xx:443
Writing to β€˜lib.sh’
lib.sh 100% |
| 6184 0:00:00 ETA
Download completed (6184 bytes)
root@ router:/tmp# ls
ban_runtime.json hosts lldpd.d resolv.conf shm stats.sql
board.json lib localtime resolv.conf.d spool sysinfo
dnsmasq.d lib.sh lock run state tmp
etc lldpd.conf log setup.sh stats
root@ router:/tmp# sh /tmp/setup.sh

╔══════════════════════════════════════════════════════════╗
β•‘ Alta Labs Route 10 + ControlD DNS β•‘
β•‘ Encrypted DNS with per-device visibility β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

Step 1: ControlD Configuration
[–] Get your resolver ID from: https://controld.com β†’ Dashboard β†’ Endpoint Resolvers
Resolver ID: xxxxxxxxxxxx
Bootstrap IP [x.x.x.x]:

════════════════════════════════════════════════════════════
Choose Your DNS Protocol
════════════════════════════════════════════════════════════

  1. DoH3 β€” DNS-over-HTTPS/3 (HTTP/3 + QUIC) [recommended]
    Port 443 | Looks like normal HTTPS traffic
    Fastest for most ISPs. Hard to block or identify as DNS.

  2. DoQ β€” DNS-over-QUIC
    Port 853 | Purpose-built DNS over QUIC
    Lowest protocol overhead. ISPs can see it’s DNS traffic.

  3. DoH β€” DNS-over-HTTPS/2 (HTTP/2 + TCP)
    Port 443 | Most widely compatible
    No QUIC β€” higher latency but works everywhere.

  4. Benchmark β€” test all three and pick the fastest
    Runs 10 queries per protocol, takes about 30 seconds.

All protocols encrypt your DNS. The difference is speed and stealth.
The watchdog will auto-fallback (DoQ β†’ DoH3 β†’ DoH) if one fails.

Choice [1]: 1

Step 2: Installing ctrld v1.5.0…
’
Connecting to 1xx.xxx.xx.x:443
Redirected to /github-production-release-asset/573642098/df6d2c5b-7122-4041-9ad6-274b27b3e0d0?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-06-06T01%3A35%3A08Z&rscd=attachment%3B+filename%3Dctrld_1.5.0_linux_arm64.tar.gz&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2026-06-06T00%3A34%3A51Z&ske=2026-06-06T01%3A35%3A08Z&sks=b&skv=2018-11-09&sig=9KUeJ08W29RavGfb24CO3HdnLWTceQn1cpuTEUKLGPo%3D&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc4MDcwNzMwOCwibmJmIjoxNzgwNzA3MDA4LCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.C9bk1ncU3EuQoycofT6tiiv8bn6E2vtjrMpwgaoIMJ4&response-content-disposition=attachment%3B%20filename%3Dctrld_1.5.0_linux_arm64.tar.gz&response-content-type=application%2Foctet-stream on release-assets.githubusercontent.com
Writing to β€˜/tmp/ctrld.tar.gz’
/tmp/ctrld.tar.gz 100% |*******************************| 6428k 0:00:00 ETA
Download completed (6583025 bytes)
[OK] ctrld binary installed to /cfg/ctrld

Step 3: Writing configuration files…
[OK] /cfg/controld.env written
[OK] /cfg/ctrld.toml written (DoH3 (HTTP/3))
[OK] /cfg/post-cfg.sh written (self-healing)

Advanced DNS Policy (optional)
[–] Route specific devices or networks to different ControlD profiles.
[–] Requires multiple resolver IDs from your ControlD dashboard.

Configure split DNS policies? [y/N]: N
[OK] Watchdog installed (5-min health check + protocol fallback)
[OK] /cfg/controld-update.sh written
[OK] Weekly auto-update cron installed
[OK] lib.sh copied to /cfg/ for runtime use

Step 4: Applying configuration…
Starting https-dns-proxy 2022-10-15-10 βœ“βœ“βœ“

Step 5: Verification

[OK] ctrld is running (PID 11585)
[OK] ctrld DNS responding on port 5354
[OK] iptables redirect rules active (4 rules)
[OK] System DNS working

╔══════════════════════════════════════════════════════════╗
β•‘ Setup Complete! β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

Your DNS is now routed through ControlD via DoH3 (HTTP/3).

Check your dashboard:
Individual devices should appear within a few minutes.

Installed on router:
/cfg/controld.env Recovery config (self-healing)
/cfg/ctrld DNS proxy binary
/cfg/ctrld.toml DNS proxy configuration
/cfg/post-cfg.sh Self-healing boot script
/cfg/controld-update.sh Weekly auto-update
/cfg/watchdog.sh 5-min health check + protocol fallback
/cfg/lib.sh Shared function library

To check: sh status.sh
To benchmark: sh benchmark.sh
To uninstall: sh uninstall.sh

root@ router:/tmp# sh status.sh
sh: can’t open β€˜status.sh’: No such file or directory
root@ router:/tmp# sh /tmp/stat
state/ stats.sql stats/
root@ router:/tmp# cd /cfg/
root@ router:/cfg# ls
applied.txt controld-update.sh dhcp.leases lib.sh rcapi.txt uplink.json
certs controld.env domain.txt lost+found rsa.db wan.json
config.json ctrld hash.txt mid.txt siteid.txt watchdog.sh
config.json.old ctrld.toml hash.txt.old post-cfg.sh stats.sql
root@ router:/cfg# sh status.sh
sh: can’t open β€˜status.sh’: No such file or directory
root@ router:/cfg# status.sh
-ash: status.sh: not found
root@ router:/cfg# sh watchdog.sh --dry-run
root@ router:/cfg# cd ctrld
-ash: cd: can’t cd to ctrld: Not a directory
root@ router:/cfg# pidof ctrld
11585
root@ router:/cfg# iptables -t nat -L PREROUTING -n | grep 5354
REDIRECT udp – 0.0.0.0/0 0.0.0.0/0 udp dpt:53 redir ports 5354
REDIRECT tcp – 0.0.0.0/0 0.0.0.0/0 tcp dpt:53 redir ports 5354
REDIRECT udp – 0.0.0.0/0 0.0.0.0/0 udp dpt:53 redir ports 5354
REDIRECT tcp – 0.0.0.0/0 0.0.0.0/0 tcp dpt:53 redir ports 5354
root@ router:/cfg# /cfg/ctrld --help
__ .__ .___
/ |_*| | | /
/ \ _ __ \ | / __ |
\ _| | | | / |/ /*/ |
_ >| || |_
/_** |
/ dns forwarding proxy /

Usage:
ctrld [command]

Available Commands:
run Run the DNS proxy server
start Quick start service and configure DNS on interface
stop Quick stop service and remove DNS from interface
restart Restart the ctrld service
reload Reload the ctrld service
status Show status of the ctrld service
uninstall Stop and uninstall the ctrld service
service Manage ctrld service
clients Manage clients
upgrade Upgrading ctrld to latest version
log Manage runtime debug logs

Flags:
-h, --help help for ctrld
-s, --silent do not write any log output
-v, --verbose count verbose log output, β€œ-v” basic logging, β€œ-vv” debug logging
–version version for ctrld

Use β€œctrld [command] --help” for more information about a command.
root@ router:/cfg# /cfg/ctrld status
Jun 5 19:01:25.000 ERR the service is not installed
root@ router:/cfg# /cfg/ctrld start
Jun 5 19:04:15.000 NTC Reading config: /cfg/config.json
Jun 5 19:04:15.626 NTC Starting service
Jun 5 19:04:16.682 ERR failed to re-read configuration file: /cfg/config.json error=β€œWhile parsing config: invalid character β€˜l’ looking for beginning of value”
Jun 5 19:04:16.682 ??? ================================
Jun 5 19:04:16.682 ??? An error occurred while performing test query: While parsing config: invalid character β€˜l’ looking for beginning of value
Jun 5 19:04:16.682 ??? ================================
Jun 5 19:04:21.726 NTC Service uninstalled
root@ router:/cfg# /cfg/ctrld run
Jun 5 19:04:50.054 FTL listener.0 failed to listen: listen udp 0.0.0.0:5354: bind: address already in use
listen tcp 0.0.0.0:5354: bind: address already in use
root@ router:/cfg# /cfg/ctrld status
Jun 5 19:05:03.000 ERR the service is not installed
root@ router:/cfg#

Hmm, have you bound port 5354 to something else? I can add a modifier to enable selecting a different port and check port avalibility vs making assumptions. Can look at this tomorrow.

I believe the script is working , but gives an error when I try to use some of the available commands to check it it’s running or get status. Would be a good idea to check if port is in use during initial install.