- Go 98.8%
- Dockerfile 1.2%
| .forgejo/workflows | ||
| cmd/dashboard | ||
| internal | ||
| vendor | ||
| .env.example | ||
| .gitignore | ||
| CHANGELOG.md | ||
| docker-compose.prod.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| README.md | ||
| VERSION | ||
Postfix Dashboard
A self-contained web dashboard for monitoring a Postfix mail server running in Docker. Written in Go — single binary, no Node.js, no Python, no external runtime.
Features
| Feature | Details |
|---|---|
| Authentication | Session login, bcrypt passwords, 12 h TTL |
| Overview | Hourly chart (today), weekly chart, KPI cards |
| Analytics | 7 / 30 / 45 / 90 day trends, top senders / recipients / relays / domains |
| Log History | Paginated table, full-text search, status filter, up to years of history |
| Live Logs | Real-time WebSocket stream with colour coding and auto-reconnect |
| Queue | Live queue view, per-message hold / release / delete, bulk flush / delete |
| Storage | SQLite — zero external database dependency |
Quick Start
1 — Run with Docker Compose (recommended)
# Copy the example env file
cp .env.example .env
# Edit credentials
nano .env
# Build and start
docker compose -f docker-compose.prod.yml up -d --build
# Open dashboard
open http://localhost:8080
Default credentials: admin / changeme (set DASHBOARD_USER / DASHBOARD_PASS in .env).
2 — Run the binary directly
# Pipe Postfix logs from stdin
docker logs -f postfix-1 2>&1 | ./postfix-dashboard \
-addr :8080 \
-db /var/lib/postfix-dashboard/dashboard.db \
-admin-user admin \
-admin-pass secretpassword
3 — Seed from a historical log file
./postfix-dashboard \
-db /data/dashboard.db \
-seed /var/log/mail.log \
-addr :8080
Architecture
stdin (Postfix logs)
│
▼
┌─────────────────────────────────────────────────┐
│ postfix-dashboard │
│ │
│ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
│ │ parser │──▶│ store │ │ ws.Hub │ │
│ │ │ │ (SQLite) │ │ (live logs) │ │
│ └──────────┘ └────┬─────┘ └──────┬──────┘ │
│ │ │ │
│ ┌──────▼────────────────▼──────┐ │
│ │ api.Handler │ │
│ │ REST endpoints + WebSocket │ │
│ └──────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ Frontend (HTML + CSS + JS, embedded) │ │
│ │ Chart.js via CDN │ │
│ └────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
Module layout
postfix-dashboard/
├── cmd/dashboard/ Main entry point + embedded HTML/CSS/JS
│ ├── main.go Server bootstrap, signal handling, log reader
│ ├── html.go Embedded HTML template
│ ├── css.go Embedded CSS (dark industrial theme)
│ ├── js.go Embedded JavaScript SPA
│ └── static.go Static file registry
├── internal/
│ ├── auth/ bcrypt password hashing, session management
│ ├── parser/ Postfix log line parser (regex-based)
│ ├── store/ SQLite data layer (mail_logs, sessions, config)
│ ├── ws/ WebSocket hub for live log broadcasting
│ └── queue/ postqueue / postsuper wrappers
├── Dockerfile Multi-stage build (builder + bookworm-slim)
├── docker-compose.yml Basic compose file
├── docker-compose.prod.yml Production compose with Docker socket log streaming
├── CHANGELOG.md
├── VERSION
└── README.md
Configuration
All settings can be passed as CLI flags or environment variables.
| Flag | Env | Default | Description |
|---|---|---|---|
-addr |
— | :8080 |
Listen address |
-db |
— | /data/postfix-dashboard.db |
SQLite database path |
-log-source |
— | stdin |
Log source (stdin only for now) |
-admin-user |
ADMIN_USER |
admin |
Admin username (first run or update) |
-admin-pass |
ADMIN_PASS |
admin |
Admin password (first run or update) |
-seed |
— | — | Path to a log file to import on startup |
Security: change the default password immediately. The
-admin-user/-admin-passflags (or env vars) update credentials on every start if provided.
Log Integration Patterns
Pattern A — Docker socket (recommended for Docker deployments)
Mount /var/run/docker.sock into the dashboard container and stream with:
docker logs --follow --timestamps postfix-1 2>&1 | /app/postfix-dashboard ...
See docker-compose.prod.yml for a complete example.
Pattern B — Syslog
Configure Postfix/rsyslog to send mail logs to a named pipe or UDP socket, then pipe into the dashboard:
tail -F /var/log/mail.log | ./postfix-dashboard -log-source stdin ...
Pattern C — Docker log driver
Use the fluentd or gelf log driver to forward container output,
or simply docker logs -f as in Pattern A.
Building from Source
Requirements: Go 1.22+, gcc, libsqlite3-dev.
go build -ldflags="-s -w" -o postfix-dashboard ./cmd/dashboard/
Docker build
docker build -t postfix-dashboard:latest .
Security Notes
- Passwords are stored as bcrypt hashes (cost 10). The plaintext is never persisted.
- Sessions use 32-byte random tokens stored server-side (SQLite). Expired sessions are purged hourly.
- Session cookies are
HttpOnlyandSameSite=Strict. - All API endpoints require a valid session. The WebSocket endpoint also validates the session cookie or a
tokenquery parameter. - Queue action inputs (queue IDs) are validated against a strict regex before being passed to
postsuper. - The dashboard binary runs as a non-root user (
dashboard) inside the Docker container.
License
MIT
Log Integration (v1.1.0+)
Recommended: Docker socket (zero configuration)
Mount the Docker socket and set LOG_SOURCE:
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
LOG_SOURCE: docker://postfix-1
The dashboard connects to the Docker API over the Unix socket, streams the container's log output directly in Go — no shell, no CLI, no pipe required.
┌─────────────────────┐ Docker API ┌──────────────────────┐
│ postfix container │ ──────────────────▶ │ dashboard binary │
│ (stdout/stderr) │ /var/run/docker.sock │ internal/dockerlogs │
└─────────────────────┘ └──────────────────────┘
Alternative: stdin (pipe from host)
docker logs --follow postfix-1 2>&1 | ./postfix-dashboard -log-source stdin