### Export TOWONEL_HUB_URL and TOWONEL_OPERATOR_KEY Source: https://towonel.dev/docs/self-hosted/operations Environment setup for operator authentication. If the operator key is supplied via TOWONEL_HUB_OPERATOR_API_KEY, read it from your secret manager instead. ```bash export TOWONEL_HUB_URL=https://hub.example.eu:8443 export TOWONEL_OPERATOR_KEY=$(docker exec towonel cat /data/operator.key) ``` -------------------------------- ### Directory layout for towonel-agent Source: https://towonel.dev/docs/agent/kubernetes Directory layout for the towonel-agent Flux setup, showing the expected file structure under kubernetes/apps/network/towonel-agent/. ```text kubernetes/apps/network/towonel-agent/ ├── ks.yaml └── app/ ├── kustomization.yaml ├── ocirepository.yaml ├── helmrelease.yaml ├── externalsecret.yaml └── dnsendpoint.yaml ``` -------------------------------- ### Configure UDP port range with listen_port_range Source: https://towonel.dev/docs/agent/tcp-udp Configure a UDP port range by using listen_port_range ([start, end], inclusive) instead of listen_port. A datagram on any port in the range is forwarded to the origin host at the same port, so origin is host-only (no :port). The hub caps one range at TOWONEL_HUB_MAX_UDP_PORT_RANGE ports (default 512). Ranges aren’t available when TOWONEL_HUB_PORTS_REQUIRE_RESERVATION is on. ```bash TOWONEL_AGENT_UDP_SERVICES='[ {"name":"relay", "origin":"10.0.0.5", "listen_port_range":[49160,49660], "idle_timeout_secs":600} ]' ``` -------------------------------- ### Create an invite with towonel CLI Source: https://towonel.dev/docs/self-hosted/hub/docker Creates an invite for a user named alice with the specified hostnames. The output is an invite token in the format tt_inv_2_. ```bash docker exec towonel towonel invite create \ --name alice \ --hostnames 'app.alice.example.eu,*.alice.example.eu' # tt_inv_2_ ``` -------------------------------- ### Enable web console and set public URL Source: https://towonel.dev/docs/self-hosted/web-console Required environment variables to enable the web console and set the public URL. TOWONEL_HUB_WEB_ENABLED must be true, TOWONEL_HUB_PUBLIC_URL is required for WebAuthn RP ID and credential/invite URLs, and TOWONEL_HUB_CONSOLE_URL sets the browser front-end origin. TOWONEL_HUB_WEBAUTHN_RP_ID overrides the derived RP ID only if it differs from the public URL host. ```bash -e TOWONEL_HUB_WEB_ENABLED=true -e TOWONEL_HUB_PUBLIC_URL=https://hub.example.eu -e TOWONEL_HUB_CONSOLE_URL=https://console.example.eu # browser front-end origin # WebAuthn RP ID derives from PUBLIC_URL; override only if they differ: -e TOWONEL_HUB_WEBAUTHN_RP_ID=example.eu ``` -------------------------------- ### Get hub ACME account info Source: https://towonel.dev/docs/agent/caa-pinning Fetch the hub's public ACME account information. The response includes the account URI and a ready-to-paste CAA record value. ```shell curl https:///v1/acme/account ``` ```json { "account_uri": "https://acme-v02.api.letsencrypt.org/acme/acct/123456789", "caa_record": "letsencrypt.org;validationmethods=tls-alpn-01;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/123456789" } ``` -------------------------------- ### Add a server with --auth-key Source: https://towonel.dev/docs/mesh Run on a server using an auth key obtained from the console's Private network > Add a server. Tags (default server) make the device belong to the tunnel and never expire; without tags the server is yours and its key lasts 180 days. Key expiry (up to 90 days) limits how long the key can add servers. ```bash towonel mesh up --hub-url https://hub.example.eu --auth-key tmk_… ``` -------------------------------- ### HelmRelease for towonel-agent Source: https://towonel.dev/docs/agent/kubernetes HelmRelease for towonel-agent with two replicas, SNI-routed TLS passthrough services, opaque TCP/UDP services, and an invite token secret. Metrics serve on agent.healthPort (default 9090) with /healthz probes; the agent is stateless and each replica gets its own transport identity. ```yaml apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: towonel-agent spec: chartRef: kind: OCIRepository name: towonel-agent interval: 1h values: controllers: main: replicas: 2 annotations: reloader.stakater.com/auto: "true" agent: services: - hostname: "*.example.dev" origin: envoy.network.svc:443 tcpServices: - name: ssh origin: forgejo-ssh.network.svc:2222 listen_port: 2222 udpServices: - name: turn origin: coturn.network.svc:3478 listen_port: 3478 inviteTokenSecret: name: towonel-agent-secret serviceMonitor: main: enabled: true ``` -------------------------------- ### Run the Towonel edge container with Docker Source: https://towonel.dev/docs/self-hosted/edge/docker Run the Towonel edge container, authenticating to the hub with the hub-link PSK. Mount a volume at /data so the iroh identity (node.key) survives restarts. Set TOWONEL_EDGE_ENABLED=true and TOWONEL_HUB_ENABLED=false, and provide the hub address, PSK, and advertised address. ```bash docker run -d --name towonel-edge \ -p 443:443 -p 51820:51820/udp \ -v towonel-edge-data:/data \ -e TOWONEL_EDGE_ENABLED=true \ -e TOWONEL_HUB_ENABLED=false \ -e TOWONEL_EDGE_HUB_LINK_ADDR=hub.example.eu:51444 \ -e TOWONEL_EDGE_HUB_LINK_PSK=$(cat hub.link.psk) \ -e TOWONEL_EDGE_ADVERTISED_ADDRESSES=fra1.example.eu:443 \ git.ow-ops.eu/towonel/towonel-node:latest ``` -------------------------------- ### Run Towonel hub with bundled Caddy Source: https://towonel.dev/docs/self-hosted/hub/docker Runs the bundled-Caddy variant of the Towonel hub, which ships Caddy (caddy-l4) in the same image. Caddy binds :80/:443 and L4-forwards to towonel with PROXY v2; mount a custom Caddyfile at /etc/caddy/Caddyfile to override. ```bash docker run -d --name towonel \ -p 80:80 -p 443:443 -p 8443:8443 -p 51820:51820/udp \ -v towonel-data:/data \ -e TOWONEL_HUB_PUBLIC_URL=https://hub.example.eu \ -e TOWONEL_EDGE_ADVERTISED_ADDRESSES=hub.example.eu:443 \ -e TOWONEL_HUB_TLS_ACME_EMAIL=ops@example.eu \ git.ow-ops.eu/towonel/towonel-hub-caddy:latest ``` -------------------------------- ### Configure UDP services with TOWONEL_AGENT_UDP_SERVICES Source: https://towonel.dev/docs/agent/tcp-udp Configure the agent to expose UDP services by setting the TOWONEL_AGENT_UDP_SERVICES environment variable. Each entry maps a service name to an origin host and port, and declares the listen port. Datagrams are framed onto the agent↔edge QUIC tunnel (length-prefixed, up to 64 KiB). The edge reaps a session after 60s of inactivity; set idle_timeout_secs per service (1–3600) for flows whose keepalives are further apart. ```bash TOWONEL_AGENT_UDP_SERVICES='[ {"name":"dns", "origin":"127.0.0.1:5353", "listen_port":5353}, {"name":"wireguard", "origin":"10.0.0.1:51820", "listen_port":51820, "idle_timeout_secs":120} ]' ``` -------------------------------- ### towonel invite create/list/revoke commands Source: https://towonel.dev/docs/self-hosted/operations Commands to create, list, and revoke invites. One invite equals one tenant; revoking removes the tenant. Default --expires is 'never'. ```bash towonel invite create --name alice --hostnames '*.alice.example.eu' towonel invite create --name bob --hostnames 'app.bob.example.eu' --expires 48h towonel invite list towonel invite revoke --id ``` -------------------------------- ### Run Towonel hub with Docker Source: https://towonel.dev/docs/self-hosted/hub/docker Runs the Towonel hub container with the required ports, a persistent volume, and environment variables for the public URL, advertised edge address, and ACME email. The /data volume stores node.key, operator.key, invite_hash.key, and ACME certs, with keys generated on first boot. ```bash docker run -d --name towonel \ -p 443:443 -p 8443:8443 -p 51820:51820/udp \ -v towonel-data:/data \ -e TOWONEL_HUB_PUBLIC_URL=https://hub.example.eu \ -e TOWONEL_EDGE_ADVERTISED_ADDRESSES=hub.example.eu:443 \ -e TOWONEL_HUB_TLS_ACME_EMAIL=ops@example.eu \ git.ow-ops.eu/towonel/towonel-node:latest ``` -------------------------------- ### Configure TCP and UDP services Source: https://towonel.dev/docs/agent/docker Environment variables to configure TCP and UDP services for the agent. Each service specifies a name, origin, and listen port. ```bash -e TOWONEL_AGENT_TCP_SERVICES='[ {"name":"ssh","origin":"127.0.0.1:22","listen_port":2222} ]' -e TOWONEL_AGENT_UDP_SERVICES='[ {"name":"wireguard","origin":"127.0.0.1:51820","listen_port":51820} ]' ``` -------------------------------- ### Enroll a laptop or phone with towonel mesh up Source: https://towonel.dev/docs/mesh Run on a laptop or phone to enroll the device. Prints a sign-in link and an 8-letter code, opens the browser, and requires signing in to the console and checking the code. Codes expire after 10 minutes; --hub-url is only needed the first time and is saved with the device. ```bash towonel mesh up --hub-url https://hub.example.eu ``` -------------------------------- ### Offer a device as an exit with towonel mesh up --advertise-exit-node Source: https://towonel.dev/docs/mesh/exit-nodes Offers the current device as an exit node. Requires the nft tool, enables IPv4 and IPv6 forwarding, and adds an nftables table named 'towonel' that masquerades traffic leaving the tunnel. The table is removed when 'mesh up' stops, but forwarding stays on. The device shows 'offers exit' in the console, and a member of the tunnel must approve it under 'Private network'. ```bash sudo towonel mesh up --advertise-exit-node ``` -------------------------------- ### Run Towonel agent with Docker Source: https://towonel.dev/docs/agent/docker Runs the Towonel agent in a Docker container with host networking and an invite token. The --network host flag lets the agent reach services on the host; drop it when all origins live on a docker network. ```bash docker run -d --name towonel-agent \ --network host \ -e TOWONEL_INVITE_TOKEN=tt_inv_2_... \ -e TOWONEL_AGENT_SERVICES='[ {"hostname":"app.example.dev","origin":"127.0.0.1:8080"} ]' \ git.ow-ops.eu/towonel/towonel-agent:latest ``` -------------------------------- ### Use an exit node with towonel mesh up --exit-node Source: https://towonel.dev/docs/mesh/exit-nodes Uses the specified device as an exit node. Requires the ip tool. Traffic that would have used the default route goes to the exit, while everything else stays direct, including local network traffic. The exit only forwards to public addresses and does not give access to its own LAN. A device cannot offer and use an exit at the same time. ```bash sudo towonel mesh up --exit-node vps-paris ``` -------------------------------- ### Configure hub and edge environment variables for control link Source: https://towonel.dev/docs/self-hosted/federation Sets the required environment variables for the hub and each edge. The hub listens on 0.0.0.0:51444 and uses the PSK from hub.link.psk; edges connect to hub.example.eu:51444 with the same PSK. ```bash # hub -e TOWONEL_HUB_LINK_LISTEN_ADDR=0.0.0.0:51444 -e TOWONEL_HUB_LINK_PSK=$(cat hub.link.psk) ``` ```bash # each edge -e TOWONEL_EDGE_HUB_LINK_ADDR=hub.example.eu:51444 -e TOWONEL_EDGE_HUB_LINK_PSK=$(cat hub.link.psk) ``` -------------------------------- ### Configure TCP services with TOWONEL_AGENT_TCP_SERVICES Source: https://towonel.dev/docs/agent/tcp-udp Configure the agent to expose TCP services by setting the TOWONEL_AGENT_TCP_SERVICES environment variable. Each entry maps a service name to an origin host and port, and declares the listen port on the edge. The edge automatically picks up the declared ports. ```bash TOWONEL_AGENT_TCP_SERVICES='[ {"name":"forgejo-ssh", "origin":"forgejo:22", "listen_port":2222}, {"name":"prom-write", "origin":"vm:8428", "listen_port":9090} ]' ``` -------------------------------- ### Static tenant JSON allowlist Source: https://towonel.dev/docs/self-hosted/operations JSON structure for static tenants in TOWONEL_TENANTS. 'name' and 'hostnames' are required; other fields pin identity and reachability and can be left empty. ```json [ { "name": "alice", "hostnames": ["*.alice.example.eu"], "pq_public_key": "", "agent_node_ids": [], "direct_addresses": [] } ] ``` -------------------------------- ### directConnect configuration for towonel-agent Source: https://towonel.dev/docs/agent/kubernetes Enables direct iroh connectivity by binding a fixed UDP port and exposing it as a NodePort. Requires serviceMonitor.main.serviceName: main because auto-detection stops working with the second Service. Direct NodePort paths are most reliable with a single replica. ```yaml directConnect: enabled: true irohPort: 51820 nodePort: 31820 # omit to let Kubernetes assign one ``` -------------------------------- ### Run towonel mesh up under systemd Source: https://towonel.dev/docs/mesh Run towonel mesh up under systemd to keep it running. The command stays in the foreground; the systemd unit uses the same state directory and restarts on failure. ```bash sudo towonel mesh up --hub-url https://hub.example.eu --state-dir /var/lib/towonel/mesh ``` ```ini [Service] Environment=TOWONEL_MESH_STATE_DIR=/var/lib/towonel/mesh ExecStart=/usr/local/bin/towonel mesh up Restart=on-failure ``` -------------------------------- ### Set TOWONEL_HUB_RELAY_URL and TOWONEL_EDGE_RELAY_URL Source: https://towonel.dev/docs/self-hosted/relay Environment variables for the hub and edge to set the relay URL. The hub advertises its URL to agents at bootstrap; edges take their own env. Bad URLs warn at startup and fall back to disabled. ```bash -e TOWONEL_HUB_RELAY_URL=https://relay.example.eu:8443 # hub -e TOWONEL_EDGE_RELAY_URL=https://relay.example.eu:8443 # edge ``` -------------------------------- ### Set edge limits via environment variables Source: https://towonel.dev/docs/self-hosted/edge/tuning Hard caps for in-flight TCP connections, UDP sessions per listener, and connections per tenant. Defaults are shown; raise under sustained or bursty load. New accepts over the cap close the socket and bump `connections_rejected_overload`; UDP drop-new (not LRU) prevents spoofed-source floods from evicting established sessions. ```bash # Hard cap on simultaneously in-flight TCP connections. New accepts over # the cap close the socket and bump connections_rejected_overload. TOWONEL_EDGE_MAX_INFLIGHT_CONNECTIONS=50000 # default 50000 (≈ ulimit -n) # Per-listener cap on tracked UDP sessions. Drop-new (not LRU) so a # spoofed-source flood can't evict an established session. TOWONEL_EDGE_MAX_UDP_SESSIONS_PER_LISTENER=4096 # default 4096 # Per-tenant connection cap. TOWONEL_EDGE_MAX_CONNECTIONS_PER_TENANT=1000 # default 1000 ``` -------------------------------- ### Set public IPs for port reservation matching Source: https://towonel.dev/docs/self-hosted/edge/tuning When the hub enforces port reservations, list the edge’s raw public IPs (no port) so reservations match. ```bash TOWONEL_EDGE_PUBLIC_IPS=203.0.113.10,2001:db8::10 ``` -------------------------------- ### Expose TURN behind towonel with coturn Source: https://towonel.dev/docs/agent/tcp-udp Expose a TURN server behind towonel by configuring the agent with a single service for the control port and a port range for the relay range. The coturn configuration advertises the edge’s public IP and pins its relay range to the exposed ports. Note: coturn sees the agent as the client source (NAT-like), so IP-based allow/deny won’t work; STUN/XOR-MAPPED-ADDRESS answers reflect the agent’s socket, so server-reflexive candidates are wrong—point clients at a separate STUN server. Keep idle_timeout_secs at or above coturn’s allocation lifetime (~300s+) so a quiet allocation isn’t reaped between refreshes. TCP TURN (3478/tcp) rides the regular TCP service support. ```bash TOWONEL_AGENT_UDP_SERVICES='[ {"name":"turn", "origin":"10.0.0.5:3478", "listen_port":3478, "idle_timeout_secs":300}, {"name":"turn-relay", "origin":"10.0.0.5", "listen_port_range":[49160,49660], "idle_timeout_secs":600} ]' ``` ```ini listening-port=3478 min-port=49160 max-port=49660 external-ip= realm=turn.example.eu ``` -------------------------------- ### Configure ACME staging and cert directory Source: https://towonel.dev/docs/self-hosted/hub/docker Environment variables to enable ACME staging mode, override the certificate cache directory, and optionally set a custom ACME directory URL. Use staging while testing to avoid rate limits; these settings do not apply to the bundled-Caddy variant. ```bash -e TOWONEL_HUB_TLS_ACME_STAGING=true -e TOWONEL_HUB_TLS_CERT_DIR=/data/acme # -e TOWONEL_HUB_TLS_ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory ``` -------------------------------- ### Docker Compose configuration for Towonel agent Source: https://towonel.dev/docs/agent/docker Docker Compose service definition for the Towonel agent. Uses host networking, sets the invite token from an environment variable, and configures the agent services. ```yaml services: towonel-agent: image: git.ow-ops.eu/towonel/towonel-agent:latest network_mode: host restart: unless-stopped environment: RUST_LOG: info TOWONEL_INVITE_TOKEN: ${TOWONEL_INVITE_TOKEN} TOWONEL_AGENT_SERVICES: | [{"hostname":"app.example.dev","origin":"127.0.0.1:8080"}] ``` -------------------------------- ### Enable PROXY v2 on the edge Source: https://towonel.dev/docs/self-hosted/reverse-proxy Environment variables to enable PROXY v2 on the edge. Once enabled, every TCP connection must use PROXY v2 and come from a trusted source; otherwise it is dropped. Keep the listen address off the public internet. ```bash TOWONEL_EDGE_LISTEN_ADDR=0.0.0.0:8444 TOWONEL_EDGE_PROXY_PROTOCOL=true # Optional — defaults to RFC1918 + loopback TOWONEL_EDGE_PROXY_PROTOCOL_TRUSTED=10.0.0.0/8,172.16.0.0/12 ``` -------------------------------- ### Enable optional HTTP listener Source: https://towonel.dev/docs/self-hosted/edge/tuning Disabled unless set. Adds a plain-HTTP listener for Host-header routing and ACME HTTP-01. ```bash TOWONEL_EDGE_HTTP_LISTEN_ADDR=0.0.0.0:80 ``` -------------------------------- ### Configure Towonel Hub with multiple Postgres replicas Source: https://towonel.dev/docs/self-hosted/hub/kubernetes Helm values for deploying Towonel Hub with multiple Postgres replicas. Disables the edge controller, sets replica count to 2, and configures the Postgres DSN with mTLS certificates mounted from secrets. Leader election is on by default; when the main DSN points at a pooler, set TOWONEL_HUB_LEADER_DB_DSN to the primary directly. ```yaml spec: values: global: fullnameOverride: towonel-hub edge: enabled: false controllers: main: replicas: 2 annotations: reloader.stakater.com/auto: "true" containers: main: env: TOWONEL_HUB_PUBLIC_URL: https://hub.example.eu TOWONEL_HUB_DB_DRIVER: postgres TOWONEL_HUB_DB_DSN: >- postgresql://towonel_hub@pg-pooler-rw.towonel.svc:5432/towonel_hub?sslmode=verify-full&sslcert=/var/run/secrets/postgresql/tls.crt&sslkey=/var/run/secrets/postgresql/tls.key&sslrootcert=/var/run/secrets/root-ca/ca.crt envFrom: - secretRef: { name: towonel-hub-secret } persistence: postgres-certs: type: secret name: postgres-towonel-hub-cert globalMounts: - path: /var/run/secrets/postgresql root-ca: type: secret name: root-ca globalMounts: - path: /var/run/secrets/root-ca ``` -------------------------------- ### Configure OIDC login with Codeberg Source: https://towonel.dev/docs/self-hosted/web-console Environment variables for OIDC login using Codeberg as the provider. TOWONEL_HUB_OIDC_CODEBERG_ISSUER, CLIENT_ID, CLIENT_SECRET, and REDIRECT_URI are required. TOWONEL_HUB_OIDC_CODEBERG_TRUST_EMAIL_VERIFIED is off by default and should only be enabled for a provider whose email_verified claim is trusted. ```bash -e TOWONEL_HUB_OIDC_CODEBERG_ISSUER=https://codeberg.org -e TOWONEL_HUB_OIDC_CODEBERG_CLIENT_ID=... -e TOWONEL_HUB_OIDC_CODEBERG_CLIENT_SECRET=... -e TOWONEL_HUB_OIDC_CODEBERG_REDIRECT_URI=https://console.example.eu/api/v1/auth/oidc/codeberg/callback ``` -------------------------------- ### Reach a device by name with ssh Source: https://towonel.dev/docs/mesh Reach another device by name when mesh up has root or CAP_NET_ADMIN privileges. Creates a towonel0 interface, assigns IPv4 from 100.64.0.0/10 and IPv6 from the tunnel's /48, and resolves names via systemd-resolved. ```bash ssh nas.towonel.internal ``` -------------------------------- ### towonel entry submit --op upsert-hostname Source: https://towonel.dev/docs/self-hosted/operations Agent-side command to submit a hostname upsert for a tenant. ```bash # from the agent side towonel entry submit --op upsert-hostname --hostname new.alice.example.eu ``` -------------------------------- ### Forward ports with towonel mesh connect and nc Source: https://towonel.dev/docs/mesh Forward ports when you lack root or CAP_NET_ADMIN. The first command listens on 127.0.0.1:5432 for the nas service; the second uses towonel mesh nc as an SSH ProxyCommand. ```bash towonel mesh connect nas:5432 # listens on 127.0.0.1:5432 ssh -o ProxyCommand="towonel mesh nc %h %p" nas ``` -------------------------------- ### towonel tenant remove and tenant leave commands Source: https://towonel.dev/docs/self-hosted/operations Operator cleanup commands to remove a tenant from the hub or have the tenant leave. The tenant-side command requires the tenant key and hub URL. ```bash towonel tenant remove --tenant-id # or, tenant-side towonel tenant leave --key-path tenant.key --hub-url https://hub.example.eu:8443 ``` -------------------------------- ### OCIRepository for towonel-agent chart Source: https://towonel.dev/docs/agent/kubernetes Flux OCIRepository that pins the towonel-agent Helm chart to a published release by tag. The chart is published to oci://git.ow-ops.eu/towonel/charts/towonel-agent and ships a values.schema.json. ```yaml apiVersion: source.toolkit.fluxcd.io/v1 kind: OCIRepository metadata: name: towonel-agent namespace: network spec: interval: 15m layerSelector: mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip operation: copy ref: tag: url: oci://git.ow-ops.eu/towonel/charts/towonel-agent ``` -------------------------------- ### OIDC and Mail Environment Configuration Source: https://towonel.dev/docs/self-hosted/hub/kubernetes Environment variables for enabling OIDC login via Codeberg and transactional mail. Requires TOWONEL_HUB_PUBLIC_URL and mail config; OIDC adds the redirect URI and optional client ID/secret and Mailjet settings via envFrom. ```yaml env: TOWONEL_HUB_OIDC_CODEBERG_REDIRECT_URI: https://console.example.eu/api/v1/auth/oidc/codeberg/callback # TOWONEL_HUB_OIDC_CODEBERG_CLIENT_ID/SECRET, TOWONEL_MAIL_MAILJET_* via envFrom ``` -------------------------------- ### Docker env for privileged ports Source: https://towonel.dev/docs/self-hosted/operations Set TOWONEL_HUB_ALLOW_PRIVILEGED_PORTS=true to allow TCP/UDP listen ports below 1024 on the hub. ```bash -e TOWONEL_HUB_ALLOW_PRIVILEGED_PORTS=true ``` -------------------------------- ### Generate shared PSK with openssl Source: https://towonel.dev/docs/self-hosted/federation Generates a 32-byte random hex PSK and writes it to hub.link.psk. This PSK must match on both hub and edges. ```bash openssl rand -hex 32 > hub.link.psk ``` -------------------------------- ### HAProxy frontend/backend with PROXY v2 Source: https://towonel.dev/docs/self-hosted/reverse-proxy HAProxy configuration that routes TLS SNI ending with .example.eu to the edge using send-proxy-v2. ```haproxy frontend tls_in bind :443 mode tcp tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 } use_backend towonel if { req_ssl_sni -m end .example.eu } backend towonel mode tcp server edge 127.0.0.1:8444 send-proxy-v2 ``` -------------------------------- ### DNSEndpoint for towonel-agent Source: https://towonel.dev/docs/agent/kubernetes DNSEndpoint that creates an A record for app.example.dev pointing to 203.0.113.10, used for the towonel-agent edge. ```yaml apiVersion: externaldns.k8s.io/v1alpha1 kind: DNSEndpoint metadata: name: towonel-agent spec: endpoints: - dnsName: app.example.dev recordType: A targets: ["203.0.113.10"] ``` -------------------------------- ### Custom policy rule for exit node access with internet in to Source: https://towonel.dev/docs/mesh/exit-nodes Custom policy rule that allows devices to use an approved exit. The 'to' field must include 'internet'. The wildcard '*' does not include 'internet', so existing rules never grant it by accident. ```json { "from": ["*"], "to": ["internet"] } ``` -------------------------------- ### relay.toml for Docker with LetsEncrypt Source: https://towonel.dev/docs/self-hosted/relay relay.toml configuration for the Docker deployment. Uses LetsEncrypt for TLS with automatic certificate management. ```toml enable_quic_addr_discovery = true http_bind_addr = "0.0.0.0:8080" [tls] hostname = "relay.example.eu" cert_mode = "LetsEncrypt" cert_dir = "/data/certs" contact = "ops@example.eu" https_bind_addr = "0.0.0.0:8443" quic_bind_addr = "0.0.0.0:7842" prod_tls = true ``` -------------------------------- ### Print hub CAA record via CLI Source: https://towonel.dev/docs/agent/caa-pinning CLI command that prints the same CAA record line ready to paste. ```shell towonel acme account ``` -------------------------------- ### Configure Mailjet transactional mail Source: https://towonel.dev/docs/self-hosted/web-console Environment variables for Mailjet transactional mail. TOWONEL_MAIL_MAILJET_API_KEY and TOWONEL_MAIL_MAILJET_API_SECRET are required, TOWONEL_MAIL_FROM_EMAIL and TOWONEL_MAIL_FROM_NAME set the sender, and TOWONEL_MAIL_SANDBOX=true routes to Mailjet's sandbox without delivery. ```bash -e TOWONEL_MAIL_MAILJET_API_KEY=... -e TOWONEL_MAIL_MAILJET_API_SECRET=... -e TOWONEL_MAIL_FROM_EMAIL=no-reply@example.eu -e TOWONEL_MAIL_FROM_NAME=Towonel -e TOWONEL_MAIL_SANDBOX=false # true routes to Mailjet's sandbox (no delivery) ``` -------------------------------- ### HelmRelease for hub-only SQLite deployment Source: https://towonel.dev/docs/self-hosted/hub/kubernetes HelmRelease for a hub-only deployment with SQLite and a PVC. Disables the edge, sets replicas to 1, mounts the PVC at /data via TOWONEL_DATA_DIR, and references a secret for envFrom. The hub API listens on 8443, the hub-edge link on 51444, and metrics on 9091; probes target /v1/health and /v1/readyz automatically. ```yaml apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: towonel-hub namespace: towonel spec: chartRef: { kind: OCIRepository, name: towonel-node } interval: 30m values: global: fullnameOverride: towonel-hub edge: enabled: false controllers: main: replicas: 1 annotations: reloader.stakater.com/auto: "true" containers: main: env: TOWONEL_DATA_DIR: /data TOWONEL_HUB_PUBLIC_URL: https://hub.example.eu envFrom: - secretRef: { name: towonel-hub-secret } persistence: data: enabled: true type: persistentVolumeClaim accessMode: ReadWriteOnce size: 1Gi globalMounts: - path: /data ``` -------------------------------- ### HelmRelease for towonel-edge Source: https://towonel.dev/docs/self-hosted/edge/kubernetes Configures the towonel-edge HelmRelease with hub disabled, edge bind addresses, and environment variables for hub-link, iroh, advertised addresses, proxy protocol, and listen workers. Uses an ExternalSecret for the hub-link PSK. ```yaml apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: towonel-edge namespace: towonel spec: chartRef: kind: OCIRepository name: towonel-node interval: 30m values: global: fullnameOverride: towonel-edge hub: enabled: false edge: bindAddress: 0.0.0.0 httpsPort: 8444 defaultPodOptions: tolerations: - operator: Exists controllers: main: annotations: reloader.stakater.com/auto: "true" containers: main: env: TOWONEL_EDGE_HUB_LINK_ADDR: towonel-hub.towonel.svc.cluster.local:51444 TOWONEL_EDGE_IROH_PORT: "51820" TOWONEL_EDGE_ADVERTISED_ADDRESSES: edge-eu.example.eu:443 TOWONEL_EDGE_PROXY_PROTOCOL: "true" TOWONEL_EDGE_LISTEN_WORKERS: "4" envFrom: - secretRef: { name: towonel-edge-secret } ``` -------------------------------- ### Docker env for UDP port range cap Source: https://towonel.dev/docs/self-hosted/operations Set TOWONEL_HUB_MAX_UDP_PORT_RANGE=512 to cap the size of a contiguous UDP port range a tenant may claim in one binding. ```bash -e TOWONEL_HUB_MAX_UDP_PORT_RANGE=512 ``` -------------------------------- ### relay.toml for Kubernetes with Reloading certs Source: https://towonel.dev/docs/self-hosted/relay relay.toml for the Kubernetes DaemonSet. Uses cert_mode = "Reloading" to pick up renewed certs without a restart, with manual cert paths pointing to the mounted secret. ```toml # mounted at /etc/iroh-relay/relay.toml enable_quic_addr_discovery = true http_bind_addr = "0.0.0.0:8080" [tls] hostname = "relay.example.eu" cert_mode = "Reloading" manual_cert_path = "/tls/tls.crt" manual_key_path = "/tls/tls.key" https_bind_addr = "0.0.0.0:8443" quic_bind_addr = "0.0.0.0:7842" ``` -------------------------------- ### Docker Compose service for iroh-relay Source: https://towonel.dev/docs/self-hosted/relay Docker Compose service for the iroh relay. Uses host networking, mounts the relay.toml config read-only, and persists data in a named volume. ```yaml services: iroh-relay: image: docker.io/n0computer/iroh-relay:1.0.0-rc.0 network_mode: host restart: unless-stopped command: ["--config-path", "/etc/iroh-relay/relay.toml"] volumes: - ./relay.toml:/etc/iroh-relay/relay.toml:ro - iroh-relay-data:/data volumes: iroh-relay-data: ``` -------------------------------- ### Caddy layer4 with PROXY v2 Source: https://towonel.dev/docs/self-hosted/reverse-proxy Caddy layer4 configuration that routes TLS SNI matching *.example.eu to the edge with PROXY v2. The bundled-Caddy hub image includes this configuration. ```caddy { layer4 { :443 { @towonel tls sni *.example.eu route @towonel { proxy { proxy_protocol v2 upstream localhost:8444 } } } } } ``` -------------------------------- ### Enable PROXY protocol v2 with Envoy Gateway Source: https://towonel.dev/docs/agent/tls-modes Envoy Gateway configuration to accept PROXY protocol v2 headers in passthrough mode. The origin must accept the PROXY protocol or the connection will fail. ```yaml apiVersion: gateway.envoyproxy.io/v1alpha1 kind: ClientTrafficPolicy metadata: name: envoy spec: proxyProtocol: optional: true ```