Securing Your AcelleMail Install: A Post-Install Checklist

Your AcelleMail install works the moment the web installer turns green — but two things now live on your server that didn't before: your subscribers' personal data, and your domain's sending reputation. This checklist secures both, in priority order, without turning you into a sysadmin. Most of it is config you set once.

What this is for

Your AcelleMail install is working the moment the web installer turns green. But "working" and "ready to put your subscribers on" are not the same thing. Two valuable things now live on your server that weren't there an hour ago:

  1. Your subscribers' personal data — names, email addresses, sometimes phone numbers and custom fields. That's personal data, and you're now its custodian.
  2. Your domain's sending reputation — every campaign signs with your domain. Get this wrong and your own legitimate mail lands in spam.

This checklist secures both, in the order that matters. It is not a generic Linux-hardening course — those exist, and we point to one at the end. It's the short list of things that, if you skip them, actually hurt an email-marketing app specifically.

Good news up front: self-hosting AcelleMail is genuinely manageable. Most of what follows is configuration you set once and never touch again. Budget about 30–40 minutes, do it in the first hour, and you're done.

How to read this: each item says why it matters for an email app first, then what to do. If a "why" doesn't apply to you, skip that item consciously rather than blindly running commands.

Priority 1 — Protect subscriber data

This is the one that turns a bad day into a reportable data breach. Lead here.

1.1 — Put the admin panel behind HTTPS, always

Every login, every subscriber export, every API token travels over this connection. On plain HTTP it's readable by anyone on the network path. Your install guide already set up a Let's Encrypt certificate — this step just makes sure AcelleMail insists on using it.

In your .env, confirm:

APP_URL=https://mail.example.com
FORCE_HTTPS=true

FORCE_HTTPS=true makes AcelleMail emit https:// links even when it sits behind a proxy that terminates TLS (Cloudflare, an AWS load balancer). After editing .env, clear AcelleMail's config cache so the change takes effect (php artisan config:clear from the install directory, or your panel's "Clear cache" action).

Don't have a certificate yet? That's a 5-minute fix — see the TLS step of your platform's install guide (Ubuntu).

1.2 — Don't run in debug mode

When APP_DEBUG=true, any uncaught error renders a full stack trace — which can include your database password and other .env values — straight into the browser. On a public site that's a credential leak waiting for the first error. It's the most common self-hosted misconfiguration, so check it explicitly — your .env must read:

APP_ENV=production
APP_DEBUG=false

Fix it if needed, then clear the config cache again.

1.3 — Keep the database off the public internet

Your subscriber data lives in MySQL/MariaDB. The AcelleMail installer creates a database user scoped to localhost, which is correct — but confirm the database server itself isn't listening to the whole world. On Ubuntu/Debian, bind-address in /etc/mysql/mysql.conf.d/mysqld.cnf should be 127.0.0.1, never 0.0.0.0. On a managed database (RDS, DigitalOcean Managed DB) this lives in the provider's security group instead — restrict it to your app server's IP.

You don't need to micromanage database grants for a single-app install; the installer's localhost-scoped user is already right. The thing that actually bites people is forgetting the firewall, which Priority 5 covers in one step.

1.4 — Set up automated backups before you import a single list

The cheapest backup you'll ever take is the first one, when the database is empty. Six months and 200 campaigns later, the temptation to "skip it just this once" is what kills people. A daily dump plus an off-site copy means a fat-fingered delete or a dead disk costs you a day, not your business.

A local copy alone doesn't survive the server dying, so pair the daily dump with an off-site target (S3, Backblaze, or your provider's snapshots) and test a restore once. The full pattern — schedule, off-site copy, retention, restore drill — is its own guide. Treat this as non-optional, not "nice to have."

➡️ Automated Database Backups

1.5 — Lock down the files that hold secrets

Your .env holds the database password, mail credentials, and the APP_KEY that encrypts session data. It should be readable by the web user and nobody else, and the rest of the install shouldn't be world-writable — only storage/ and bootstrap/cache/ need write access. If PHP is ever compromised, correct file permissions are what stop an attacker rewriting your app files. Your install guide sets these during setup; re-confirm them if you've been copying files around as root.

Want full encryption-at-rest (encrypted volumes, encrypted backups) for regulated data? That's the next level up — see Data Encryption for Self-Hosted Platforms.

Priority 2 — Protect your sending reputation

This is what's unique about an email app. A normal web app can be sloppy here and only its own uptime suffers. With AcelleMail, getting this wrong means mailbox providers start junking your campaigns — and reputation is slow to earn back.

2.1 — Get SPF, DKIM, and DMARC right (non-negotiable)

Gmail, Yahoo, and Microsoft now expect bulk senders to pass all three — and they must align to pass DMARC, not merely exist. In plain terms:

  • SPF lists which servers may send for your domain.
  • DKIM signs each message so receivers can prove it's really from you and untampered. Use a 2048-bit key.
  • DMARC tells receivers what to do when a message fails the other two.

