> ## Content Index
> Fetch the complete content index at: https://anantafatur.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Monitoring Docker Images with Diun and SMTP Notifications
- URL: https://anantafatur.dev/diun-docker-image-monitoring/
- Published: 2026-08-22T14:26:48.000Z
- Updated: 2026-08-22T14:29:40.000Z
- Description: I set up Diun to watch my Docker containers for image updates, configured SMTP email notifications, and worked through several configuration gotchas along the way.
- Author: Ananta

I run a few Docker containers on my server: Ghost, MariaDB, Beszel, Docmost, Vaultwarden, and Smokeping. I want to keep them updated. Not for new features. I just want to reduce the CVE risk. A stale container image is an open invitation for problems, and I do not want to check Docker Hub manually every week just to see if there is a new patch.

So I needed a tool that watches my Docker images and tells me when a new version is available. I settled on Diun, a lightweight container image update notifier by crazy-max. It does one thing and does it well: it checks registries and notifies you when your images have updates.

Here is how I set it up, what broke, and how I fixed it.

---

## The setup

I run everything with Docker Compose. Diun itself runs as its own container, mounts the Docker socket, and watches a list of images I define in a config file. No labels on my containers. Just a simple `diun.yml` that lists exactly what I care about:

```yaml
- name: ghost:alpine
- name: mariadb:lts-noble
- name: henrygd/beszel:latest
- name: docmost/docmost:latest
- name: vaultwarden/server:alpine
- name: linuxserver/smokeping:latest

```

I use floating tags like `ghost:alpine`, `mariadb:lts-noble`, and `vaultwarden/server:alpine`. These track the latest version within a major release or variant. The digest changes whenever the upstream maintainer pushes a new build, and Diun catches it. This is exactly what I want. I get notified about updates without worrying about pinned versions going stale.

## Installing Diun

Diun has a simple compose file. I use the File provider so it reads my `diun.yml` directly:

```yaml
name: diun

services:
  diun:
    image: crazymax/diun:4.33
    command: serve
    volumes:
      - "./data:/data"
      - "./diun.yml:/data/diun.yml"
      - "/var/run/docker.sock:/var/run/docker.sock"
    environment:
      - "TZ=Asia/Jakarta"
      - "DIUN_WATCH_WORKERS=20"
      - "DIUN_WATCH_SCHEDULE=0 */6 * * *"
      - "DIUN_WATCH_JITTER=30s"
      - "DIUN_PROVIDERS_FILE_FILENAME=/data/diun.yml"
    labels:
      - "diun.enable=true"
    restart: always

```

The File provider reads `diun.yml` and watches exactly those images. I also keep the `diun.enable=true` label on Diun itself so it monitors its own image. That way I know when a new Diun release is available too.

## Adding SMTP email notifications

Diun supports many notification backends: Discord, Telegram, Slack, webhooks, and even plain SMTP email. I wanted email because I do not need real-time alerts. I just want to see an update notification in my inbox when a new image is available.

