All posts

Dozzle on a VPS: logs for the running stack

Dozzle v11.4.1: 8080 only on 127.0.0.1, simple auth, one live log stream, Caddy. Idle 19.8 MiB.

Written by NodeRings Inc.

NodeRings Inc. writes these notes. The company runs the marketplace and the agent that stays on the provider’s side of the hypervisor.

Dozzle v11.4.1 held 19.8 MiB idle on this lab host after simple auth was on and one live log stream had been opened for an already-running container. That is cgroup memory.current, the median of twenty samples taken 30 seconds apart with a quiet UI. docker stats printed 19.8 MiB. CPU percent sat at 0.77. Port 8082 listened on 127.0.0.1 only on this lab (host 8080 was taken). A curl to the guest's LAN address on that port was refused. Use 127.0.0.1:8080:8080 when 8080 is free.

Dozzle is a real-time Docker log viewer in the browser. It tails container stdout/stderr with a searchable UI, multi-container views, and optional swarm support. You use it when docker logs -f across five services is too clumsy and a full Loki/ELK stack is too heavy for a single VPS. Because it mounts the Docker socket, it can see every container the daemon can see.

The getting started guide publishes 8080:8080, mounts docker.sock and /data, and leaves authentication off. Competing guides stop when the container table loads. Pin v11.4.1 by digest, bind the port to loopback, turn on DOZZLE_AUTH_PROVIDER=simple with a generated users.yml, open live logs for one container from the stack, leave actions and shell off, and put Caddy on 443.

Mounting docker.sock gives Dozzle the same control as root on the host, so simple auth and the loopback bind belong in the first install.

ReadingValue
cgroup memory.current19.8 MiB, median of 20
docker stats19.8 MiB
CPU percent0.77, median
Host listener127.0.0.1:8082 (lab) / 127.0.0.1:8080 (post)
After proofLogin required; whoami-lab log stream open
Imageamir20/dozzle:v11.4.1
Skip thisWhat this run did
8080:8080 on every interfacePublished 127.0.0.1:8080:8080
Auth left off on a public IPDOZZLE_AUTH_PROVIDER=simple + users.yml
Floating latestPinned v11.4.1 by digest
Stopping at the container tableOpened live logs for whoami-lab
Enabling actions / shell by defaultLeft both unset
Opening 8080 on the panel firewallLeft the app port closed; Caddy on 80/443
Bar chart. Idle cgroup memory.current 19.8 MiB and docker stats 19.8 MiB for Dozzle v11.4.1.
Idle after simple auth and one live log view. Merged multi-container streams sit above this.

How do you install Dozzle on Docker?

The image is amir20/dozzle:v11.4.1, digest sha256:915a5acf91b01bb4d11de1fde7e30d55646211240269e4404c03a6f71c5fc91e. Generate a users.yml before the first up:

mkdir -p ~/dozzle/data
cd ~/dozzle
docker run -i --rm amir20/dozzle:v11.4.1 generate labadmin \
  --email [email protected] --name "Lab Admin" > data/users.yml
# paste password on stdin, or: echo "$PASSWORD" | docker run -i --rm …
chmod 600 data/users.yml
services:
  dozzle:
    image: amir20/dozzle:v11.4.1@sha256:915a5acf91b01bb4d11de1fde7e30d55646211240269e4404c03a6f71c5fc91e
    container_name: dozzle
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      DOZZLE_AUTH_PROVIDER: simple
      DOZZLE_HOSTNAME: vps
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/data
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

Leave DOZZLE_ENABLE_ACTIONS and DOZZLE_ENABLE_SHELL out of the file until you need stop, start, or exec from the browser. Log rotation matches the Compose checklist.

docker compose up -d
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/

A working process redirects to /login (often 307) when simple auth is on.

docker-compose.yml for Dozzle v11.4.1 with 127.0.0.1:8080:8080, DOZZLE_AUTH_PROVIDER simple, docker.sock and data mounts.
Pinned digest, loopback publish, simple auth, actions and shell left off.

How should you harden and use Dozzle day to day?

