### Start and probe the setup
Source: https://github.com/razvandimescu/numa/blob/main/tests/docker/dnsdist-numa-l7/README.md
Starts the docker compose services and probes the setup using dig and curl to verify the PROXY v2 UDP flow and check numa statistics.
```sh
docker compose up -d --build
```
```sh
dig +short @127.0.0.1 -p 15454 example.com
```
```sh
curl -s http://127.0.0.1:15381/stats | jq '.proxy_protocol, .transport'
```
```sh
docker compose logs numa | grep -i pp2
```
--------------------------------
### Install Numa via Script (Linux)
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Download and execute the installation script for Numa on Linux.
```bash
# Linux
curl -fsSL https://raw.githubusercontent.com/razvandimescu/numa/main/install.sh | sh
```
--------------------------------
### Install Numa as a System Service (macOS/Linux)
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Install Numa to run as a system service using the `install` command. This is for macOS and Linux.
```bash
sudo numa install
```
--------------------------------
### Install Numa using Homebrew, Cargo, or script
Source: https://github.com/razvandimescu/numa/blob/main/site/index.html
Choose one of the installation methods provided. After installation, run the 'numa' command with sudo to bind to privileged ports.
```bash
# Install (pick one)
$ brew install razvandimescu/tap/numa
$ cargo install numa
$ curl -fsSL https://raw.githubusercontent.com/razvandimescu/numa/main/install.sh | sh
```
--------------------------------
### Setup Phone DNS with Numa
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Run this command to configure your phone's DNS to route through Numa over TLS. It generates a QR code for easy profile installation and certificate trust toggling. Requires `[mobile] enabled = true` in `numa.toml`.
```bash
numa setup-phone
```
--------------------------------
### Install Numa on Windows
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Install Numa on Windows, requiring administrator privileges. A reboot is necessary for auto-start.
```bash
# Windows
numa install (admin) + reboot
```
--------------------------------
### Verify ODoH Setup
Source: https://github.com/razvandimescu/numa/blob/main/recipes/odoh-upstream.md
Verify the ODoH setup by querying a local Numa instance using `kdig`. Check Numa's logs for `ODoH relay returned ...` errors if routing fails, and look for `odoh://` in the API and startup banner.
```bash
kdig @127.0.0.1 example.com
```
--------------------------------
### Iterative DNS Resolution Example
Source: https://github.com/razvandimescu/numa/blob/main/blog/dnssec-from-scratch.md
Illustrates the step-by-step process of an iterative DNS query, showing referrals and glue records.
```text
resolve("cloudflare.com", A)
→ ask 198.41.0.4 (a.root-servers.net)
← "try .com: ns1.gtld-servers.net (192.5.6.30)" [referral + glue]
→ ask 192.5.6.30 (ns1.gtld-servers.net)
← "try cloudflare: ns1.cloudflare.com (173.245.58.51)" [referral + glue]
→ ask 173.245.58.51 (ns1.cloudflare.com)
← "104.16.132.229" [answer]
```
--------------------------------
### Install Numa via Homebrew (macOS)
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Use Homebrew to install Numa on macOS systems.
```bash
# macOS
brew install razvandimescu/tap/numa
```
--------------------------------
### Install Numa via Pacman (Arch Linux)
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Install Numa using the Pacman package manager on Arch Linux.
```bash
# Arch Linux
pacman -S numa
```
--------------------------------
### Deploy Numa Client with Docker Compose
Source: https://github.com/razvandimescu/numa/blob/main/packaging/client/README.md
Use these commands to start and monitor the Numa ODoH client service.
```sh
docker compose up -d
docker compose logs -f numa # watch startup
```
--------------------------------
### Install Numa via Cargo
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Install Numa using the Cargo package manager for Rust projects.
```bash
# All platforms
cargo install numa
```
--------------------------------
### Run Numa in Foreground
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Start Numa in the foreground. Port 53 requires root or administrator privileges.
```bash
sudo numa # run in foreground (port 53 requires root/admin)
```
--------------------------------
### Run Numa and test resolution
Source: https://github.com/razvandimescu/numa/blob/main/site/index.html
After installation, run the 'numa' command with sudo to bind to privileged ports. Use 'dig' to test DNS resolution against the local Numa instance.
```bash
# Run
$ sudo numa # bind :53, :80, :443, :853, :5380
$ dig @127.0.0.1 google.com # test resolution
```
--------------------------------
### Configure Mobile Setup Visibility
Source: https://github.com/razvandimescu/numa/blob/main/site/dashboard.html
Controls the display of the mobile setup section based on whether mobile features are enabled in the stats. Sets the display style of the 'phoneSetup' element.
```javascript
const phoneSetupEl = document.getElementById('phoneSetup');
if (stats.mobile && stats.mobile.enabled) {
phoneSetupEl.style.display = '';
mobilePort = stats.mobile.port;
} else {
phoneSetupEl.style.display = 'none';
}
```
--------------------------------
### Install CA on Linux
Source: https://github.com/razvandimescu/numa/blob/main/recipes/doh-on-lan.md
Place the Numa CA certificate in the appropriate directory and update the system's trusted certificates on Linux.
```bash
drop into /usr/local/share/ca-certificates/
and run sudo update-ca-certificates
```
--------------------------------
### Criterion Benchmark Result Example (Rust)
Source: https://github.com/razvandimescu/numa/blob/main/bench/README.md
An example of output from a Criterion benchmark, showing the measured time, change compared to a baseline, and statistical significance.
```text
round_trip_cached time: [710.5 ns 715.2 ns 720.1 ns]
change: [-2.48% -1.85% -1.21%] (p = 0.00 < 0.05)
Performance has improved.
```
--------------------------------
### Generate Phone Setup Profile and QR Code
Source: https://github.com/razvandimescu/numa/blob/main/blog/dot-from-scratch.md
This command generates a mobile configuration profile for iOS, serving it via a QR code in the terminal. This profile configures your iPhone to use Numa for DNS-over-TLS.
```bash
$ numa setup-phone
Numa Phone Setup
Profile URL: http://192.168.1.10:8765/mobileconfig
██████████████████████████████
██ ██
██ [QR code rendered in ██
██ your terminal] ██
██ ██
██████████████████████████████
On your iPhone:
1. Open Camera, point at the QR code, tap the yellow banner
2. Allow the download when Safari asks
3. Open Settings — tap "Profile Downloaded" near the top
(or: Settings → General → VPN & Device Management → Numa DNS)
4. Tap Install (top right), enter passcode, Install again
5. Settings → General → About → Certificate Trust Settings
Toggle ON "Numa Local CA" — required for DoT to work
```
--------------------------------
### Monitor Caddy Logs for ACME Provisioning
Source: https://github.com/razvandimescu/numa/blob/main/packaging/relay/README.md
Follows the logs of the Caddy service to observe the ACME certificate provisioning process. This is useful for troubleshooting initial setup.
```sh
docker compose logs -f caddy
```
--------------------------------
### Install CA on macOS
Source: https://github.com/razvandimescu/numa/blob/main/recipes/doh-on-lan.md
Add the fetched Numa CA certificate to the system keychain on macOS to establish trust for DoH connections.
```bash
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain numa-ca.pem
```
--------------------------------
### Run the smoke test script
Source: https://github.com/razvandimescu/numa/blob/main/tests/docker/dnsdist-numa-l7/README.md
Executes the smoke test script to build the numa Docker image, start dnsdist, and run queries to validate the PROXY v2 UDP path.
```sh
./smoke.sh
```
--------------------------------
### Deploy Numa ODoH Relay with Docker Compose
Source: https://github.com/razvandimescu/numa/blob/main/packaging/relay/README.md
Starts the Caddy and Numa relay services in detached mode. Use this command to initiate the deployment.
```sh
docker compose up -d
```
--------------------------------
### Create a New Service with DNS, TLS, and Proxy
Source: https://github.com/razvandimescu/numa/blob/main/blog/dns-from-scratch.md
Use this command to create a new service. It automatically sets up the DNS entry, generates a TLS certificate, and configures the reverse proxy, including WebSocket support for Vite HMR. This single API call replaces the need for separate configurations for DNS, proxy, and certificates.
```bash
curl -X POST localhost:5380/services -d '{"name":"frontend","target_port":5173}'
```
--------------------------------
### Initialize API and Utility Functions
Source: https://github.com/razvandimescu/numa/blob/main/site/dashboard.html
Sets up the API endpoint and defines utility functions for HTML escaping, theme management, uptime formatting, number formatting, time formatting, and mobile configuration.
```javascript
const API = ''; const h = s => String(s).replace(/&/g,'&').replace(//g,'>').replace(/
```
```javascript
let prevTotal = null; let lastLogEntries = []; const rebindAllowed = new Set(); // domains allowlisted this session, so old log rows show "allowed" instead of the button let prevTime = null; async function fetchJSON(path) { const res = await fetch(API + path); if (!res.ok) throw new Error(res.status); return res.json(); }
```
```javascript
function applyTheme(mode) { if (mode === 'light' || mode === 'dark') { document.documentElement.setAttribute('data-theme', mode); } else { document.documentElement.removeAttribute('data-theme'); } const btn = document.getElementById('themeBtn'); if (btn) btn.textContent = 'Theme: ' + mode[0].toUpperCase() + mode.slice(1); }
```
```javascript
function cycleTheme() { const cur = localStorage.getItem('numa-theme') || 'auto'; const next = cur === 'auto' ? 'light' : cur === 'light' ? 'dark' : 'auto'; localStorage.setItem('numa-theme', next); applyTheme(next); }
```
```javascript
applyTheme(localStorage.getItem('numa-theme') || 'auto');
```
```javascript
function formatUptime(secs) { if (secs < 60) return `${secs}s`; if (secs < 3600) return `${Math.floor(secs / 60)}m`; const h = Math.floor(secs / 3600); const m = Math.floor((secs % 3600) / 60); return `${h}h ${m}m`; }
```
```javascript
function formatUptimeSub(secs) { const d = Math.floor(secs / 86400); const h = Math.floor((secs % 86400) / 3600); const m = Math.floor((secs % 3600) / 60); const s = secs % 60; if (d > 0) return `${d}d ${h}h ${m}m ${s}s`; if (h > 0) return `${h}h ${m}m ${s}s`; if (m > 0) return `${m}m ${s}s`; return `${s}s`; }
```
```javascript
function formatNumber(n) { if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M'; if (n >= 1000) return (n / 1000).toFixed(1) + 'K'; return n.toString(); }
```
```javascript
function formatTime(epoch) { const d = new Date(epoch * 1000); return d.toLocaleTimeString([], { hour12: false }); }
```
```javascript
let mobilePort = 8765; let proxyTld = 'numa';
```
```javascript
function togglePhoneSetup() { const pop = document.getElementById('phoneSetupPopover'); const isOpen = pop.style.display !== 'none'; pop.style.display = isOpen ? 'none' : 'block'; if (!isOpen) { if (window.innerWidth <= 700) { document.getElementById('qrContainer').style.display = 'none'; const linkEl = document.getElementById('phoneSetupLink'); const host = window.location.hostname; linkEl.style.display = 'block'; linkEl.innerHTML = `Install Profile`; } else { fetch(API + '/qr').then(r => r.text()).then(svg => { document.getElementById('qrContainer').innerHTML = svg; }).catch(() => { document.getElementById('qrContainer').innerHTML = '
Could not load QR
'; }); } } }
```
```javascript
document.addEventListener('click', (e) => { const setup = document.getElementById('phoneSetup'); if (setup && !setup.contains(e.target)) { document.getElementById('phoneSetupPopover').style.display = 'none'; } });
```
```javascript
function shortSrc(addr) { if (!addr) return ''; const ip = addr.replace(/:\d+$/, ''); if (ip === '127.0.0.1' || ip === '::1') return 'localhost'; return ip; }
```
```javascript
function formatRemaining(secs) { if (secs == null) return 'permanent'; if (secs < 60) return `${secs}s left`; if (secs < 3600) return `${Math.floor(secs / 60)}m ${secs % 60}s left`; return `${Math.floor(secs / 3600)}h ${Math.floor((secs % 3600) / 60)}m left`; }
```
```javascript
function formatBytes(bytes) { if (bytes === 0) return '0 B'; if (bytes < 1024) return bytes + ' B'; if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB'; return (bytes / 1073741824).toFixed(1) + ' GB'; }
```
```javascript
const MEMORY_COMPONENTS = [ { key: 'cache', label: 'Cache', cls: 'cache', color: 'var(--teal)' }, { key: 'blocklist', label: 'Blocklist', cls: 'blocklist', color: 'var(--rose)' }, { key: 'query_log', label: 'Query Log', cls: 'querylog', color: 'var(--amber)' }, { key: 'srtt', label: 'SRTT', cls: 'srtt', color: 'var(--cyan)' }, { key: 'overrides', label: 'Overrides', cls: 'overrides', color: 'var(--violet)' }, ];
```
```javascript
function renderMemory(mem, stats) { if (!mem) return; // Stat card document.getElementById('memoryRss').textContent = formatBytes(mem.process_memory_bytes); document.getElementById('memorySub').textContent = 'est. ' + formatBytes(mem.total_estimated_bytes); const entryCounts = { cache: stats.cache.entries, blocklist: stats.blocking.domains_loaded, query_log: mem.query_log_entries, srtt: mem.srtt_entries, overrides: stats.overrides.active, };
```
--------------------------------
### Run Numa with Host Networking (Docker)
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Recommended Docker deployment on Linux using host networking. This simplifies network configuration by sharing the host's network stack.
```bash
docker run -d --name numa --network host ghcr.io/razvandimescu/numa
```
--------------------------------
### Run Numa with Nix
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Execute Numa using the Nix package manager.
```bash
# Nix
nix run github:razvandimescu/numa
```
--------------------------------
### Pause Blocking for 5 Minutes
Source: https://github.com/razvandimescu/numa/blob/main/site/dashboard.html
Pauses the blocking feature for a specified duration (5 minutes in this example). It sends a POST request to the API.
```javascript
async function pauseBlocking() {
try {
await fetch(API + '/blocking/pause', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ minutes: 5 }),
});
refresh();
} catch (err) {}
}
```
--------------------------------
### Run All Micro-benchmarks (Rust)
Source: https://github.com/razvandimescu/numa/blob/main/bench/README.md
Execute all available micro-benchmarks using Cargo. These benchmarks measure individual operations on the hot path without requiring a running server.
```sh
cargo bench
```
--------------------------------
### Register Local Development Service with Numa
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Use this command to register a local development service by name and target port. This allows accessing services via a custom domain (e.g., `https://frontend.numa`) without modifying system configurations.
```bash
curl -X POST localhost:5380/services \
-d '{"name":"frontend","target_port":5173}'
```
--------------------------------
### Run Numa with Custom Configuration (Docker)
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Deploy Numa using Docker with a custom configuration file. Mounts a local numa.toml file into the container to override default settings.
```bash
docker run -d --name numa --network host \
-v /path/to/numa.toml:/root/.config/numa/numa.toml \
ghcr.io/razvandimescu/numa
```
--------------------------------
### Code Block Styling
Source: https://github.com/razvandimescu/numa/blob/main/site/index.html
Styles for a code block, including syntax highlighting for prompts, commands, flags, and strings. This is useful for displaying terminal output or code examples.
```css
.code-block {
background: #1a1612;
color: #d6d0c6;
border: 1px solid rgba(44,36,24,0.15);
border-radius: 4px;
padding: 1.5rem;
font-family: var(--font-mono);
font-size: 0.8rem;
line-height: 1.9;
color: var(--text-secondary);
overflow-x: auto;
position: relative;
white-space: pre-wrap;
word-break: break-all;
}
.code-block::before {
content: 'terminal';
position: absolute;
top: 0;
right: 0;
font-family: var(--font-mono);
font-size: 0.6rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: #7a7060;
padding: 0.4rem 0.8rem;
background: #241f1a;
border-left: 1px solid rgba(255,255,255,0.06);
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.code-block .prompt {
color: #8baa6e;
}
.code-block .comment {
color: #7a7060;
}
.code-block .cmd {
color: #d48a5a;
}
.code-block .flag {
color: #8b9fbb;
}
.code-block .str {
color: #7dab7d;
}
```
--------------------------------
### Fetch Numa's Self-Signed CA Certificate
Source: https://github.com/razvandimescu/numa/blob/main/recipes/doh-on-lan.md
Download Numa's self-signed CA certificate to install it on client devices. This is necessary for clients to trust the DoH connection.
```bash
curl -o numa-ca.pem http://:5380/ca.pem
```
--------------------------------
### Run Numa with Port Mapping (Docker)
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Docker deployment for macOS and Windows using port mapping. Exposes Numa's DNS and dashboard ports to the host.
```bash
docker run -d --name numa -p 53:53/udp -p 53:53/tcp -p 5380:5380 ghcr.io/razvandimescu/numa
```
--------------------------------
### Rustls Crypto Provider Panic Error
Source: https://github.com/razvandimescu/numa/blob/main/blog/dot-from-scratch.md
This error occurs when the rustls crypto provider is not installed before building a ServerConfig, specifically affecting DoT users who disable the HTTPS proxy. The fix involves calling `install_default` within `load_tls_config`.
```text
thread 'dot' panicked at rustls-0.23.25/src/crypto/mod.rs:185:14:
no process-level CryptoProvider available -- call
CryptoProvider::install_default() before this point
```
--------------------------------
### Calculate and Display Queries Per Second (QPS)
Source: https://github.com/razvandimescu/numa/blob/main/site/dashboard.html
Calculates and displays the Queries Per Second (QPS) based on the change in total queries over time. Also shows the percentage of encrypted queries. Requires 'prevTotal' and 'prevTime' to be initialized.
```javascript
const now = Date.now();
const encPct = encryptionPct(stats.transport,
['dot', 'doh']
,
['udp', 'tcp', 'dot', 'doh']
);
if (prevTotal !== null && prevTime !== null) {
const dt = (now - prevTime) / 1000;
const dq = q.total - prevTotal;
const qps = dt > 0 ? (dq / dt).toFixed(1) : '0.0';
const encTag = q.total > 0 ?
` · ${encPct}% enc`
: '';
document.getElementById('qps').textContent =
`~${qps}/s${encTag}`
;
}
prevTotal = q.total;
prevTime = now;
```
--------------------------------
### Save and Compare Benchmarks (Rust)
Source: https://github.com/razvandimescu/numa/blob/main/bench/README.md
Save a named baseline for micro-benchmarks using Criterion, make changes, and then run benchmarks against the saved baseline for comparison.
```sh
cargo bench -- --save-baseline before
# ... make changes ...
cargo bench -- --baseline before
```
--------------------------------
### Intersection Observer for Reveal Animations
Source: https://github.com/razvandimescu/numa/blob/main/site/index.html
This JavaScript snippet uses the Intersection Observer API to add a 'visible' class to elements when they enter the viewport, triggering reveal animations. It's configured with a 10% threshold and a root margin to control when the animation starts.
```javascript
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
```
--------------------------------
### Diagram of UDP PROXY v2 flow
Source: https://github.com/razvandimescu/numa/blob/main/tests/docker/dnsdist-numa-l7/README.md
Illustrates the flow of UDP queries from a host through dnsdist to numa, with PROXY v2 headers prepended.
```text
host dig +udp ──UDP──> dnsdist :53 ──UDP+PROXY v2──> numa :53 ──forward──> 9.9.9.9
```
--------------------------------
### Run Specific Micro-benchmark Suite (Rust)
Source: https://github.com/razvandimescu/numa/blob/main/bench/README.md
Execute a specific micro-benchmark suite, such as 'hot_path' for parsing, serialization, caching, and cloning, or 'throughput' for pipeline QPS and buffer allocation.
```sh
cargo bench --bench hot_path
```
```sh
cargo bench --bench throughput
```
--------------------------------
### dnsdist Configuration for Numa
Source: https://github.com/razvandimescu/numa/blob/main/recipes/dnsdist-front.md
Sets up dnsdist to listen for DoH, DoT, and DoQ on public interfaces, forwarding plain DNS requests with PROXY protocol to a local Numa instance. Includes TLS certificate paths and basic routing.
```lua
-- /etc/dnsdist/dnsdist.conf
newServer({"address="127.0.0.1:53", name="numa", checkType="A", checkName="numa.rs.",
useProxyProtocol=true}) -- preserves real client IPs (see below)
addDOHLocal(
"0.0.0.0:443",
"/etc/letsencrypt/live/dns.example.com/fullchain.pem",
"/etc/letsencrypt/live/dns.example.com/privkey.pem",
"/dns-query",
{doTCP=true, reusePort=true}
)
addTLSLocal(
"0.0.0.0:853",
"/etc/letsencrypt/live/dns.example.com/fullchain.pem",
"/etc/letsencrypt/live/dns.example.com/privkey.pem"
)
addAction(AllRule(), PoolAction("", false))
```
--------------------------------
### Run End-to-End Benchmark (Shell)
Source: https://github.com/razvandimescu/numa/blob/main/bench/README.md
Execute the end-to-end benchmark script to compare Numa's latency against public resolvers. This measures millisecond-level latency including network I/O.
```sh
# Start Numa first (default port 15353 for testing)
python3 bench/dns-bench.sh [port] [rounds]
python3 bench/dns-bench.sh 15353 20 # default
```
--------------------------------
### Run Numa with Docker
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Deploy and run Numa as a Docker container in detached mode.
```bash
# Docker
docker run -d --name numa --network host ghcr.io/razvandimescu/numa
```
--------------------------------
### Manual Probe Commands
Source: https://github.com/razvandimescu/numa/blob/main/tests/docker/pp2-numa/README.md
Provides commands for manually testing DoT and plain TCP DNS queries through HAProxy, checking numa stats, and viewing client IP visibility.
```sh
docker compose up -d --build
```
```sh
kdig +tls @127.0.0.1 -p 5853 example.com
```
```sh
dig +tcp @127.0.0.1 -p 15353 example.com
```
```sh
curl -s http://127.0.0.1:15380/stats | jq '.proxy_protocol'
```
```sh
docker compose logs numa | grep -i pp2
```
--------------------------------
### Render DNS Cache List - JavaScript
Source: https://github.com/razvandimescu/numa/blob/main/site/dashboard.html
Renders a list of DNS cache entries, showing up to the first 50 entries sorted by remaining TTL in descending order. Displays the total number of entries and a message if the cache is empty.
```javascript
function renderCache(entries) {
const el = document.getElementById('cacheList');
document.getElementById('cacheCount').textContent = entries.length ? `${entries.length} entries` : '';
if (!entries.length) {
el.innerHTML = '
Cache empty
';
return;
}
// Show first 50, sorted by TTL remaining desc
const sorted = entries.sort((a, b) => b.ttl_remaining - a.ttl_remaining).slice(0, 50);
el.innerHTML = sorted.map(e =>
`
${h(e.domain)}${e.query_type} ${e.ttl_remaining}s
`).join('');
}
```
--------------------------------
### Configure Numa Server Allow List
Source: https://github.com/razvandimescu/numa/blob/main/blog/numa-services-over-tailnet.md
Define the '[server].allow_from' list in numa.toml to restrict access to the Numa proxy based on IP ranges, such as Tailnet and local networks.
```toml
[server]
allow_from = ["100.64.0.0/10", "192.168.1.0/24"]
```
--------------------------------
### Verify DNS Resolution with kdig
Source: https://github.com/razvandimescu/numa/blob/main/recipes/dnsdist-front.md
Tests public DoH and DoT resolution through the configured dnsdist endpoint using kdig, ensuring proper responses and client IP logging.
```bash
kdig +https @dns.example.com example.com
kdig +tls @dns.example.com example.com
```
--------------------------------
### DNS Query Packet Structure
Source: https://github.com/razvandimescu/numa/blob/main/blog/dns-from-scratch.md
Illustrates the byte layout of a 29-byte DNS query for 'example.com A', breaking down the header and question sections.
```text
ID Flags QCount ACount NSCount ARCount
┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐
Header: AB CD 01 00 00 01 00 00 00 00 00 00
└────┘ └────┘ └────┘ └────┘ └────┘ └────┘
↑ ↑ ↑
│ │ └─ 1 question, 0 answers, 0 authority, 0 additional
│ └─ Standard query, recursion desired
└─ Random ID (we'll match this in the response)
Question: 07 65 78 61 6D 70 6C 65 03 63 6F 6D 00 00 01 00 01
── ───────────────────── ── ───────── ── ───── ─────
7 e x a m p l e 3 c o m end A IN
↑ ↑ ↑
└─ length prefix └─ length └─ root label (end of name)
```
--------------------------------
### Registering a Numa Service via TOML
Source: https://github.com/razvandimescu/numa/blob/main/blog/numa-services-over-tailnet.md
Configure a Numa service by specifying its name, target port, and the target host's Tailnet IP. This is used when the service runs on a different machine than the Numa node.
```toml
[[services]]
name = "peekmtail"
target_port = 6419
target_host = "100.64.72.113" # the laptop's tailnet IP, where peekm runs
```
--------------------------------
### Render Allowlist Entries
Source: https://github.com/razvandimescu/numa/blob/main/site/dashboard.html
Renders the allowlist entries, displaying each domain and providing a button to delete it. It also shows the count of entries and handles cases where the list is empty.
```javascript
function renderAllowlist(entries, manualBlocks) {
const focused = document.activeElement && document.activeElement.id;
if (focused === 'allowDomainInput' || focused === 'blockDomainInput') return;
const el = document.getElementById('blockingAllowlist');
const count = entries.length;
const blocked = manualBlocks || [];
el.innerHTML = `
Allowlist${count ? ` (${count})` : ''}
${count ? entries.map(d => `
${h(d)}
`).join('') : '
No '}`;
}
```
--------------------------------
### Configure Reqwest HTTP/2 Window Sizes
Source: https://github.com/razvandimescu/numa/blob/main/blog/fixing-doh-tail-latency.md
Adjust HTTP/2 initial stream and connection window sizes for small-payload workloads like DoH. This can reduce median latency by preventing unnecessary WINDOW_UPDATE frames and improving server-side scheduling.
```rust
reqwest::Client::builder()
.use_rustls_tls()
.http2_initial_stream_window_size(65_535)
.http2_initial_connection_window_size(65_535)
.http2_keep_alive_interval(Duration::from_secs(15))
.http2_keep_alive_while_idle(true)
.http2_keep_alive_timeout(Duration::from_secs(10))
.pool_idle_timeout(Duration::from_secs(300))
.pool_max_idle_per_host(1)
.build()
```
--------------------------------
### Enable LAN Discovery
Source: https://github.com/razvandimescu/numa/blob/main/README.md
Enable automatic LAN discovery for Numa instances. This allows machines to find each other and proxy requests.
```bash
numa lan on
```
--------------------------------
### Parse Compressed DNS QNAME
Source: https://github.com/razvandimescu/numa/blob/main/blog/dns-from-scratch.md
Reads a DNS qualified name (QNAME) from a buffer, handling label compression pointers. Appends the parsed name to an output string. The buffer's read position is managed carefully to avoid skipping data when following pointers.
```rust
pub fn read_qname(&mut self, outstr: &mut String) -> Result<()> {
let mut pos = self.pos();
let mut jumped = false;
let mut delim = "";
loop {
let len = self.get(pos)?;
// Top two bits set = compression pointer
if (len & 0xC0) == 0xC0 {
if !jumped {
self.seek(pos + 2)?; // advance past the pointer
}
let offset = (((len as u16) ^ 0xC0) << 8) | self.get(pos + 1)? as u16;
pos = offset as usize;
jumped = true;
continue;
}
pos += 1;
if len == 0 { break; } // root label
outstr.push_str(delim);
outstr.push_str(&self.get_range(pos, len as usize)?
.iter().map(|&b| b as char).collect::());
delim = ".";
pos += len as usize;
}
if !jumped {
self.seek(pos)?;
}
Ok(())
}
```
--------------------------------
### Verify DoH Connection with kdig
Source: https://github.com/razvandimescu/numa/blob/main/recipes/doh-on-lan.md
Use kdig to test the DoH connection by querying a domain over HTTPS. This verifies that Numa is correctly serving DNS queries via DoH.
```bash
kdig +https @numa example.com
```
--------------------------------
### Implement Request Hedging in Rust
Source: https://github.com/razvandimescu/numa/blob/main/blog/fixing-doh-tail-latency.md
This Rust function demonstrates how to implement request hedging for raw forward queries. It sends a primary request and, after a specified delay, sends a secondary request in parallel. The first successful response from either request is returned. This is useful for reducing tail latency caused by random upstream delays.
```rust
pub async fn forward_with_hedging_raw(
wire: &[u8],
primary: &Upstream,
secondary: &Upstream,
hedge_delay: Duration,
timeout_duration: Duration,
) -> Result> {
let primary_fut = forward_query_raw(wire, primary, timeout_duration);
tokio::pin!(primary_fut);
let delay = sleep(hedge_delay);
tokio::pin!(delay);
// Phase 1: wait for primary to return OR the hedge delay.
tokio::select! {
result = &mut primary_fut => return result,
_ = &mut delay => {}
}
// Phase 2: hedge delay expired — fire secondary, keep primary alive.
let secondary_fut = forward_query_raw(wire, secondary, timeout_duration);
tokio::pin!(secondary_fut);
// First successful response wins.
tokio::select! {
r = primary_fut => r,
r = secondary_fut => r,
}
}
```
--------------------------------
### Configure Peekm to Trust Tailnet CIDR
Source: https://github.com/razvandimescu/numa/blob/main/blog/numa-services-over-tailnet.md
When using tools like peekm, use the '--trusted-cidr' flag with the Tailnet IP range (e.g., '100.64.0.0/10') to allow connections from the Numa proxy.
```bash
peekm --trusted-cidr 100.64.0.0/10 ~/projects
```
--------------------------------
### Initial Load and Polling for Dashboard Refresh
Source: https://github.com/razvandimescu/numa/blob/main/site/dashboard.html
Initiates the first dashboard refresh and sets up an interval to poll for updates every 2 seconds. This ensures the dashboard stays current with service statuses.
```javascript
// Initial load + polling
refresh();
setInterval(refresh, 2000);
```
--------------------------------
### Configure Global Nameserver in Tailscale
Source: https://github.com/razvandimescu/numa/blob/main/blog/numa-tailnet-resolver.md
Set the Numa node's Tailnet IP as the global nameserver in the Tailscale admin console. This directs all Tailnet DNS queries to Numa.
```text
100.65.127.63 # our pi-0's ip
```
--------------------------------
### Verify Numa Query Log
Source: https://github.com/razvandimescu/numa/blob/main/blog/numa-tailnet-resolver.md
Check Numa's query log to confirm that client requests are originating from their Tailscale IP addresses. This verifies end-to-end connectivity through WireGuard.
```log
100.81.95.112 A example.com NOERROR cache 1ms
100.81.95.112 AAAA gateway.example.net NOERROR fwd 34ms
100.81.95.112 A news.ycombinator.com NOERROR fwd 28ms
```
--------------------------------
### Configure Numa Access Control
Source: https://github.com/razvandimescu/numa/blob/main/blog/numa-tailnet-resolver.md
Configure the `allow_from` setting in Numa's TOML configuration to restrict access to specific networks. This ensures Numa only serves requests from your Tailnet and local network.
```toml
[server]
allow_from = ["192.168.1.0/24", "100.64.0.0/10"]
```