A modular multi-tunnel orchestrator and manager for VPN connection pairs running inside isolated network namespaces (netns).
Hermit is a modular multi-tunnel orchestrator and manager for VPN connection pairs running inside isolated network namespaces (netns). It decouples configurations into reusable Inbound Profiles (e.g., SOCKS5/HTTP Proxy, Tailscale) and Outbound Profiles (e.g., WireGuard, Local), allowing you to easily pair, share configurations, and manage multiple tunnels side-by-side.
The application provides a real-time web dashboard to monitor bandwidth usage, manage connection states, create and share profiles, and configure global settings.
Important
This project requires elevated system privileges (privileged: true) and advanced networking tools such as nftables, iproute2, wireguard-tools, and tailscale. To avoid impacting your host machine's network configuration and to ensure a consistent development environment, it is highly recommended to develop and run this project completely within Docker.
- Multi-Tunnel Orchestration: Pair inbound (SOCKS5/HTTP Proxy, Tailscale) with outbound (WireGuard, Local) profiles to run multiple independent tunnels side-by-side.
- Isolated Network Namespaces: Run each connection pair in its own Linux network namespace (
netns) with dynamic source-policy routing to prevent routing conflicts. - Decoupled DNS Control Plane: A DNS filtering system with bloom filters, caching, dynamic blocklist loading (AdGuard, GoodbyeAds, adult content), and custom DNS routing rules (Block, Bypass, Redirect, Forward Proxy, Forward DNS).
- DNS Endpoints (DoH / VPN Nodes): Expose secure DNS-over-HTTPS (DoH) endpoints with auto-generated Apple Configuration Profiles (
.mobileconfig) or dedicated Tailscale DNS Nodes. - Tailscale DNS Override: Automatically registers local DNS Nodes as tailnet-wide nameservers.
- EDNS Client Subnet (ECS): Forward client subnet masks to public upstreams (e.g. Google DNS) to optimize CDN routing, with support for LAN privacy filtering and custom fallback IPs.
- VPN Providers Integration: Direct authentication with NordVPN (using Access Tokens) and Mullvad to fetch recommendations, network speed profiles, and public keys.
- Real-Time Web Dashboard: A Phoenix LiveView dashboard to monitor bandwidth, manage tunnel states, view query logs, and edit configurations on the fly.
Hermit creates VPN tunnels by combining an Inbound Profile with an Outbound Profile inside an isolated Linux network namespace. The architecture is split into two planes:
- Traffic Plane: Carries regular network data (HTTP, TCP/UDP) through the tunnel.
- DNS Control Plane: Handles name resolution, caching, and ad/tracker filtering independently from the tunnels.
flowchart TD
Client[Client / Host Application] -->|1. Request In| Inbound[Inbound Profile SOCKS5/HTTP or Tailscale]
subgraph NetNS [VPN Pair Namespace]
Inbound -->|2. Internal Forwarding| Outbound[Outbound Profile WireGuard / Local]
end
Outbound -->|3. Tunnel / Host Out| Internet[VPN / External Internet]
- Inbound Profiles define how traffic enters the namespace:
- SOCKS5/HTTP Proxy: Exposes SOCKS5 and HTTP proxy endpoints for clients to connect to.
- Tailscale: Joins the namespace to your Tailscale network (tailnet) as a node, allowing any tailnet device to route traffic through it.
- Outbound Profiles define how traffic exits the namespace:
- WireGuard: All outbound traffic is routed through a WireGuard tunnel.
- Local: Bypasses VPN tunnels and routes traffic directly through the host network interface (useful for testing, local proxies, or selective routing).
- VPN Pairs: The orchestrator combines one Inbound + one Outbound into a running instance, handling resource allocation and conflict prevention automatically.
The DNS plane is fully decoupled from VPN Pairs and Inbound Networks. Hermit supports DNS Endpoints and DNS Profiles to separate network connection endpoints from routing/filtering logic:
- DNS Profiles: Pre-configure multiple DNS Profiles, each with its own upstream DNS servers (UDP/DoH), custom routing rules (block/bypass/redirect), and toggleable blocklists.
- DNS Endpoints (DoH / VPN Nodes): Expose access points for your devices. You can create multiple Endpoints:
- DoH Only (Default / Lightweight): Runs entirely in-memory using the Phoenix HTTP/HTTPS web port, using 0% extra CPU/RAM. Provides a secure HTTPS DoH URL (
/dns-query/:token) and automatically generates signed Apple configuration profiles (.mobileconfig). - Tailscale Integration (Optional): Link your DNS Endpoint to any Tailscale Inbound Profile. When active, Hermit boots a dedicated DNS Node (
tailscaledinside a network namespacehermit_dns_endpoint_#{id}) on your tailnet, allowing client devices to resolve DNS over UDP/TCP 53.
- DoH Only (Default / Lightweight): Runs entirely in-memory using the Phoenix HTTP/HTTPS web port, using 0% extra CPU/RAM. Provides a secure HTTPS DoH URL (
- Automated Global DNS Configuration: When Tailscale DNS Override is enabled on a Tailscale Endpoint, Hermit registers the local DNS Node IP as the global nameserver for your entire tailnet. All devices on your tailnet will use this node automatically without manual client configuration.
flowchart TD
subgraph Clients [Client Devices]
AppleDev[iOS / macOS Device]
TailnetDev[Tailnet Device]
end
subgraph Endpoints [DNS Endpoints]
DoHEndpoint[DoH Endpoint /dns-query/:token]
TSEndpoint[Tailscale Endpoint Node IP]
end
subgraph Profile [Active DNS Profile]
Rules{Rules & Blocklists}
Upstream[Upstream DNS / DoH]
end
%% Queries to Endpoints
AppleDev -->|HTTPS Query| DoHEndpoint
TailnetDev -->|UDP/TCP Port 53| TSEndpoint
%% Endpoints routing to active profile
DoHEndpoint -->|Internal Forward| Rules
TSEndpoint -->|nftables Redirect| Rules
%% Profile Resolution
Rules -->|Allow & Cache Miss| Upstream
Rules -->|Block / Redirect / Cache Hit| Respond[DNS Response]
Upstream --> Respond
When a DNS query arrives, the server evaluates it through a fast path before reaching the network:
- Custom Rules: User-defined routing rules are matched first. Actions include:
- Block: Instantly block matching domains (NXDOMAIN).
- Bypass: Bypass ad/tracker blocklist filters.
- Redirect: Resolve domain to a specific target IP address (A record).
- Forward Proxy: Proxy the DNS query through the proxy tunnel of a selected VPN pair.
- Forward DNS: Forward the DNS query to a specific DNS Server (UDP/DoH), optionally routed through the SOCKS5/HTTP proxy of a selected VPN pair.
- Blocklists: Checked against built-in ad/tracker blocklists (AdGuard, GoodbyeAds, adult content). Matched domains are blocked instantly.
- Cache: Previously resolved queries are returned from cache.
If none of the above match (cache miss), the query is forwarded to configured upstream DNS servers (UDP or DoH).
In addition to Tailscale integration, Hermit includes a built-in DNS-over-HTTPS (DoH) server. This allows any device (even those not on your Tailnet) to use your secure, filtered DNS configurations.
- Secure DoH Endpoint: Each DNS Endpoint is assigned a unique token, exposing a secure DoH resolver endpoint at
https://<your-host>/dns-query/<doh_token>. - Apple Configuration Profiles (
.mobileconfig): Hermit can dynamically generate Apple configuration profiles for iOS and macOS. Users can download these profiles from the dashboard to configure system-wide secure DNS with zero manual setup. All profile descriptions match your custom Endpoint names.
Hermit supports EDNS Client Subnet (ECS, RFC 7871) to optimize CDN routing (e.g. YouTube, Netflix, Facebook) by forwarding the client's subnet mask (IPv4 /24 or IPv6 /48) to public upstream DNS servers.
- Smart Client Subnet Forwarding: For public client IPs (e.g. via DoH), Hermit forwards the subnet directly. For private client IPs (e.g. loopback, LAN, or Tailscale CGNAT
100.64.0.0/10), Hermit skips ECS injection automatically to protect client privacy. - ECS Fallback IP: You can configure a public IP address as the fallback. When a request originates from a private Tailscale IP, Hermit will inject the fallback IP subnet instead, ensuring you always resolve CDN traffic to your target country.
To simplify creating Outbound Profiles, Hermit provides a dedicated Providers page (/providers) that integrates with popular commercial VPN providers:
- NordVPN: Authenticate using a NordVPN Access Token to retrieve your private key, list recommended countries, and import recommended WireGuard server configurations.
- Mullvad: Fetch active Mullvad WireGuard servers with country/city metadata, network speeds, and public keys.
- Custom Imports: Easily upload or paste custom WireGuard configuration files to generate new Outbound Profiles in one click.
- Docker and Docker Compose
Note
There is no need to install Elixir, Erlang, or SQLite on your host machine as all runtime dependencies are packaged and configured automatically inside the container.
Hermit can be run in two different modes:
We recommend using our automated setup script. This script automatically prepares the ~/.hermit/storage directory, generates a secure random env file at ~/.hermit/env, checks if your host has Sysbox installed to run in a non-privileged configuration, and guides you through security settings.
curl -fsSL https://raw.githubusercontent.com/quaywin/hermit/main/install.sh | bashAlternatively, you can perform a manual installation without cloning:
# Create storage directory in your home folder to prevent root ownership issues
mkdir -p ~/.hermit/storage
# Download docker-compose configuration
curl -L https://raw.githubusercontent.com/quaywin/hermit/main/docker-compose.yml -o docker-compose.yml
# Start Hermit
docker compose up -dIf you have already cloned the repository, run docker compose up -d --build instead.
Once started, access the dashboard at http://localhost:3000.
Mounts the source code directory directly, enabling incremental compilation and hot-code reloading. You do not need to rebuild the Docker image when editing files.
docker compose -f docker-compose.dev.yml up -dTip
Modifying source code on the host machine instantly triggers incremental compilation in less than 0.5 seconds. Subsequent starts are nearly instantaneous because dependency compilation and build artifacts are cached.
Hermit can be deployed seamlessly to Fly.io MicroVMs with persistent storage and 512MB Swap safety buffer ($0/month under free credit allowance). See the detailed Fly.io Deployment Guide for full setup instructions.
# Quick Launch on Fly.io
fly launch --no-deploy
fly volumes create hermit_data --size 1 --region sin
fly secrets set PHX_HOST="your-app.fly.dev" SECRET_KEY_BASE=$(openssl rand -base64 48)
fly scale memory 512
fly deployBy default, the dashboard runs on port 3000. To use a different port, set HERMIT_PORT:
# Production
HERMIT_PORT=8080 docker compose up -d
# Development
HERMIT_PORT=8080 docker compose -f docker-compose.dev.yml up -dBy default, the web dashboard has no authentication enabled. If you are deploying Hermit on a public VPS or a shared network, you can enforce Basic Authentication by setting the following environment variables in your environment configuration file (~/.hermit/env):
HERMIT_BASIC_AUTH_USER=admin
HERMIT_BASIC_AUTH_PASS=your_secure_passwordWarning
If these environment variables are unset or commented out, authentication will be bypassed and the dashboard will be open to anyone.
By default, Hermit binds port 41642/udp on the host machine (mapped to 41641/udp inside the container). This avoids conflicts with any Tailscale daemon running directly on your host machine, which typically uses port 41641/udp.
If you are deploying Hermit on a VPS:
- Recommended: Open port
41642/udpin your VPS firewall to allow Tailscale to establish direct, peer-to-peer (P2P) connections, ensuring optimal speed and the lowest latency.
If you need to change this port to a different one (e.g., 41643):
- Open
docker-compose.yml(and/ordocker-compose.dev.yml). - Change the host-side port mapping:
ports: - "${HERMIT_PORT:-3000}:3000" - "41643:41641/udp"
- Open the corresponding port on your firewall instead.
Hermit automatically implements the high-performance network tuning recommended by Tailscale:
- UDP Buffer & Queue Scaling: Hermit automatically configures network sysctls (
rmem_max,wmem_max,udp_mem, andnetdev_max_backlog) at startup. - Namespace UDP GRO Offloading: Hermit automatically runs
ethtoolto enablerx-udp-gro-forwardingand disablerx-gro-liston all virtual interfaces inside the isolated network namespaces.
Host-level Optimization (Manual): Because Hermit runs in an isolated container (especially when using Sysbox), it cannot modify the host's physical network hardware. To get the maximum throughput:
- Ensure your host system runs Linux Kernel 6.2 or later.
- Manually enable UDP GRO on your host's primary physical network interface (this single-line command auto-detects the interface and works on all shells including Bash, Zsh, and Fish):
sudo sh -c 'ethtool -K $(ip -o route get 8.8.8.8 | cut -f 5 -d " ") rx-udp-gro-forwarding on rx-gro-list off'
Running real-world VPN pairs requires operating-system level root privileges to create network namespaces (netns), configure virtual network interfaces, and route traffic via nftables.
- The
privileged: truesetting indocker-compose.ymlgrants the container permissions to perform these system-level operations in an isolated manner. - Running directly on your host machine risks messing up local network interfaces and requires granting global
sudoprivileges to external scripts, which is unsafe for your development environment.
By default, Docker containers require privileged: true to perform network namespace and mounting tasks. If you want to run Hermit in a production environment with maximum security, you can use the Sysbox Container Runtime on Linux to run without privileged access.
With Sysbox installed on your host system:
- Sysbox intercepts mount and network calls safely using Linux User Namespaces.
- The container runs with strict VM-like isolation while still permitting Hermit to configure nested namespaces and routes.
To run with Sysbox, use the dedicated configuration:
docker compose -f docker-compose.sysbox.yml up -d(Our install.sh script automatically detects Sysbox and configures it if available).
If container creation fails with OCI runtime create failed: namespace {"time" ""} does not exist, this is due to a compatibility issue between Docker 29.5+ (which enables time namespaces by default) and current Sysbox releases.
To resolve this, disable time-namespaces in your host's Docker daemon configuration:
- Edit
/etc/docker/daemon.jsonand add:{ "features": { "time-namespaces": false } } - Restart the Docker service:
sudo systemctl restart docker
We aim to continuously improve Hermit. Planned future enhancements include:
- Expanded VPN Provider Integration: Add support for more commercial VPN providers (such as Surfshark, ProtonVPN, and ExpressVPN) to fetch keys, server recommendations, and network speed profiles automatically.
- Alternative Inbound Mesh Networks: Integrate additional Tailscale-like overlay networks (e.g., ZeroTier, Netmaker, Headscale, or Nebula) as Inbound Profiles, allowing client devices on those networks to route traffic through your outbound tunnels.
If you are looking for other tools to manage VPNs or WireGuard tunnels, here is how Hermit compares to existing popular open-source alternatives:
| Project | Primary Focus | UI Type | WireGuard Management | Tailscale Integration | Network Namespace Isolation |
|---|---|---|---|---|---|
| Hermit | Multi-tunnel orchestrator | Web Dashboard | Yes | Yes | Yes (isolated netns) |
| wireproxy | Userspace WireGuard proxy | CLI / Config | Yes | No | No (userspace proxy) |
| Gluetun | Docker-focused VPN client | CLI / Config | Yes | No | No (uses Docker network links) |
The development of Hermit was shaped by a few core ideas and existing tools:
- Tailscale Exit Nodes + Mullvad VPN: The initial spark came from wanting a clean way to combine the ease of Tailscale’s mesh networking with the privacy of Mullvad VPN. The goal was to dynamically route traffic from Tailscale devices through isolated Mullvad WireGuard tunnels.
- Self-hosted DNS inside Tailnet: Instead of relying on external DNS services, the author set out to run a dedicated DNS Resolver node directly inside the Tailnet. The early Erlang/Elixir DNS implementation was built with reference to the
dns_erlangspecification and Kip Cole's dns library. - Evolution into a Control D Alternative: Once a basic DNS server was operational inside the Tailnet, we saw the potential of dynamic, multi-tenant DNS routing. Inspired by the architecture of commercial services like Control D, Hermit evolved to support multiple isolated DNS Endpoints (each with dedicated DoH tokens or Tailscale Node IPs) mapped to custom DNS Profiles (blocking, bypassing, or redirecting domains through specific VPN Pairs).
Hermit is built on top of and inspired by several amazing open-source projects:
- WireGuard - For the extremely fast, modern, and secure VPN protocol.
- Tailscale - For making private networking easy and secure.
- AdGuard Home & GoodbyeAds - For providing the blocklists that power our DNS control plane.
- dns - The Elixir DNS library that helped shape our query parser and packet builder.
- Elixir & Phoenix LiveView - For enabling a real-time system dashboard with minimal overhead.