Keep actions and shell features off unless you intentionally want restart/stop from the UI; a compromised session with actions on is remote root via the socket (Dozzle security notes). Simple auth with a strong password (or forward-auth / Authentik) is the minimum. A :ro mount of docker.sock does not make the API read-only (OWASP Docker cheat sheet); for log-only access put tecnativa/docker-socket-proxy in front with CONTAINERS=1, INFO=1, and POST=0. Never expose Dozzle’s port in forward-proxy mode without the proxy: Dozzle trusts Remote-User and grants all roles if no roles header is present. Filter noise with the UI search; /data holds users and settings for backups.

If you run many hosts, prefer Dozzle agents over legacy remote hosts. Pair with Dockge for Compose edits and keep log viewing separate from stack mutation when you can.

Why must the port stay on loopback?

Anyone who reaches Dozzle with docker.sock mounted can read every container's logs. With actions or shell on, that same person can change containers. Publishing 8080 on every interface puts the UI on the internet without TLS.

ss -H -lntup | grep 8080

On this lab host the publish was 127.0.0.1:8082. Curl to the guest LAN address failed with connection refused. Leave the app port closed in the panel firewall. Open 80 and 443 for Caddy. Docker published ports often bypass UFW inside the guest, so the loopback bind kept the LAN address quiet. The public-address case is in provider-side firewall.

ss showing LISTEN on 127.0.0.1 only for the Dozzle publish, and curl to the LAN address refused.
Host view of the publish. The process inside still binds container port 8080.

How do you turn on simple auth?

DOZZLE_AUTH_PROVIDER=simple reads users.yml from /data. The generate command writes bcrypt hashes. Open http://127.0.0.1:8080 (or the tunnel) and sign in with the username you generated. Crop the password from screenshots.

ssh -N -L 8080:127.0.0.1:8080 user@YOUR_VPS_IP

Forward-proxy auth (Authentik, Authelia) passes Remote-User, and Dozzle trusts that header when the proxy is the only gate. Keep the container off the public interface in that setup.

Dozzle Authentication Required page with Username, Password, and Login.
Simple auth login. Crop the password.

What does one live log stream prove?

Pick a container that already runs on the VPS. This lab opened whoami-lab and hit its loopback URL a few times so new access lines appeared in the stream. The sidebar listed the rest of the stack under the hostname label. Seeing those other containers means Dozzle is attached to the host Docker engine.

Merged streams and SQL search can wait, since one named container with scrolling lines is the install check.

Dozzle log view for whoami-lab showing streaming HTTP access lines and container metrics.
Live whoami-lab logs after login. Other lab containers stay in the sidebar.

Where does Caddy go?

logs.example.com {
	reverse_proxy 127.0.0.1:8080
}

TLS setup is in the Caddy HTTPS post. Put Dozzle on a hostname and skip a path prefix.

Caddyfile site block reverse_proxy to 127.0.0.1:8080 for logs.example.com.
Public HTTPS on 443. Dozzle stays on loopback.

How do you back up data?

/data holds users.yml, session material, and settings. Stop the container, archive data/, start again:

docker compose stop dozzle
tar -C ~/dozzle -czf dozzle-data.tgz data
docker compose start dozzle

On this lab the archive was under 1 KB for a fresh users file and session secret. Point Restic at that tarball.

Stop Dozzle, tar data into dozzle-data.tgz, start again.
Stopped copy of data/. Regenerate users.yml if you lose the file.

What belongs in Dozzle vs elsewhere?

Use Dozzle for “what is this container saying right now?” Use journald or a log shipper for weeks of history. Filter by container name when a compose project is noisy. Dark theme and wrap settings are local preferences. If the UI is blank behind Cloudflare, check WebSockets and Rocket Loader the same way code-server docs warn. Revoke simple-auth passwords by regenerating users.yml and recreating the container.

FAQ

Is :ro on docker.sock enough? A read-only mount passes Docker API calls through the socket. Use a socket proxy for an allow-list. The security notes cover that.

Actions and shell? Leave both out of the compose file. Either flag lets the UI stop, start, or exec into containers.

Dozzle or Dockge? Dockge edits Compose stacks in the browser. Dozzle streams logs and stats for containers that are already running.

Multi-host? Remote agents are optional. This install uses one VPS and one docker.sock.

Does UFW block a published 8080? Inside the guest, published Docker ports often bypass UFW. Bind 127.0.0.1:8080:8080 and leave 8080 closed on the panel firewall.