Technitium DNS Companion - Getting Started Guide¶
Getting started is quick and easy with Docker (or an equivalent container runtime). Just a few environment variables are needed to connect to your Technitium DNS nodes.
Getting Started (2-minute path)¶
Option A: One-command quickstart (recommended)¶
You don't need to clone the repo. Download the script and run it from the host where you want to run the container:
- macOS/Linux:
curl -fsSL https://raw.githubusercontent.com/Fail-Safe/Technitium-DNS-Companion/main/scripts/docker-quickstart.sh -o docker-quickstart.sh
chmod +x docker-quickstart.sh
./docker-quickstart.sh
- Windows PowerShell:
iwr https://raw.githubusercontent.com/Fail-Safe/Technitium-DNS-Companion/main/scripts/docker-quickstart.ps1 -OutFile docker-quickstart.ps1
powershell -ExecutionPolicy Bypass -File .\docker-quickstart.ps1
- What the script does:
- Verifies Docker is running
- Downloads
.env.exampleintotechnitium.envif missing - Pulls the selected image first (so
:lateststays current) - Shows the exact
docker runcommand and can run it for you -
Prompts to confirm HTTP/HTTPS ports before running (must be different; it will re-prompt if you choose the same port)
-
If
technitium.envdidn’t exist, the script will create it and exit so you can edit it. - After editing
technitium.env, rerun the script and press Enter to launch (any other key cancels).
Option B: Manual docker run (no clone required)¶
Runs the single container that serves both the API and built frontend. Use this if you prefer to type the command yourself.
-
Prepare environment:
-
Download
.env.example(or copy it from a clone) and save astechnitium.env. - Minimum variables:
TECHNITIUM_NODES=node1,node2TECHNITIUM_<NODE>_BASE_URLfor each node.- Required for interactive UI access (v1.4+): Technitium login/RBAC (session auth).
- Recommended for background features in session-auth mode:
TECHNITIUM_BACKGROUND_TOKEN(least-privilege, read-only). - Legacy only (Technitium DNS < v14 / migration): env-token mode using
TECHNITIUM_<NODE>_TOKEN. -
Optional: set
TZ,CORS_ORIGINS, and HTTPS variables. -
Run the container:
docker run --rm -p 3000:3000 -p 3443:3443 \
--env-file technitium.env \
-v technitium-dns-companion-data:/data \
ghcr.io/fail-safe/technitium-dns-companion:latest
Notes on persistence (/data volume):
-v technitium-dns-companion-data:/datais recommended. It is used for caches and optional on-disk features.- If you enable the optional SQLite rolling query-log store, set
QUERY_LOG_SQLITE_PATHto a path under/dataso stored logs survive container restarts. - DNS Filtering History snapshots can also be stored under
/data(see.env.example/DNS_FILTERING_SNAPSHOT_DIR).
Optional: Enable SQLite rolling query logs storage (accuracy for “Last 24h” presets)
- In
technitium.env:
QUERY_LOG_SQLITE_ENABLED=true
QUERY_LOG_SQLITE_PATH=/data/query-logs.sqlite
QUERY_LOG_SQLITE_RETENTION_HOURS=24
QUERY_LOG_SQLITE_POLL_INTERVAL_MS=10000
QUERY_LOG_SQLITE_OVERLAP_SECONDS=60
QUERY_LOG_SQLITE_MAX_ENTRIES_PER_POLL=20000
-
With session auth (v1.4+: always enabled for interactive UI), ingestion runs as a background task and requires
TECHNITIUM_BACKGROUND_TOKEN(least-privilege token that can read query logs). Without it, the DB may exist but will not stay up to date. -
Direct access defaults to automatically generated self-signed HTTPS: https://localhost:3443
-
HTTP on port 3000 is intended for a trusted host-based TLS reverse proxy (
TRUST_PROXY=true). -
Use a trusted HTTPS certificate (optional):
-
Place certs locally:
certs/
├── fullchain.pem
└── privkey.pem
- In
technitium.env, set:
HTTPS_ENABLED=true
HTTPS_PORT=3443
HTTPS_CERT_PATH=/app/certs/fullchain.pem
HTTPS_KEY_PATH=/app/certs/privkey.pem
# HTTPS_CA_PATH=/app/certs/chain.pem # (optional) Specify if you have a separate CA file
- Mount certs when running:
docker run --rm -p 3000:3000 -p 3443:3443 \
--env-file technitium.env \
-v technitium-dns-companion-data:/data \
-v $(pwd)/certs:/app/certs:ro \
ghcr.io/fail-safe/technitium-dns-companion:latest
-
For Windows PowerShell, use
${PWD}\certsfor the host path. -
Operations:
-
Logs:
docker logs -f <container-id>(if run without--rm, add--name tdcthendocker logs -f tdc) - Restart (named container):
docker restart tdc - Upgrade image:
docker pull ghcr.io/fail-safe/technitium-dns-companion:latest
Option C: docker compose (from a repo clone)¶
Use this if you’ve cloned the repo and prefer compose for repeatability or dev overrides. The included file requires Docker Compose 2.24 or later for optional environment-file overlays.
-
Copy
.env.exampleto.envand set your variables..env.exampleis the complete, commented configuration reference, so the available settings are documented locally without needing this guide open. Compose loads it first for backward-compatible defaults, then overlays values from.env. The user file is optional to Compose so existing deployments that configure the service another way continue to start. -
Start the published image. Compose creates the persistent
datadirectory if it does not already exist:
docker compose up -d
To build the checked-out source instead, use:
docker compose -f docker-compose.yml -f docker-compose.local-build.yml up -d --build
-
HTTPS: the default is persistent self-signed HTTPS on port 3443. For a trusted certificate, place certs in
certs/, set the HTTPS variables in.env, and uncomment the certificate mount indocker-compose.yml. For a host-based TLS reverse proxy, setTRUST_PROXY=true. Port 3000 retains its existing all-interface bind by default; setCOMPANION_HTTP_BIND=127.0.0.1when only a host-based reverse proxy should reach it. -
Operations:
-
Logs:
docker compose logs -f - Restart:
docker compose restart - Upgrade: run
git pull, thendocker compose up -d
Compose also limits the service's local json-file logs to three 10 MB files
by default. Use COMPANION_LOG_MAX_SIZE and COMPANION_LOG_MAX_FILES in
.env to tune those limits.
Opt into the beta channel¶
Set the image override in .env:
COMPANION_IMAGE=ghcr.io/fail-safe/technitium-dns-companion:beta
Then pull and recreate the service:
docker compose pull
docker compose up -d
The beta and next tags move with the next branch. Each published build
also has an immutable sha-<commit> tag. Record the revision shown in the
About dialog or inspect the image labels before reporting a problem:
docker image inspect "$COMPANION_IMAGE" \
--format '{{ index .Config.Labels "org.opencontainers.image.revision" }}'
To return to stable, change COMPANION_IMAGE back to
ghcr.io/fail-safe/technitium-dns-companion:latest, then run the same pull and
up commands. See the Beta Testing Guide for exact-build
pinning and rollback guidance.
Troubleshooting¶
- Container will not start:
docker compose logsthendocker compose configto validate env vars. - Port bind error ("port is already allocated"): pick different host ports (e.g.,
-p 1234:3000 -p 1235:3443) or stop the other container/service using that port. - Cannot connect to Technitium DNS nodes: Check URLs and tokens in
.env.
Health checks¶
The image health check probes https://127.0.0.1:<HTTPS_PORT>/api/health and
http://127.0.0.1:<PORT>/api/health from inside the container. Compose inherits
this image-level check.
- HTTPS is attempted first, then HTTP as fallback.
- The probe uses Node.js and does not require
wgetorcurlin the image.
Quick verification:
docker compose ps
docker inspect --format='{{json .State.Health}}' "$(docker compose ps -q technitium-dns-companion)" | jq
Post-upgrade permissions check (v1.4+)¶
Recent images run as a non-root user (node, uid/gid 1000). If older bind mounts or volumes contain root-owned files, startup or background tasks may fail with permission errors such as:
EACCES: permission denied, open /app/certs/...(HTTPS certs not readable)attempt to write a readonly database(SQLite query logs DB not writable)
Quick check inside the container:
docker exec -it <container> sh -lc 'id; ls -ld /app/certs /data /app/config; ls -l /app/certs 2>/dev/null || true; ls -l /data 2>/dev/null || true'
Recommended permissions:
- Certificate directories should be traversable/readable (commonly
755) - Certificate/key files should be readable by the container user (commonly
644) - SQLite DB path and related files (
.sqlite,-wal,-shm) should be writable by uid1000
Example remediation (adjust to your host paths/volume contents):
# Certs (host or volume content)
chmod 755 /path/to/certs /path/to/certs/certs
chmod 644 /path/to/certs/certs/*
# App state volume (from container as root, then restart)
docker exec -u 0 <container> sh -lc 'chown -R node:node /data'
docker restart <container>
Temporary workaround only: run the container as root while fixing file ownership, then switch back to non-root.
Docker Secrets / File-based Secrets¶
For production deployments, you can use Docker secrets or file-based secrets instead of
passing sensitive values directly as environment variables. The application supports the
common _FILE suffix pattern.
Supported Variables¶
| Environment Variable | File Variant |
|---|---|
TECHNITIUM_BACKGROUND_TOKEN |
TECHNITIUM_BACKGROUND_TOKEN_FILE |
TECHNITIUM_<NODE>_TOKEN |
TECHNITIUM_<NODE>_TOKEN_FILE |
When the _FILE variant is set, the application reads the secret from that file path.
The _FILE variant takes precedence if both are set.
Docker Swarm Example¶
- Create the secrets:
echo "your-background-token" | docker secret create technitium_background_token -
- Reference in your stack file:
version: "3.8"
services:
technitium-dns-companion:
image: ghcr.io/fail-safe/technitium-dns-companion:latest
environment:
TECHNITIUM_NODES: "node1,node2"
TECHNITIUM_NODE1_BASE_URL: "http://dns1.example.com:5380"
TECHNITIUM_NODE2_BASE_URL: "http://dns2.example.com:5380"
# Use _FILE variants for secrets
TECHNITIUM_BACKGROUND_TOKEN_FILE: /run/secrets/technitium_background_token
secrets:
- technitium_background_token
ports:
- "3000:3000"
volumes:
- companion-data:/data
secrets:
technitium_background_token:
external: true
volumes:
companion-data:
Kubernetes Example¶
- Create the secret:
kubectl create secret generic technitium-tokens \
--from-literal=background-token='your-background-token'
- Mount in your deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: technitium-dns-companion
spec:
template:
spec:
containers:
- name: companion
image: ghcr.io/fail-safe/technitium-dns-companion:latest
env:
- name: TECHNITIUM_NODES
value: "node1,node2"
- name: TECHNITIUM_BACKGROUND_TOKEN_FILE
value: /secrets/background-token
volumeMounts:
- name: secrets
mountPath: /secrets
readOnly: true
volumes:
- name: secrets
secret:
secretName: technitium-tokens
Per-Node Tokens¶
For legacy deployments with per-node tokens:
# Create secrets for each node
echo "node1-token" | docker secret create technitium_node1_token -
echo "node2-token" | docker secret create technitium_node2_token -
environment:
TECHNITIUM_NODE1_TOKEN_FILE: /run/secrets/technitium_node1_token
TECHNITIUM_NODE2_TOKEN_FILE: /run/secrets/technitium_node2_token
secrets:
- technitium_node1_token
- technitium_node2_token
Need contributor instructions? See DEVELOPMENT.md.