AcelleMail generates the DKIM key for you and shows the exact DNS records to publish. Don't hand-craft these — follow the in-app flow:

➡️ How to Set Up SPF, DKIM, and DMARC Records

2.2 — Roll DMARC enforcement gradually

Don't publish p=reject on day one — if your SPF or DKIM alignment is even slightly off, you'll bounce your own legitimate mail. Start at p=none to collect reports and see exactly what's sending under your domain, then tighten to p=quarantine, then p=reject once the reports are clean. There's no flag-day deadline — the point is steady, verified progression.

➡️ DMARC Enforcement Migration

2.3 — Send at a sane rate, and don't IP-hop

Mailbox providers throttle suspicious patterns — sudden volume spikes or a brand-new IP blasting at full tilt — before they ever hard-block. Two habits keep you clear:

  • Pick a sending IP/domain and stick with it. Constantly rotating IPs or sender names is a classic spammer signature. On a brand-new IP, warm it up gradually before full volume — see Domain & IP Warmup.
  • Set rate limits in AcelleMail to match what your sending server (your own SMTP, Amazon SES, SendGrid, Mailgun) actually allows. Configure these under Sending servers rather than letting one campaign fire 100k emails in a burst.

➡️ Sending Throttling Strategies

2.4 — Watch for reputation drops and blacklisting

Even a clean setup can get listed if a few hundred subscribers mark you as spam in a short window. The fix is mostly upstream — list hygiene and authentication — but you want to know when it happens, because throttling shows up before a hard block.

➡️ Sender Reputation Monitoring · if you're already in trouble, the Deliverability Incident Runbook.

Priority 3 — Lock down admin and API access

Your admin panel can export every subscriber and send on your behalf. The API can do the same programmatically. These are the two doors worth bolting.

3.1 — Strong admin password + two-factor

Multi-factor auth is the single highest-leverage control here — it stops credential-stuffing and brute-force outright, even if a password leaks. AcelleMail ships TOTP-based two-factor; turn it on for every admin account:

Go to Admin → Account Settings → Two-Factor Authentication → enable, scan the QR with any authenticator app (Google Authenticator, 1Password, Authy), and save the recovery codes to your password manager immediately — there's no override if you lose both the device and the codes.

3.2 — Restrict who can reach /admin

/admin/login is the highest-value brute-force target on the box. Beyond a strong password, two web-server layers help:

  • Rate-limit the login so password sprayers get throttled — a few attempts per minute per IP is plenty.
  • If your team has fixed IPs, allowlist them. Restricting /admin to known IP ranges makes stolen credentials nearly useless to an outside attacker. Skip this if your admins roam (cafés, mobile) — it'll lock you out.

These live in your web-server config (the nginx section of your install guide), not in AcelleMail's settings.

3.3 — Treat the API token like a password, and rotate it

Every AcelleMail account has an api_token. Anyone holding it can read your lists and send campaigns, so:

  • Store it in a secrets manager or .env, never in version control.
  • Prefer the Authorization: Bearer header over the ?api_token= query parameter — query strings end up in server logs and browser history.
  • Rotate it if it might have leaked (committed to a repo, shared in a ticket, an ex-employee had it). Rotating is just resetting the token in the account's API settings; the old one stops working immediately.

➡️ REST API Authentication & Endpoints

Priority 4 — Keep AcelleMail and PHP patched

A perfectly hardened box still gets owned by one unpatched known vulnerability. This is ongoing, not one-time.

  • AcelleMail updates ship security fixes alongside features. Apply them when they land — don't sit three versions behind.
  • PHP is the runtime everything sits on. Stay on a supported PHP version (8.3+ for current AcelleMail) and let your distro's unattended-upgrades apply security patches automatically.
  • Re-audit after any disclosed vulnerability in PHP, nginx, MySQL/MariaDB, or AcelleMail — and on a quarterly cadence otherwise, the same rhythm you use to re-check your DNS records.

Priority 5 — Server-OS basics (the short version)

These are general server-hardening steps — not AcelleMail-specific, so we won't reproduce a whole sysadmin course. Two matter most, done once:

Firewall down to only what AcelleMail needs — SSH, HTTP, and HTTPS inbound, nothing else. MySQL, Redis, and php-fpm should never be reachable from the internet. On Ubuntu that's a handful of ufw allow rules (OpenSSH + "Nginx Full"); on DigitalOcean or AWS, use the provider's Cloud Firewall / Security Group as the primary edge filter and treat the host firewall as defense in depth.

SSH with keys, not passwords. Copy your key first, confirm it works in a second terminal, then disable password login. Adding fail2ban to auto-ban repeat offenders is a nice extra.

That's the 80/20. The full Linux-hardening treatment (non-standard SSH port, disabling root login, kernel sysctl tuning) is a general OS topic — your platform's install guide covers the firewall and SSH basics in context:

