---
url: https://dozzle.dev/guide/podman.md
description: >-
  Run Dozzle with Podman, rootful or rootless, as a standalone service, Quadlet
  unit or agent, and fix missing memory stats and failing healthchecks.
---

# Podman

Dozzle supports Podman through its Docker-compatible socket interface. One known difference from Docker affects setup: memory stats are often missing in rootless/Quadlet deployments (cgroup delegation). This guide covers standalone mode (local monitoring) and agent mode (remote monitoring via a central Dozzle server).

## Deployment Options

| Mode           | Use Case                          | Setup Complexity |
| -------------- | --------------------------------- | ---------------- |
| **Standalone** | Single host log viewing           | Simple           |
| **Agent**      | Multi-host centralized monitoring | Moderate         |

### Deployment Methods

Podman offers several launch approaches:

| Method            | Auto-start | Memory Stats | Healthchecks | Best For    |
| ----------------- | ---------- | ------------ | ------------ | ----------- |
| CLI               | Manual     | ✓            | ✓            | Development |
| `podman-compose`  | ✗          | ✓            | ✗            | Testing     |
| Quadlet (systemd) | ✓          | ✗\*          | ✓            | Production  |

\*Memory stats are typically unavailable in rootless mode unless cgroup v2 memory delegation is enabled. See the FAQ at the bottom of this page.

***

# &#x20;Standalone Mode

Run Dozzle as a standalone service to monitor local Podman containers.

## &#x20;Rootful Setup

For system-wide Podman daemon:

```bash
# Enable and start the Podman socket
sudo systemctl enable podman.socket
sudo systemctl start podman.socket

# Dozzle can connect via the Docker socket
podman run -v /run/podman/podman.sock:/var/run/docker.sock \
  -p 3000:8080 \
  ghcr.io/amir20/dozzle:latest
```

## &#x20;Rootless Setup

Rootless Podman isolates containers to a user namespace:

```bash
# Start user-level socket (runs automatically with user session)
systemctl --user enable podman.socket
systemctl --user start podman.socket

# For a user named 'appuser', Dozzle can connect via:
podman run -v /run/user/$(id -u appuser)/podman/podman.sock:/var/run/docker.sock \
  -p 3000:8080 \
  ghcr.io/amir20/dozzle:latest
```

**Important**: A Dozzle bound to one user's rootless socket only sees that user's containers. Other users' rootless containers live in separate namespaces and won't appear.

## &#x20;Quadlet Deployment

Quadlet enables systemd-native container management. Create a `.container` file at `~/.config/containers/systemd/dozzle.container`:

```ini
[Unit]
Description=Dozzle Log Viewer
After=network-online.target
Wants=network-online.target

[Container]
Image=ghcr.io/amir20/dozzle:latest
PublishPort=3000:8080
Volume=/run/user/%U/podman/podman.sock:/var/run/docker.sock

HealthCmd=/dozzle healthcheck
HealthInterval=5s
HealthTimeout=10s
HealthRetries=5
HealthStartPeriod=15s

[Service]
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target
```

Enable and start:

```bash
systemctl --user daemon-reload
systemctl --user enable --now dozzle.service
```

For multi-user systems, drop the same file into each user's `~/.config/containers/systemd/` and pick a distinct host port per user (e.g. `PublishPort=3001:8080`). Each instance only sees that user's rootless containers.

> \[!NOTE] Quadlet generates a systemd timer for healthchecks. `podman-compose` does not, so healthchecks won't run on a schedule there; trigger them manually with `podman healthcheck run NAME` if needed.

***

# &#x20;Agent Mode

Run Dozzle as an agent on remote Podman hosts for centralized monitoring via a main Dozzle server. Agents communicate with the main server via gRPC.

## &#x20;Agent Setup

### Prerequisites

* Open port 7007 on agent host
* Network connectivity between main server and agent

### Start Dozzle Agent

Run Dozzle in agent mode on remote Podman hosts:

```bash
# Rootful agent
podman run -d \
  --name dozzle-agent \
  -v /run/podman/podman.sock:/var/run/docker.sock \
  -p 7007:7007 \
  ghcr.io/amir20/dozzle:latest agent
```

```bash
# Rootless agent (for user 'appuser')
sudo -u appuser podman run -d \
  --name dozzle-agent \
  -v /run/user/$(id -u appuser)/podman/podman.sock:/var/run/docker.sock \
  -p 7007:7007 \
  ghcr.io/amir20/dozzle:latest agent
```

### Quadlet Agent Deployment

Create a `.container` file for the agent:

```ini
# dozzle-agent.container
[Unit]
Description=Dozzle Agent
After=network-online.target
Wants=network-online.target

[Container]
Image=ghcr.io/amir20/dozzle:latest
PublishPort=7007:7007
Volume=/run/user/%U/podman/podman.sock:/var/run/docker.sock
Exec=agent

HealthCmd=/dozzle healthcheck
HealthInterval=5s
HealthTimeout=10s
HealthRetries=5
HealthStartPeriod=15s

[Service]
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target
```

