DoHzel Proxy Installation with Docker (Debian)#

Introduction#

This guide describes how to run DoHzel Proxy in a Debian-based Docker container. The container image downloads the official DoHzel Proxy binary for your host architecture (x64 or arm64), initializes configuration on first start, enrolls the instance, and runs the DNS server in the foreground.

All deployment files are bundled with this documentation in the scripts/ directory.

Quick download#

Download the four deployment files as a single archive:

dohzel-proxy-docker-debian.tar.gz

Extract and enter the directory on your Docker host:

mkdir dohzel-proxy-docker && cd dohzel-proxy-docker
tar xzf /path/to/dohzel-proxy-docker-debian.tar.gz

Then follow the steps below from that directory.

Deployment files#

File Purpose
dohzel-proxy-docker-debian.tar.gz Archive containing all files below
Dockerfile Debian-based image definition; downloads the proxy binary at build time
entrypoint.sh Initializes, enrolls, optionally joins a profile, then starts the server
env.template Template for optional profile enrollment at first start
prune.sh Stops the container, removes the data volume, and deletes the image

Copy these files to a working directory on your Docker host, or run the commands below from a checkout of this documentation repository.

Prerequisites#

On the Docker host:

  • Docker installed and running
  • Port 53/udp and 53/tcp available on the host, or an alternate host port mapped to container port 53
  • Outbound access to *.hafnova.com and download.hafnova.com

Configure enrollment#

From the directory containing the deployment files:

cp env.template .env

Edit .env and replace SETME with your profile enrollment code if you want the proxy to join a profile automatically on first start:

export PROFILE_TOKEN="YOUR_PROFILE_TOKEN"

If you leave PROFILE_TOKEN as SETME, the proxy enrolls without joining a profile. You can join a profile later with the CLI.

Note: .env is copied into the image at build time. Rebuild the image after changing it.

Build and run#

Build the image:

docker build -t dohzel-proxy .

Run the container with persistent configuration storage:

docker run -d \
  -p 53:53/udp \
  -p 53:53/tcp \
  -v dohzel-data:/root/.dohzel-proxy \
  --name my-dohzel \
  dohzel-proxy

On first start, the entrypoint script:

  1. Runs init if no configuration exists yet
  2. Runs enroll
  3. Runs profile join when PROFILE_TOKEN is set
  4. Starts server

Host port already in use#

If the host already runs a local DNS resolver on port 53, map a different host port:

docker run -d \
  -p 20053:53/udp \
  -p 20053:53/tcp \
  -v dohzel-data:/root/.dohzel-proxy \
  --name my-dohzel \
  dohzel-proxy

Test resolution against the mapped port:

nslookup duckduckgo.com -port=20053 127.0.0.1

Verify the installation#

Check container logs:

docker logs my-dohzel

Inspect proxy status inside the container:

docker exec my-dohzel bash -c '/usr/local/bin/dohzel-proxy.linux-*-latest.bin status'

Note the Rebound URL from the status output to manage the device in the DoHzel console.

Further configuration#

Runtime settings use the same CLI commands as a native Linux install. Run them inside the container, for example:

docker exec -it my-dohzel bash -c '/usr/local/bin/dohzel-proxy.linux-*-latest.bin profile join YOUR_CODE'
docker exec -it my-dohzel bash -c '/usr/local/bin/dohzel-proxy.linux-*-latest.bin mode DNS2eDOH'

Configuration is persisted in the dohzel-data Docker volume.

Remove the installation#

Run the bundled cleanup script from the deployment directory:

chmod +x prune.sh
./prune.sh

This removes enrollment data stored in the dohzel-data volume. Back up the volume first if you need to keep the device identity.