Fast, safe, and payload-transparent routing for DNS and TLS transports.
ΩΨ§Ψ±Ψ³Ϋ Β· Install Β· Usage Β· Commands Β· Docker Β· Upgrade Β· Uninstall Β· Credits
CottenRouter is a lightweight front router that lets multiple DNS-tunnel backends share one server, one IP address, and public port 53. It reads the first DNS question, selects the longest matching configured suffix, and forwards the packet to the correct private backend.
It can also share public DoT and HTTPS ports by reading TLS SNI and passing each encrypted stream through unchanged. CottenRouter does not terminate TLS, add DNS labels, or add protocol bytes, so it does not reduce tunnel MTU.
Key features:
- Concurrent routing for several DNS-tunnel projects on one public endpoint
- UDP DNS, DNS-over-TCP, DoT, DoH, NaiveProxy, and StunTLS passthrough
- Guided terminal UI for installation, configuration, monitoring, and removal
- Transactional host installation with snapshots, health checks, and rollback
- Fixed queues, rate limits, timeouts, connection caps, and resource controls
- Loopback-only administration API and a dashboard refreshed every two seconds
- Rootless, read-only, shell-free Docker image
- Checksum-verified
linux/amd64andlinux/arm64release binaries
flowchart LR
C[DNS / TLS clients] -->|UDP/TCP 53, DoT, HTTPS| R[CottenRouter]
R -->|Longest DNS suffix| D1[CottenDNS :5301]
R -->|Longest DNS suffix| D2[MasterDnsVPN :5302]
R -->|Longest DNS suffix| D3[StormDNS :5303]
R -->|Longest DNS suffix| D4[thefeed :5304]
R -->|DNS route or TLS SNI| D5[SlipGate services]
R -.->|Loopback only| A[Admin API :9088]
| Host installation | Docker | |
|---|---|---|
| Routing core | β | β |
| Guided backend installers | β | β |
| Interactive control deck | β | β |
| systemd and firewall integration | β | β |
| Rootless runtime | β | β |
| Best for | A fresh server managed end to end | Existing container infrastructure |
For a host installation you need:
- Linux with
systemd 245+ rootorsudoaccess- A public IP and at least one unique domain or subdomain for each backend
- Ubuntu 20.04+, Debian 11+, or RHEL/Rocky/AlmaLinux 9+ is recommended
amd64orarm64for a prebuilt binary; other architectures build from source
WSL is supported for development and testing only. Use a native Linux server for production.
curl -fsSL https://raw.githubusercontent.com/TaJirax/CottenRouter/main/scripts/install.sh | sudo bash
sudo cottenrouter tuiThe installer downloads the latest official release, verifies its checksum, checks required tools, systemd, disk space, and listeners, and waits for a successful health check. A failed installation restores the previous state. Running the command again performs an in-place upgrade.
Install a specific release:
curl -fsSL https://raw.githubusercontent.com/TaJirax/CottenRouter/main/scripts/install.sh \
| sudo bash -s -- --version=v1.2.10Install the current development branch:
curl -fsSL https://raw.githubusercontent.com/TaJirax/CottenRouter/main/scripts/install.sh \
| sudo bash -s -- --channel=edgeBuild from source during installation:
curl -fsSL https://raw.githubusercontent.com/TaJirax/CottenRouter/main/scripts/install.sh \
| sudo bash -s -- --build-from-source| Installer option | Purpose |
|---|---|
--version=vX.Y.Z |
Install an exact tagged release |
--channel=stable |
Install the latest release; this is the default |
--channel=edge |
Build the latest default-branch commit for testing |
--build-from-source |
Compile locally instead of using a release binary |
--no-swap |
Skip the installer-owned emergency swap safeguard |
sudo cottenrouter tui| Key | Action |
|---|---|
Space |
Select or deselect a project |
i |
Run guided installation for selected projects |
Enter / e |
Edit domains, private ports, TCP, DoT, and DoH |
a |
Open the complete native project configuration |
s |
Restart a project |
u |
Detach a project while preserving its files |
x |
Permanently remove a project after confirmation |
v |
Show credential paths and public values |
V |
Reveal secrets after explicit confirmation |
Give every backend a unique delegated domain, for example cotten.example.com, master.example.com, storm.example.com, and feed.example.com. Exact duplicate suffixes are rejected. Nested suffixes are supported and the longest match wins.
sudo systemctl status cottenrouter
sudo journalctl -u cottenrouter -f
sudo cottenrouter healthz -config /etc/cottenrouter/config.json
curl -fsS http://127.0.0.1:9088/v1/statusValidate or run a configuration manually:
cottenrouter check -config cottenrouter.json
cottenrouter serve -config cottenrouter.jsonStart with cottenrouter.example.json, or use cottenrouter.docker.json for containers. Unknown configuration fields are rejected.
Import an existing SlipGate configuration:
cottenrouter slipgate-import \
--input /etc/slipgate/config.json \
--output cottenrouter.jsonInspect current upstream projects and installers:
cottenrouter catalog
cottenrouter catalog --offlineThe online catalog resolves and verifies each project's current default branch. The offline output is bundled fallback metadata and is not recommended for installation.
cottenrouter tui Install, manage, and monitor projects
cottenrouter serve Run the router with a configuration
cottenrouter check Validate a configuration without serving
cottenrouter healthz Probe router health
cottenrouter install Install a backend from the CLI
cottenrouter configure Edit stable backend settings
cottenrouter advanced Edit advanced native backend settings
cottenrouter service Start, stop, or restart a project
cottenrouter remove Detach or purge a project
cottenrouter uninstall Alias for the project removal operation
cottenrouter keys Display project credentials
cottenrouter catalog List current projects and installers
cottenrouter slipgate-import Convert an existing SlipGate configuration
cottenrouter version Print the installed version
Use cottenrouter <command> --help for command-specific options.
Manage a service directly:
sudo cottenrouter service --project=cottendns --action=restart
sudo cottenrouter service --project=stormdns --action=stop
sudo cottenrouter service --project=stormdns --action=startDetach one backend while preserving its files:
sudo cottenrouter remove --project=cottendnsPermanently remove that backend's managed data:
sudo cottenrouter remove --project=cottendns --purge --confirm=cottendnsThe container runs the routing core only. You remain responsible for the lifecycle of backend containers.
curl -fsSLO https://raw.githubusercontent.com/TaJirax/CottenRouter/main/docker-compose.yml
curl -fsSLO https://raw.githubusercontent.com/TaJirax/CottenRouter/main/cottenrouter.docker.json
# Replace the example domain and backend in cottenrouter.docker.json
docker compose up -dCheck health:
docker compose exec cottenrouter \
/usr/local/bin/cottenrouter healthz \
-config /etc/cottenrouter/config.jsonUpdate or remove the container:
docker compose pull
docker compose up -d
docker compose downThe official ghcr.io/tajirax/cottenrouter image supports linux/amd64 and linux/arm64. It listens on unprivileged port 5353 inside the container while Docker publishes host port 53. It runs as UID 65532, drops all capabilities, uses a read-only root filesystem, and includes no shell. See the Docker guide.
The installer upgrades CottenRouter in place. It snapshots the active configuration, replaces the binary, validates the configuration, restarts the service, and waits for the health probe. If any step fails, it restores the previous installation automatically.
flowchart LR
A[Current installation] --> B[Snapshot config and service state]
B --> C[Download and verify release]
C --> D[Validate and restart]
D -->|Health check passes| E[Upgrade complete]
D -->|Health check fails| F[Automatic rollback]
curl -fsSL https://raw.githubusercontent.com/TaJirax/CottenRouter/main/scripts/install.sh | sudo bashPinning a version is useful for reproducible deployments or returning to a known release:
curl -fsSL https://raw.githubusercontent.com/TaJirax/CottenRouter/main/scripts/install.sh \
| sudo bash -s -- --version=v1.2.10Available versions are listed on the Releases page.
Use this only when you intentionally want the latest default-branch commit:
curl -fsSL https://raw.githubusercontent.com/TaJirax/CottenRouter/main/scripts/install.sh \
| sudo bash -s -- --channel=edgedocker compose pull
docker compose up -dThe configuration is a read-only bind mount, so replacing the container does not replace your local config file.
cottenrouter version
sudo systemctl --no-pager --full status cottenrouter
sudo cottenrouter healthz -config /etc/cottenrouter/config.jsonProduction tip: use the stable channel or an exact version. Take a server snapshot before upgrading upstream backend projects, because their native installers run as root and are maintained independently.
Safely remove CottenRouter while preserving configuration, upstream projects, panels, pre-existing firewall rules, and swap:
sudo cottenrouter-uninstallAlso delete the router configuration:
sudo cottenrouter-uninstall --purge --confirm CottenRouterDelete CottenRouter, every managed backend, and their managed data:
sudo cottenrouter-uninstall \
--purge \
--purge-backends \
--confirm CottenRouterRemove only swap created and marked as owned by the installer:
sudo cottenrouter-uninstall --remove-swap --confirm CottenRouterPurge operations cannot be undone. CottenRouter removes only firewall rules, accounts, and swap carrying its ownership markers; it does not remove pre-existing state.
- Parse the first DNS question and drop malformed packets.
- Select the longest configured domain suffix.
- Allocate a transaction ID on a connected backend socket.
- Forward the packet unchanged apart from that temporary ID.
- Accept a reply only when its question name, type, and class match exactly.
- Restore the client's original ID and return the reply.
IDs are never reused in one socket generation. After all 65,536 IDs have been consumed, CottenRouter rotates to a new source port so a late response cannot enter the new generation.
Remote backends are rejected by default, both UDP and TCP messages are capped at 16 KiB, and the admin API must remain on loopback. Transaction-ID and question matching is not cryptographic authentication; configured backends are trusted. Host backend installers run as root, so snapshot the server before running an upstream release you have not reviewed.
Read more in Security, Installer and control deck, and Backend integration.
git clone https://github.com/TaJirax/CottenRouter.git
cd CottenRouter
go build -o cottenrouter ./cmd/cottenrouter
go test ./...
go test -race ./...
go vet ./...
gofmt -w cmd internalCI also checks five-backend isolation under load, full 16 KiB packets, throughput, concurrent DoT/DoH and NaiveProxy/StunTLS routing, formatting, and the rootless Docker image.
Use Issues for bugs and feature requests, and Pull Requests for code contributions.
| Guide | Contents |
|---|---|
| Docker | Rootless container layout, networking, images, and updates |
| Installer and control deck | TUI controls, ports, panels, safeguards, and removal |
| Backend integration | Domains, listeners, feature boundaries, and project notes |
| Security | Flood controls, resource limits, systemd hardening, and swap |
| Configuration example | Complete annotated-style configuration starting point |
CottenRouter is designed to interoperate with these independent open-source projects. We sincerely thank their authors and contributors:
| Project | Role in the ecosystem | Link |
|---|---|---|
| CottenDNS | DNS tunnel with UDP/TCP, DoT, DoH, ARQ, and MTU discovery | Repository |
| MasterDnsVPN | DNS tunneling backend | Repository |
| StormDNS | DNS tunneling backend | Repository |
| thefeed | Feed, chat, media, and relay over DNS | Repository |
| SlipGate | DNS transports, SlipNet, NaiveProxy, and StunTLS | Repository |
The terminal UI is built with Bubble Tea, Bubbles, and Lip Gloss from Charm. The secure Docker image is based on Distroless. Complete dependency lists are available in go.mod and go.sum.
No upstream source tree or binary is vendored in this repository. Every upstream project retains its own copyright and license, and its installer is fetched directly from its repository only when requested by the operator. See NOTICE.md.
CottenRouter is released under the MIT License. Upstream integrations remain subject to their respective project licenses.
Built for cleaner, safer, and more manageable DNS-tunnel deployments.