Running Sendry with Docker and Docker Compose.
# Clone repository
git clone https://github.com/foxzi/sendry.git
cd sendry
# Copy and edit configs
cp configs/sendry.example.yaml configs/sendry.yaml
cp configs/web.example.yaml configs/web.yaml
# Start services
docker compose up -d| Service | Port | Description |
|---|---|---|
| sendry | 25, 465, 587 | SMTP/SMTPS server |
| sendry | 8080 | HTTP API |
| sendry | 9090 | Prometheus metrics |
| sendry-web | 8088 | Web management interface |
server:
hostname: mail.example.com
smtp:
port: 25
submission_port: 587
smtps_port: 465
api:
port: 8080
auth:
api_keys:
- key: "your-api-key"
name: "default"
domains:
example.com:
mode: production
logging:
level: info
format: jsonserver:
listen_addr: ":8088"
database:
path: "/var/lib/sendry-web/app.db"
auth:
local_enabled: true
session_secret: "change-me-to-random-32-chars-minimum"
session_ttl: 24h
sendry:
servers:
- name: "sendry"
base_url: "http://sendry:8080" # Docker internal network
api_key: "your-api-key" # Same as in sendry.yaml
env: "prod"
logging:
level: info
format: jsondocker compose up -ddocker compose up sendry -ddocker compose up sendry-web -d# All services
docker compose logs -f
# Specific service
docker compose logs -f sendry
docker compose logs -f sendry-webdocker compose downdocker compose up -d --buildAfter starting sendry-web, create an admin user:
docker compose exec sendry-web /usr/bin/sendry-web user create \
--email admin@example.com \
--password your-password \
--config /etc/sendry/web.yamlThen open http://localhost:8088 and login.
| Volume | Path | Description |
|---|---|---|
| sendry-data | /var/lib/sendry | Queue, DKIM keys, metrics |
| sendry-web-data | /var/lib/sendry-web | SQLite database |
# Stop services
docker compose stop
# Backup volumes
docker run --rm -v sendry_sendry-data:/data -v $(pwd):/backup alpine \
tar czf /backup/sendry-data-backup.tar.gz -C /data .
docker run --rm -v sendry_sendry-web-data:/data -v $(pwd):/backup alpine \
tar czf /backup/sendry-web-data-backup.tar.gz -C /data .
# Start services
docker compose startYou can set these in .env file or pass directly:
# .env
VERSION=0.4.0
TZ=Europe/Moscow# Or pass directly
TZ=Europe/Moscow docker compose up -dBoth services share sendry-net network. Sendry Web connects to Sendry MTA via internal hostname sendry:8080.
- Use external configs - mount configs from host instead of copying
- Use secrets - don't commit API keys and passwords
- Set up TLS - use reverse proxy (nginx, traefik) for HTTPS
- Monitor - connect Prometheus to :9090/metrics
- Backup - regularly backup volumes
services:
sendry-web:
labels:
- "traefik.enable=true"
- "traefik.http.routers.sendry-web.rule=Host(`panel.example.com`)"
- "traefik.http.routers.sendry-web.tls.certresolver=letsencrypt"
- "traefik.http.services.sendry-web.loadbalancer.server.port=8088"# Check logs
docker compose logs sendry
docker compose logs sendry-web
# Check config syntax
docker compose exec sendry /usr/bin/sendry config validate- Check API key matches in both configs
- Check
base_urluses Docker hostname:http://sendry:8080 - Check both containers are on same network
# Fix ownership
docker compose exec sendry chown -R sendry:sendry /var/lib/sendry
docker compose exec sendry-web chown -R sendry:sendry /var/lib/sendry-web