I use SMTP2Go for my SMTP. It is a free SMTP relay service that gives you 1,000 emails per month. I [already set it up](https://anantafatur.dev/how-to-get-a-free-smtp-for-your-personal-homelab-using-smtp2go/) for my homelab before, so I had the credentials ready. I added them to a `.env` file so they are not hardcoded in the compose file:

```
## SMTP
DIUN_NOTIF_MAIL_HOST=smtp.example.com
DIUN_NOTIF_MAIL_PORT=587
DIUN_NOTIF_MAIL_SSL=false
DIUN_NOTIF_MAIL_INSECURESKIPVERIFY=false
DIUN_NOTIF_MAIL_USERNAME=diun@example.com
DIUN_NOTIF_MAIL_PASSWORD=changeme
DIUN_NOTIF_MAIL_FROM=<no-reply-email>
DIUN_NOTIF_MAIL_TO=<my-email>

```

Then referenced those variables in the compose file:

```yaml
environment:
  - "DIUN_NOTIF_MAIL_HOST=${DIUN_NOTIF_MAIL_HOST}"
  - "DIUN_NOTIF_MAIL_PORT=${DIUN_NOTIF_MAIL_PORT}"
  - "DIUN_NOTIF_MAIL_SSL=${DIUN_NOTIF_MAIL_SSL}"
  - "DIUN_NOTIF_MAIL_INSECURESKIPVERIFY=${DIUN_NOTIF_MAIL_INSECURESKIPVERIFY}"
  - "DIUN_NOTIF_MAIL_USERNAME=${DIUN_NOTIF_MAIL_USERNAME}"
  - "DIUN_NOTIF_MAIL_PASSWORD=${DIUN_NOTIF_MAIL_PASSWORD}"
  - "DIUN_NOTIF_MAIL_FROM=${DIUN_NOTIF_MAIL_FROM}"
  - "DIUN_NOTIF_MAIL_TO=${DIUN_NOTIF_MAIL_TO}"

```

Docker Compose picks up the `.env` file automatically from the same directory. No extra wiring needed.

## The gotchas

Of course, things did not work on the first try. Here is what I hit.

### The FROM field only accepts a plain email

I tried to use a display name format:

```
DIUN_NOTIF_MAIL_FROM=My Name <no-reply@example.com>

```

Diun rejected it:

```
Key: 'Config.Notif.Mail.From' Error:Field validation for 'From' failed on the 'email' tag

```

The `from` field only accepts a plain email address, not a display name. I changed it to just a plain email address and it worked.

### The watchRepo incident

Here is the big one. I initially tried Diun's Docker provider with labels on my containers. But I learned that with pinned tags, Diun only checks the digest of that specific tag. If the maintainer rebuilds the same tag, I get notified. But if a new version comes out, Diun does not see it because it only watches the tag I am pinned to.

So I thought: let me enable `watchRepo`, which scans all tags in the repository:

```yaml
- "DIUN_DEFAULTS_WATCHREPO=true"

```

Bad idea. Very bad idea.

I restarted Diun and my inbox exploded. Diun scanned every single tag in the repositories, found every version that was "new" relative to my database, and sent me an email for each one. I got dozens of emails in seconds.

I immediately took the container down. Do not enable `watchRepo` unless you also configure `max_tags` and `include_tags` filters. Otherwise it will scan everything.

---

## Why I switched to the File provider

After the `watchRepo` disaster, I switched to the File provider. Instead of adding labels to every container and relying on the Docker provider, I just list the images I want to watch in a `diun.yml` file. This is cleaner. I can see all the images I am watching in one place. And I use floating tags like `ghost:alpine` and `mariadb:lts-noble` that track the latest version within a major release, so Diun catches new builds without needing `watchRepo`.

The File provider and the Docker provider are different things. The Docker provider scans running containers with labels. The File provider reads a config file. I use the File provider because it gives me explicit control over what I watch, and I do not have to remember to add labels to every new container. I just add a line to `diun.yml`.

## Testing the notification

Diun has a built-in test command for notifications:

```sh
docker compose -f diun/docker-compose.yaml exec -T diun diun notif test

```

This sends a test email using your configured SMTP settings. It confirmed that my SMTP config was working without needing to wait for an actual image update.

When I ran the full check, the logs showed:

```
Found 6 image(s) to analyze
Jobs completed added=0 failed=0 skipped=0 unchanged=6 updated=0

```

All six images were up to date. No emails. Exactly what I wanted.

## Final config

Here is the complete Diun compose file I ended up with:

```yaml
name: diun

services:
  diun:
    image: crazymax/diun:4.33
    command: serve
    volumes:
      - "./data:/data"
      - "./diun.yml:/data/diun.yml"
      - "/var/run/docker.sock:/var/run/docker.sock"
    environment:
      - "TZ=Asia/Jakarta"
      - "DIUN_WATCH_WORKERS=20"
      - "DIUN_WATCH_SCHEDULE=0 */6 * * *"
      - "DIUN_WATCH_JITTER=30s"
      - "DIUN_PROVIDERS_FILE_FILENAME=/data/diun.yml"
      - "DIUN_NOTIF_MAIL_HOST=${DIUN_NOTIF_MAIL_HOST}"
      - "DIUN_NOTIF_MAIL_PORT=${DIUN_NOTIF_MAIL_PORT}"
      - "DIUN_NOTIF_MAIL_SSL=${DIUN_NOTIF_MAIL_SSL}"
      - "DIUN_NOTIF_MAIL_INSECURESKIPVERIFY=${DIUN_NOTIF_MAIL_INSECURESKIPVERIFY}"
      - "DIUN_NOTIF_MAIL_USERNAME=${DIUN_NOTIF_MAIL_USERNAME}"
      - "DIUN_NOTIF_MAIL_PASSWORD=${DIUN_NOTIF_MAIL_PASSWORD}"
      - "DIUN_NOTIF_MAIL_FROM=${DIUN_NOTIF_MAIL_FROM}"
      - "DIUN_NOTIF_MAIL_TO=${DIUN_NOTIF_MAIL_TO}"
    healthcheck:
      test: ["CMD", "diun", "healthcheck"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 60s
    labels:
      - "diun.enable=true"
    restart: always

```

And the `diun.yml`:

```yaml
- name: ghost:alpine
- name: mariadb:lts-noble
- name: henrygd/beszel:latest
- name: docmost/docmost:latest
- name: vaultwarden/server:alpine
- name: linuxserver/smokeping:latest

```

---

## Closing

Diun is a simple tool that does one thing. It watches images and tells you when they change. The setup took maybe 30 minutes, and most of that was the `watchRepo` incident.

It is also incredibly lightweight. Here is the resource usage on my server after letting it run for a while:

```
CONTAINER      CPU %    MEM USAGE / LIMIT     MEM %    NET I/O          BLOCK I/O
89ded4f5a824   0.04%    12.69MiB / 7.619GiB   0.16%    928kB / 446kB    1.79MB / 1.03MB

```

12 MiB of RAM and barely any CPU. The image itself is only 82 MB on disk. It just sits there quietly, checks every 6 hours, and sends an email if something changes. Exactly what I wanted.

For now, this works. My containers stay updated, my inbox stays quiet, and I sleep better knowing I will get an email when something changes.