Why self-host Mautic instead of paying for a marketing SaaS
Marketing SaaS prices the one thing you cannot control: the size of your list. Mailchimp bills by contact tier, and each tier also caps how much you may send — 10× your contact count on Essentials, 12× on Standard, 15× on Premium. Grow the list and both the invoice and the ceiling move against you. Brevo and ActiveCampaign price on the same axis.
Mautic removes that axis. You pay for the server and nothing else, and the bill is identical whether the database holds 5,000 contacts or 500,000: the entry ServOrbit VPS tier (2 vCPU, 4 GB RAM, 50 GB SSD, starting from our entry-level plans) carries a Mautic stack comfortably. Your data stays on your own infrastructure, where no SaaS host mines it for its own purposes.
The platform is published under the GPL-3.0. Its fiscal host is the Open Source Collective — which holds the MAUTIC trademark and domains on behalf of the project — and it is governed by an elected Mautic Council. There is no free-versus-paid edition to work around: Mautic is not a feature-gated build of a commercial product.
What you get with self-hosted Mautic
- Visual campaign builder — conditional branches, time delays and event triggers.
- Lead scoring — points awarded for opens, clicks, page visits and form submissions.
- Dynamic segmentation — filters on any contact attribute, refreshed in real time.
- Landing pages and forms — hosted on your own domain, with no external dependency.
- Full REST API — integrate your apps, CRM and tools through webhooks.
- GPL-3.0 licence — no contact cap, no per-email fee, no proprietary retention clause.
⚠ Mautic 5.2 LTS end of life — upgrade to Mautic 7
Mautic 5.2 LTS reached end of security support on 30 June 2026. No further security patches will be issued for the 5.2.x branch. Instances still running on that line are exposed.
The current active release is Mautic 7.2.1 "Absolunto Edition" (Mautic 7 carries a four-year active support cycle, through approximately 2030). Mautic 6 was a short-cycle intermediate release and is itself now past end of life.
Migration path. A direct upgrade from 5.2 to 7.x is not supported. The official path is sequential:
1. Mautic 5.2 → Mautic 6.x (latest stable 6.x minor)
2. Mautic 6.x → Mautic 7.x
Before any migration: back up the full mautic_data and mautic_db volumes. Test on a staging environment. Verify third-party plugin compatibility with Mautic 7.
Mautic 7 Docker architecture: same multi-role model, updated image
Mautic 7.x retains the multi-role model introduced in version 5: the same Docker image is instantiated three times under different DOCKER_MAUTIC_ROLE values:
- mautic_web: the Apache front end — it serves the installation wizard first, then the dashboard
- mautic_cron: runs the scheduled commands (segment rebuilds, campaign triggers, queued sends, cleanup, statistics)
- mautic_worker: consumes the asynchronous message queue (tracking hits, webhooks, notifications)
A fourth container, MySQL 8.0, stores contacts, campaigns and events. The three Mautic containers share one volume (mautic_data:/var/www/html) so the configuration written by the wizard is immediately visible to the cron and worker roles.
The cron role is the one people underestimate. Mautic sends nothing from the web request itself: a published campaign only fires because mautic:campaigns:trigger and mautic:emails:send run on a schedule. Stop that container and the interface still shows the campaign as published while nothing leaves the server.
Mautic 7 requires PHP 8.1 or higher and MySQL 8.0 / MariaDB 10.4 minimum. The ONLY_FULL_GROUP_BY report fix (issue #17092) is included since Mautic 7.2.0 — no workaround needed if you are on 7.2.1 or later.
Installing Mautic on your ServOrbit VPS
Deploy from the Marketplace
In your ServOrbit client area, open Marketplace → Automation & Workflows → Mautic and click Deploy. The AWX playbook provisions Ubuntu 24.04, installs Docker, generates the MySQL password, starts the four containers and configures nginx as a reverse proxy for your domain. The Apache container is bound to the loopback interface only — it is never exposed directly to the internet.
Complete the Mautic installation wizard
Open your domain in a browser. Mautic redirects to the
/s/setupwizard. Enter the site URL, check the database connection (already pre-filled from the compose environment), create your administrator account and confirm. Get the site URL right on the first pass: tracking pixels, landing pages and unsubscribe links are all built from it.Configure your SMTP relay
Go to Settings → Email Settings and choose your SMTP provider: Amazon SES, Mailgun, Brevo (free tier of 300 emails per day) or Postmark. Two things to know about SES before you build a budget. First, its headline rate is $0.10 per 1,000 emails — not "under $0.10" — and it is billed PER RECIPIENT, not per message: a send to 100 recipients counts as 100 emails. Second, that rate belongs to the à-la-carte tier: a new SES account starts on Essentials at $0.16 per 1,000. Then click Test email and confirm delivery before you touch a campaign.
Configure SPF, DKIM and DMARC
Before your first send, add the three DNS records for your sending domain. SPF declares which servers may send on your behalf: add a TXT record
v=spf1 include:<your-relay.example> -all. DKIM signs each message cryptographically: generate a key pair in your SMTP relay, publish the public key as a TXT record underdefault._domainkey.yourdomain.com, and enable signing in Mautic (Settings → Email Settings → DKIM). DMARC ties the two together: start withv=DMARC1; p=none; rua=mailto:[email protected]to collect reports, then progressively move top=quarantineandp=reject. Without aligned SPF, DKIM and DMARC, Gmail and Outlook reject campaigns above 5,000 sends per day.Create a segment and import your contacts
Under Segments → New Segment, define your filter criteria. Under Contacts → Import, upload your CSV and map the Email, First name and Last name columns onto Mautic fields. Enable double opt-in if your audience is based in the EU or in Morocco.
Build and publish your first campaign
Under Campaigns → New Campaign, drag a source (your segment) onto the canvas, add a Send email action, set a 24-hour delay, then add a conditional follow-up email. Publish, and let the worker and cron containers drain the send queue in the background.
SPF, DKIM and DMARC are not optional before your first send. Without them your campaigns land in spam at Gmail and Outlook — a problem the SMTP relay alone does not solve. Our [SPF/DKIM/DMARC guide](/blog/spf-dkim-dmarc-delivrabilite-emails-pro) walks through the DNS configuration step by step.
Use case: replacing Mailchimp for an SMB
A marketing agency running lists for 15 clients — 80,000 contacts in total — was invoiced 620 €/month by Mailchimp. Moving to self-hosted Mautic on a 4 GB RAM VPS replaced that invoice with the cost of a single entry-tier server, taking well over 7,000 € a year off the budget.
The migration took two days: CSV export from Mailchimp, import into Mautic, then rebuilding the automations in the campaign builder. The HTML email templates were imported from Mailchimp unchanged. Deliverability came out comparable because Mailgun was kept as the SMTP relay — sending reputation follows the relay, not the platform sitting in front of it.
One thing a CSV export does not carry is engagement history. Opens, clicks and page visits stay behind in Mailchimp, so every imported contact arrives in Mautic with a score of zero, and any segment built on past behaviour has to be re-earned from the first campaign onward. Plan that first send as a re-engagement wave rather than a like-for-like resume.
Performance: workers, queues and scheduled commands
By default the mautic_worker container runs a single consumer process. For volumes above 20,000 sends per day, increase the worker count via the MAUTIC_MESSENGER_CONSUMER_LIMIT environment variable and adjust MAUTIC_MESSENGER_WORKER_SLEEP to reduce idle delay.
Critical cron commands and recommended frequency:
- mautic:segments:update — every 5 minutes (rebuilds dynamic segments)
- mautic:campaigns:trigger — every 5 minutes (fires campaign events)
- mautic:emails:send — every 5 minutes (drains the send queue)
- mautic:emails:fetch — every 10 minutes (processes IMAP bounces)
- mautic:import — every 5 minutes (resumes pending imports)
- mautic:dnc:import — daily (syncs unsubscribe lists)
If the mautic_cron container is not running these commands, published campaigns will not send. Check with: docker logs mautic_cron --tail 50.
Troubleshooting: common errors
Emails not sending — campaign stuck. First cause: the mautic_cron container is not running or not executing mautic:emails:send. Check with docker ps that the container is Up, then docker logs mautic_cron --tail 100 to review recent executions. Second cause: the SMTP relay is misconfigured or failing silently. Go to Settings → Email Settings → Test email and read the returned error.
HTTP 500 on reports. If you are still on Mautic 5.2 with MySQL 8.0, the ONLY_FULL_GROUP_BY mode causes SQL 1055 errors on grouped reports. See the dedicated section below. On Mautic 7.2.0+, this is resolved natively.
Tracking pixels not counted. Verify that the site URL in Mautic matches exactly the served domain (https, not http; no trailing slash). The tracking pixel is built from this URL — a mismatch blocks tracking returns.
CSV import stuck. The CSV file must be UTF-8 encoded, without BOM. For large imports (> 10,000 rows), Mautic processes in batches via mautic:import — verify the cron is running.
Forms not submitting. Check the CORS policy if the form is embedded on a different domain. Mautic 7 requires allowed domains to be listed under Settings → Configuration → CORS.
MySQL 8 compatibility: HTTP 500 on reports and ONLY_FULL_GROUP_BY mode
Note: this issue is fixed in Mautic 7.2.0+. If you have migrated, you can skip this section. For instances still on Mautic 5.2.x:
Some Mautic reports return HTTP 500 the moment you open them — typically a Page hits report that groups by URL and title and adds a COUNT column. The symptom is quiet: a blank report page, nothing in Mautic's application log, no explicit error anywhere in the interface.
Diagnosis. The ONLY_FULL_GROUP_BY SQL mode rejects SELECT queries whose non-aggregated columns are missing from the GROUP BY clause. MySQL answers with error 1055. Check the server with:
SHOW GLOBAL VARIABLES LIKE 'sql_mode';Workaround A — persist the change. SET PERSIST sql_mode = (SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', '')) writes to mysqld-auto.cnf in the data directory (the mautic_db volume) and survives container restarts. Alternatively, add command: --sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES to the db service in the compose file.
Workaround B — run MariaDB instead. MariaDB does not enable ONLY_FULL_GROUP_BY by default, and Mautic 5 supports MariaDB 10.2 and above. Swapping the engine requires a full database dump and reload.