### 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"] ```