Analytics cookies only (Google Analytics, PostHog). No ad networks, no cross-site tracking. See our privacy policy.
An open source marketing-automation platform: contact and company records, segments, landing pages and forms, email campaigns and visual campaign workflows, with lead scoring and tracking. Built on PHP and Symfony with MySQL.
Runs on a VPS from $12/mo (Kamatera 4GB, 4 GB RAM) · prices checked Sep 2026
Pick Mautic when email is one channel in a wider marketing-automation setup rather than the whole job: contact and company records, segments, forms and landing pages, points-based scoring, and campaigns that act on what a contact does, with email, SMS and web notifications as the channels. It is a PHP and Symfony application on MySQL under GPL-3.0-or-later, and the official docker-mautic image runs the same codebase in three roles (web, cron and worker), so the Compose file runs four containers including the database. If what you want is mostly a newsletter to a list, listmonk is a single Go binary and far lighter, and Keila is simpler still.
Follow the Mautic deploy guide →Paid link — we earn a commission if you shop through it.
Run these commands on your server:
# Mautic 7 (official docker-mautic image, pinned) with MySQL 8.4 behind Caddy for automatic HTTPS, per our Mautic deploy guide
# needs a domain pointed at this server and ports 80/443 open; three Mautic containers (web, cron, worker) share one image
mkdir -p ~/mautic && cd ~/mautic
DOMAIN=mautic.example.com
[ -f .env ] || printf 'DOMAIN=%s\nMYSQL_ROOT_PASSWORD=%s\nMYSQL_PASSWORD=%s\nMAUTIC_ADMIN_PASSWORD=%s\n' "$DOMAIN" "$(openssl rand -hex 16)" "$(openssl rand -hex 16)" "$(openssl rand -hex 12)" > .env
chmod 600 .env
cat > docker-compose.yml <<'EOF'
x-mautic-env: &mautic-env
MAUTIC_DB_HOST: db
MAUTIC_DB_PORT: "3306"
MAUTIC_DB_DATABASE: mautic_db
MAUTIC_DB_USER: mautic_db_user
MAUTIC_DB_PASSWORD: ${MYSQL_PASSWORD}
MAUTIC_MESSENGER_DSN_EMAIL: doctrine://default
MAUTIC_MESSENGER_DSN_HIT: doctrine://default
x-mautic-volumes: &mautic-volumes
- mautic-config:/var/www/html/config
- mautic-logs:/var/www/html/var/logs
- mautic-media:/var/www/html/docroot/media
services:
db:
image: mysql:8.4
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: mautic_db
MYSQL_USER: mautic_db_user
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: mysqladmin --user=$$MYSQL_USER --password=$$MYSQL_PASSWORD ping
start_period: 5s
interval: 5s
timeout: 5s
retries: 10
mautic_web:
image: mautic/mautic:7.2.1-apache
restart: always
ports:
- "127.0.0.1:8080:80"
volumes: *mautic-volumes
environment: *mautic-env
healthcheck:
test: curl -f http://localhost
start_period: 5s
interval: 5s
timeout: 5s
retries: 100
depends_on:
db:
condition: service_healthy
mautic_cron:
image: mautic/mautic:7.2.1-apache
restart: always
volumes: *mautic-volumes
environment:
<<: *mautic-env
DOCKER_MAUTIC_ROLE: mautic_cron
depends_on:
mautic_web:
condition: service_healthy
mautic_worker:
image: mautic/mautic:7.2.1-apache
restart: always
volumes: *mautic-volumes
environment:
<<: *mautic-env
DOCKER_MAUTIC_ROLE: mautic_worker
depends_on:
mautic_web:
condition: service_healthy
caddy:
image: caddy:2
restart: always
ports: ["80:80", "443:443"]
environment:
DOMAIN: ${DOMAIN}
volumes: ["./Caddyfile:/etc/caddy/Caddyfile:ro", "caddy_data:/data"]
depends_on: [mautic_web]
volumes:
mysql-data:
mautic-config:
mautic-logs:
mautic-media:
caddy_data:
EOF
cat > Caddyfile <<'EOF'
{$DOMAIN} {
encode zstd gzip
reverse_proxy mautic_web:80
}
EOF
sudo docker compose up -d
for i in $(seq 1 60); do sudo docker compose ps mautic_web | grep -q '(healthy)' && break; sleep 5; done
# the cron and worker containers log "Waiting for Mautic to be installed" until the installer has run; give it your own email
. ./.env
sudo docker compose exec -T --user www-data --workdir /var/www/html mautic_web php ./bin/console mautic:install "https://$DOMAIN" --admin_email=admin@example.com --admin_username=admin --admin_password="$MAUTIC_ADMIN_PASSWORD" --force
sudo docker compose ps --format 'table {{.Service}}\t{{.Status}}'
# sign in at https://DOMAIN as admin (password: grep ADMIN_PASSWORD ~/mautic/.env); campaigns queue until you set an email transport under Settings > ConfigurationMautic's own docs and the docker-mautic README are explicit about what a working install needs beyond `docker compose up`: