Releases: heyvaldemar/dozzle-traefik-letsencrypt-docker-compose
Release list
v2.0.6
Fixed
- CI had never run the restore script. The test restored with its own
copy of the commands. The script readDATA_PATHandDATA_BACKUPS_PATH
from the shell that ran it rather than from.envor the stack, so a path
set in.envwas not the one it listed or cleared, and it cleared with
rm -rf dir/*, which leaves every dotfile of the newer state in place. It
now takes every path and name from the running backups container, accepts
the backup file name as an argument, starts the application again whatever
happens, and CI runs it: a file written before a backup and deleted after it
must be back once that backup is restored.
Changed
- The freshness check has its own workflow, Pin Freshness. It ran inside Deployment Verification, whose badge is the one at the top of this README. Across the fleet, nine red runs in ten were a pin one version behind - which the fleet's triage moves within the day - and a reader cannot tell that from a stack that does not boot. The badge now says whether the stack boots. The job itself is unchanged.
v2.0.5
Changed
amir20/dozzle:v11.1.0moved toamir20/dozzle:v11.1.1. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.
Security
traefik:3.7was rebuilt upstream; the pin moved fromsha256:1c32e7c36820…tosha256:24841fe2de73…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.
Upgrading
git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.
Full history in CHANGELOG.md.
What upstream changed
Read by fleet triage from the upstream release notes (or the commits between the tags) against this compose file, before the bump was applied.
Upstream changes v11.1.0 -> v11.1.1
Verdict: SAFE TO APPLY — a features/bug-fix/performance release with no breaking changes, no new or renamed variables, and no companion-service version dependency (Dozzle only talks to the Docker daemon via the socket proxy already pinned in this compose file).
Breaking changes
- none found in the notes
Variables
- none. No entry in the release notes adds, renames or removes an environment variable.
DOZZLE_AUTH_OIDC_SCOPESis mentioned as a new feature ("Add DOZZLE_AUTH_OIDC_SCOPES to request extra OIDC scopes") but it is optional and only relevant if OIDC auth is in use; this template usesDOZZLE_AUTH_PROVIDER=simpleby default, so it does not apply to the default configuration and needs no.env.examplechange to stay working.
Data and dependencies
- none. The proxy contract this template depends on (
GET /containers/json,GET /info,EVENTS,PING,VERSION, log streaming,POSTdenied) is unaffected — none of the fixes ("Harden container store", "Discard a stale host refresh", "Read Podman's health status off the wire") change the set of Docker API endpoints Dozzle calls against thedockerproxyallow-list. - No database or cache is involved in this stack; the only companion service Dozzle talks to is
dockerproxy, which stays at its current pin (v0.5.0) and is unaffected by this release.
Before applying
- Bump the pin:
DOZZLE_IMAGE_VERSION=v11.1.1(or update thex-imagesdefault in the compose file) and update the accompanying digest. - No data migration, no config edit, no manual command. Take the routine backup you'd take before any bump (the
backupsservice already covers/data), thendocker compose pull && docker compose up -d. - If OIDC auth is in use, review whether
DOZZLE_AUTH_OIDC_SCOPESshould be set — otherwise skip.
Notes read
- v11.1.1 (2026-09-20), covering the range v11.1.0...v11.1.1, as pasted above. No UPGRADING/BREAKING_CHANGES/CHANGELOG section was supplied for this range.
v2.0.4
Security
alpine:3.22was rebuilt upstream; the pin moved fromsha256:365499d9dccb…tosha256:5291449c3df7…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.
Upgrading
git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.
Full history in CHANGELOG.md.
v2.0.3
Security
traefik:3.7was rebuilt upstream; the pin moved fromsha256:f86a2cab1b5c…tosha256:1c32e7c36820…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.alpine:3.22was rebuilt upstream; the pin moved fromsha256:14358309a308…tosha256:365499d9dccb…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.
Upgrading
git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.
Full history in CHANGELOG.md.
v2.0.2
Changed
amir20/dozzle:v11.0.1moved toamir20/dozzle:v11.1.0. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.
Upgrading
git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.
Full history in CHANGELOG.md.
v2.0.1
Dozzle v11.0.1, and the version line put back in order.
Two releases were cut for this repository within the hour: v2.0.0 for Dozzle v11, and v1.0.2 by fleet triage for v11.0.1 on top of it. Triage took the next version from the latest GitHub release rather than the highest tag, and v2.0.0 was a tag with no release page, so it was invisible to it.
The newer content ended up carrying the lower version. update.sh sorts tags, so it would have offered a deployed host v2.0.0 and then told it that it was current. This release puts the highest tag back on the newest content.
v1.0.2 stays where it is. It was published and somebody may be holding it; deleting a released tag to tidy a number is not worth the one person it breaks. The fix is in fleet-ops, which now follows the highest tag.
And a stale command in a refusal
The hash-generation command that init-auth prints when it refuses to start still named v11.0.0 while the pin had moved to v11.0.1, as did .env.example in three places. A refusal that tells somebody to run a command against a version they are not deploying is a refusal that wastes their evening. Every place that names the version moves with the pin now.
Upgrading: ./update.sh.
v2.0.0
Dozzle v11.
A major upstream release: the interface is redesigned, GitHub and OIDC sign-in are added, and the session token changed.
Everyone is signed out once after this upgrade. That is the whole of the user-visible disruption, and it is why this is a major here rather than a minor. Nobody loses access; they log in again.
The authentication contract is unchanged, and that was checked
users.yml is still the access allowlist, password login still works, and docker run amir20/dozzle:v11.0.0 generate still produces the same file, now with two additional optional fields (github and roles) that an existing file does not need. The DOZZLE_ADMIN_USERNAME and DOZZLE_ADMIN_PASSWORD_HASH path is untouched.
The new sign-in providers are opt-in and this template configures none of them, so a deployment that says nothing about GitHub or OIDC behaves exactly as it did.
Every reference to the old version moved with the pin, including the hash-generation command that init-auth prints when it refuses to start. A refusal that tells somebody to run a command against a version they are not deploying is a refusal that wastes their evening.
Upgrading: ./update.sh --allow-major, then log in again.
v1.0.2
Changed
amir20/dozzle:v11.0.0moved toamir20/dozzle:v11.0.1. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.
Upgrading
git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.
Full history in CHANGELOG.md.
What upstream changed
Read by fleet triage from the upstream release notes (or the commits between the tags) against this compose file, before the bump was applied.
Upstream changes v11.0.0 -> v11.0.1
Verdict: SAFE TO APPLY — the notes contain only new features, UI redesign, and bug fixes; no breaking changes, no new/renamed variables, and no companion service version requirements appear.
Breaking changes
- none found in the notes
Variables
- none
Data and dependencies
- none — no database, cache, or search engine version requirements appear in the notes. The image talks to the Docker daemon through
dockerproxy(docker-socket-proxy:v0.5.0), which is unaffected by anything in this release.
Before applying
- Bump the pin in the compose file:
${DOZZLE_IMAGE_VERSION:-v11.0.0@sha256:...}→v11.0.1@<new digest>, or setDOZZLE_IMAGE_VERSION=v11.0.1(with the correct digest) in.envif overriding. - Update the digest, not just the tag — the compose file pins by
tag@sha256, so the new release's actual digest must be substituted. - No config, auth, or proxy allow-list changes are needed;
init-auth,dockerproxypermissions (CONTAINERS,EVENTS,PING,VERSION,INFO), and all.envvalues are unaffected by anything in these notes. - Restart normally (
docker compose up -d); no manual migration or backup step is indicated by the notes.
Notes read
- v11.0.1 (2026-09-12), compared against v11.0.0 via amir20/dozzle@v11.0.0...v11.0.1
v1.0.1
A CI fix. Nothing in the running stack changes.
The socket proxy is watched and scanned like every other pinned image
It was added as a fourth image and then left out of both the daily freshness check and the Trivy matrix. A pin nobody watches goes stale in silence — and this is the one container in the stack holding the Docker socket, which makes it the last image that should be scanned by nobody.
Both now cover it: the freshness job re-resolves its digest against the registry every day, and Trivy scans it on every build alongside the rest.
How it was found
By the fleet conformance rule that asserts every digest-pinned image has a freshness job behind it. The gap was invisible from inside this repository, where every build was green and every check passed — which is the point of running that rule across the fleet rather than inside each template.
Upgrading
./update.shNo variables changed, no data touched, no manual step.
v1.0.0
First release. A production deployment of Dozzle behind Traefik with automatic Let's Encrypt TLS, built to the fleet standard.
Dozzle answers one question — what actually broke? — without a log shipper, a storage backend or an index, because it streams from the Docker daemon rather than collecting anything. It is also the most dangerous container most people deploy, and it ships with two defaults that make it so. This template refuses both.
It will not start without authentication
DOZZLE_AUTH_PROVIDER defaults to none. None means an unauthenticated reader of every log line on the host — connection strings, tokens printed at startup, the bodies of failed requests — handed to whoever finds the hostname. Most compose files in circulation leave it there and publish the result.
Here the init container either builds users.yml from a hash in .env or stops the deploy before anything is listening:
ERROR: Dozzle would start with no authentication.
There is no /data/users.yml, and DOZZLE_ADMIN_USERNAME and
DOZZLE_ADMIN_PASSWORD_HASH are not both set in .env.
…
Generate the hash, then put both values in .env:
docker run --rm amir20/dozzle:v10.10.0 generate \
--name 'Your Name' --email you@example.com \
--password 'YOUR_STRONG_PASSWORD' yourusername
CI checks both halves on every run: an anonymous request is redirected to a login page, and the generated credentials are accepted by the token endpoint. It also generates that hash by running the command the README gives you, which is how the instruction stays true instead of going stale.
Dozzle never gets the Docker socket
Dozzle's own security page says a container with the socket has root on the host unless restricted, and :ro on the mount is cosmetic — the API is root-equivalent whichever way the file is mounted, because the privilege is in what the API can do, not in who can write the socket file.
So a proxy holds it and forwards only what Dozzle needs, with POST denied. Measured on the stack rather than asserted, and checked every run:
| through the proxy | answer |
|---|---|
GET /containers/json |
200 |
POST /containers/<id>/restart |
403 |
| log streaming | works |
CI also reads the Dozzle container's mount list, because the cheapest way for this to disappear is somebody adding the socket back for an afternoon.
Container actions, if you want them
Restart and stop buttons need Dozzle's setting and the proxy's POST permission, so both live in container-actions.override.yml — setting one without the other silently does nothing, which is worse than either choice made on purpose.
There is no override for DOZZLE_ENABLE_SHELL and will not be. A restart button is a restart button; a browser shell inside the container holding your database credentials is arbitrary command execution on your host, one stolen session cookie away. You have SSH.
Two defects the first CI run found
A literal $$ inside an unquoted heredoc is the shell's PID. The step that writes the test .env substitutes the bcrypt hash with ${{ … }}, so bash saw $$2a$$11$$… — doubled for Compose — inside a heredoc that must stay unquoted. Every $$ became the process id, the hash reached the user file as 24972a2497112497…, and Dozzle refused the password against a file that looked entirely plausible.
/info had to be on the proxy's allow-list. Without it Dozzle reports the host as available: false with no CPU count, no memory figure and no daemon version — and then logs "Connected to Docker" on the very next line. Nothing in CI caught it, because every assertion asked what the proxy answered and the proxy was answering correctly. There is one now that asks what Dozzle made of it.
Also included
Four images pinned by tag@sha256:<digest>, a backup loop that reads its own archive back before naming it a backup, an end-to-end suite requiring users.yml in the archive by name, a restore script, update.sh, cap_drop: ALL on every service, resource limits, and OpenSSF Scorecard. Traefik's idle timeout is an hour rather than 180 seconds, because a live log tail is a response that never ends.