➡️ Install AcelleMail on Ubuntu 24.04 (and the Debian / Rocky / DigitalOcean / AWS variants)

Quick verification

Two minutes to confirm the high-value items took:

  • In .env: APP_ENV=production, APP_DEBUG=false, FORCE_HTTPS=true.
  • Database is bound to 127.0.0.1 (or locked to your app IP in the provider security group).
  • Firewall is up with only SSH / HTTP / HTTPS open.
  • A backup file actually exists — and re-check tomorrow that the schedule fired.

Then, in the app: send a test campaign to a mail-tester.com address — it scores your SPF/DKIM/DMARC alignment in one click, the fastest way to confirm Priority 2 landed.

Common issues

What you see Likely cause Fix
Locked out of SSH after disabling passwords Disabled password auth before the key worked Use your provider's web console; re-enable password auth, copy the key, confirm, then disable again
Stack trace with .env values in the browser APP_DEBUG=true still set Set APP_DEBUG=false, clear the config cache
Your own campaigns land in spam SPF/DKIM/DMARC not aligned, or p=reject set before alignment was clean Run a mail-tester; back DMARC down to p=none, fix alignment, re-tighten
Admin login locks out your whole office Rate-limit or IP-allowlist too tight for a shared office IP Raise the limit, or scope the allowlist to the office's real egress IP
Backups silently stopped, disk fills The scheduled job didn't run Confirm the backup schedule is active and its retention cleanup is firing
API token shows up in access logs Using the ?api_token= query parameter Switch callers to the Authorization: Bearer header

What to do after

Once Priorities 1–3 are in place you can safely import your first list and publish the admin URL. Keep Priority 4 (patching) on a calendar reminder, and revisit this checklist whenever you add an admin user, change sending servers, or move the install to a new server.

FAQ

Do I need all of this before going live? Priorities 1–3 yes, before you import real subscribers or publish the admin URL. Priority 4 is ongoing; Priority 5 is the OS floor — do the firewall + SSH-keys steps, defer the rest if you must.

Is Cloudflare / a WAF a substitute for this? No — it's an extra layer, not a replacement. Cloudflare in front gives you free DDoS protection and hides your origin IP, but it doesn't fix an exposed database, missing backups, or unaligned DMARC. Defense in depth means both.

What about GDPR / CAN-SPAM? Hardening protects the data; compliance is a separate set of content and process obligations on top. See the GDPR Compliance Guide for Email Marketing.

Running AcelleMail in Docker? Same priorities, applied at the container/host boundary — the Docker Deployment Guide covers the Docker-specific patterns.

Related articles

15 comments

7 comments

  1. i.rossi.mil
    For anyone using systemd-resolved (Ubuntu 22+): set DNSStubListener=no in /etc/systemd/resolved.conf before installing. Otherwise port 53 conflicts when you eventually run a bounce handler
    1. admin
      Good tip. The Cloudflare-outbound-rate-limit case is something we hadnt documented.
  2. joel.anders.se
    Clean walkthrough. The supervisor config copy-paste worked first try.
  3. d.cohen.tlv
    Followed this on Ubuntu 24.04 last week. Zero issues. The php-imap and php-sqlite3 notes saved me a wizar-error round-trip.
    1. admin (edited)
      Glad it landed. Drop suggestions in the comments and we'll incorporate them on the next refresh tbh
    2. admin (edited)
      Thanks. Pass it along if it helps your team.
  4. aditi.s.bom
    Any reason to use MariaDB over MySQL 8? We default to MariaDB everywhere but I see most Acelle install guides use MySQL.
    1. admin
      Honest answer: it depends on your provider. SES handles it gracefully; Mailgun is stricter. Well add a provider-by-provider table in the next revision.
  5. danrey.dev
    Any reason to use MariaDB over MySQL 8? We default to ariaDB everywhere but I see most Acelle install guides use MySQL...
    1. admin
      We don't recommend that approach in production. It works in dev but has subtle race conditions under concurrent load. Stick with the documented pattern.
  6. akira.tnk88
    Installed on a $12/mo DigitalOcean droplet for our 30k-subscriber list. Performance has been fine. Memory peaks around 1.6 GB during batch sends; comfortable on 2GB.
    1. admin (edited)
      Thanks for the detail — adding the kernel-reboot edge case to the article on the next update.
    2. admin (edited)
      Thanks for the numbers. Worth pulling into a follow-up post on volume-tier sizing...
  7. anna.k.pm
    We use Hetzner instead of DO — same Ubuntu image, identical install. Probably $4/mo cheaper. The PTR record on Hetzner requires opening a support ticket but they respond same-day.
    1. admin (edited)
      Useful context. The fact that it took 3 weeks end-to-end is realistic; we sometimes get pushed to say 1-week timelines and they're not honest...

More in Installation & Setup