> \[!NOTE] The Dozzle image's entrypoint is `/dozzle`, so `agent` goes in `Exec=` (the command), not `Entrypoint=`.

Enable and start:

```bash
systemctl --user daemon-reload
systemctl --user enable dozzle-agent.service
systemctl --user start dozzle-agent.service
```

***

# &#x20;Main Server with Remote Agents

Configure the main Dozzle server to connect to agents on remote Podman hosts.

## &#x20;Server Configuration

Run the main Dozzle server with agent endpoints:

```bash
podman run -d \
  --name dozzle \
  -p 3000:8080 \
  ghcr.io/amir20/dozzle:latest \
  --remote-agent "host1.example.com:7007" \
  --remote-agent "host2.example.com:7007"
```

Or with environment variables:

```bash
podman run -d \
  --name dozzle \
  -e DOZZLE_REMOTE_AGENT="host1.example.com:7007,host2.example.com:7007" \
  -p 3000:8080 \
  ghcr.io/amir20/dozzle:latest
```

### Quadlet Main Server with Agents

```ini
# dozzle-server.container
[Unit]
Description=Dozzle Server with Remote Agents
After=network-online.target
Wants=network-online.target

[Container]
Image=ghcr.io/amir20/dozzle:latest
PublishPort=3000:8080
Environment=DOZZLE_REMOTE_AGENT=host1.example.com:7007,host2.example.com:7007

HealthCmd=/dozzle healthcheck
HealthInterval=5s
HealthTimeout=10s
HealthRetries=5
HealthStartPeriod=15s

[Service]
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target
```

> \[!NOTE] `WantedBy=multi-user.target` only applies to system units. For `systemctl --user` units, use `default.target`.

***

# &#x20;Additional Configuration

## &#x20;Host IDs

Nothing to set up here. Dozzle handles Podman host IDs on its own, and this section exists only because earlier versions of this page asked you to create a file that never worked.

Docker identifies an engine by the UUID in `/var/lib/docker/engine-id`, written once when the daemon first starts. Podman is daemonless and tracks no such identity, so its Docker-compatible `/info` endpoint fills that field with a fresh random UUID on every call. You can see it for yourself:

```sh
curl -s --unix-socket /run/user/$(id -u)/podman/podman.sock "http://d/v1.40/info" | jq .ID
curl -s --unix-socket /run/user/$(id -u)/podman/podman.sock "http://d/v1.40/info" | jq .ID
```

Two different UUIDs, and creating `/var/lib/docker/engine-id` changes nothing, because Podman never reads it. Dozzle instead derives a stable ID from the hostname and the container storage path, which keeps a host recognizable across restarts and keeps two rootless users on one machine apart.

> \[!WARNING] If you created `/var/lib/docker/engine-id` on a Podman host following older instructions, you can delete it.

### When IDs Collide

Two Podman hosts that share both a hostname and a storage path get the same derived ID, and Dozzle drops one of them as a duplicate. Hostnames are normally distinct, so this takes cloned VMs or a fleet that never set a hostname. Set `DOZZLE_HOST_ID` on one of them to break the tie:

```ini
# dozzle-agent.container
[Container]
Environment=DOZZLE_HOST_ID=web-01
```

The value can be any string of letters, numbers, dashes, underscores and dots. It must be unique across your hosts and stay the same for the life of the host.

## &#x20;FAQ

### Memory Stats Missing in Rootless Mode

Memory stats are usually missing in rootless deployments because the `memory` cgroup controller isn't delegated to the user slice by default. Check what's delegated:

```bash
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/cgroup.controllers
```

If `memory` is not in the output, enable delegation via a drop-in:

```bash
sudo mkdir -p /etc/systemd/system/user@.service.d
sudo tee /etc/systemd/system/user@.service.d/delegate.conf <<'EOF'
[Service]
Delegate=cpu cpuset io memory pids
EOF
sudo systemctl daemon-reload
```

Then log out and back in (or reboot) for the user slice to pick up the new delegation. See the [Podman rootless tutorial](https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md) for details.

### Healthchecks Reported as Unhealthy

**podman-compose issue**: Healthchecks are reported as unhealthy even though manual runs pass. This is a Podman behavior where healthchecks aren't automatically evaluated without a systemd timer (Quadlet generates one automatically).

Workaround with `podman-compose`:

```bash
# Manual healthcheck run
podman healthcheck run <container_id>
```

**Quadlet**: `HealthCmd=` takes a plain command line, not the Docker `CMD [...]` JSON form:

```ini
HealthCmd=/dozzle healthcheck
```

Older `podman-compose` (< 1.5.0) runs all healthchecks via `sh`, which doesn't exist in the Dozzle image. Update to a current version.

### Cross-user Container Visibility

Rootless Podman can only access containers in the same user namespace. If running Dozzle as one user, it cannot see containers from another user's rootless session.

**Solution**: Either run Dozzle as the same user or use rootful mode.
