SSD Nodes Learn
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-07-24

Mailcow op VPS: Gmail accepteert uw mail

Controleer eerst port 25 op uw VPS. Voorkom dat mail in de queue blijft staan en los de Gmail 550 5.7.25 PTR error op met de juiste DNS-instellingen.

Wat u bouwt

Een volledige mailserver op een eigen server: SMTP voor het verzenden en ontvangen van e-mail, IMAP zodat uw telefoon en laptop gesynchroniseerd blijven, een webmail-client en een spamfilter die elk bericht in beide richtingen beoordeelt. mailcow-dockerized bundelt Postfix, Dovecot, Rspamd, SOGo webmail, MariaDB, Redis en een ACME-client in één Docker Compose stack, waardoor de software niet het moeilijkste onderdeel is. U heeft het systeem binnen een half uur werkend.

Het moeilijke deel is alles eromheen. E-mail is de enige dienst waarbij het internet een volledig nieuwe server actief wantrouwt. Het verschil tussen "het werkt" en "Gmail negeert elk bericht" wordt bepaald door vier DNS-records en één instelling voor IP-reputatie waar u mogelijk geen volledige controle over heeft. Lees de vereisten hieronder voordat u een server huurt. Als u na het lezen besluit dat de reputatie-opbouw de moeite niet waard is, dan is dat een begrijpelijk besluit — onze analyse van wat het waard is om zelf te hosten in 2026 categoriseert e-mail onder "alleen als u het meent" om precies deze redenen.

De vereisten ZIJN het project

Als u één van deze punten mist, worden e-mails verzonden die nooit aankomen. Hieronder staan ze in volgorde van hoe vaak ze problemen veroorzaken:

Outbound port 25 moet open staan. Uw server levert e-mail aan Gmail en Microsoft via TCP port 25. Veel VPS- en cloudproviders blokkeren outbound 25 standaard om spam te bestrijden. Deze blokkade is stil: er treden geen fouten op tijdens het opstarten en alles lijkt correct te werken, maar de e-mail blijft voor altijd in de queue staan. Test dit voordat u iets installeert. Als de poort geblokkeerd is, is de enige oplossing een support ticket naar uw provider om de poort te openen; sommige providers doen dit voor oudere accounts, anderen doen dit nooit.

Een schoon IP met een goede reputatie. Gerecyclede VPS IP-adressen staan vaak al op blocklists door spam van een vorige gebruiker. Controleer uw IP via een dienst zoals de Spamhaus lookup of mxtoolbox voordat u begint. Een IP op een blocklist leidt tot afwijzingen die u niet via software kunt oplossen.

Controle over DNS plus een correcte PTR record. U moet records toevoegen aan de zone van uw domein. Daarnaast heeft u reverse DNS (PTR) nodig waarbij het IP-adres van de server naar uw mail hostname verwijst. PTR is bijna nooit ingesteld in uw DNS-paneel; dit wordt beheerd door de eigenaar van het IP-adres. Dit wordt ingesteld in het control panel van uw VPS-provider of via een support ticket.

6 GiB RAM en 2 vCPU is de minimale aanbevolen configuratie. Het minimum van mailcow zelf is 6 GiB RAM plus 1 GiB swap voor een private installatie. 8 GiB wordt geadviseerd zodra er meerdere gebruikers afhankelijk zijn van het systeem. Bij minder dan ongeveer 2.5 GiB biedt generate_config.sh de optie om de ClamAV virusscanner uit te schakelen, zodat de kernel de containers niet afsluit. Reserveer 20 GB SSD voor de start.

Een DNS-naam, geen enkel IP-adres. Kies een hostname zoals mail.example.com. Deze naam wordt uw MAILCOW_HOSTNAME, uw TLS certificate subject, uw PTR target en uw SMTP banner. Houd dit overal consistent.

Stap 1 — Controleer of outbound poort 25 open staat

Voer dit eerst uit. Alle andere stappen zijn zinloos als dit mislukt. Probeer vanaf de nieuwe VPS een SMTP-verbinding te maken met een echte mailserver:

sudo apt update && sudo apt install -y netcat-openbsd
nc -vz -w 5 gmail-smtp-in.l.google.com 25

Een werkende verbinding geeft direct resultaat:

Connection to gmail-smtp-in.l.google.com (142.250.x.x) 25 port [tcp/smtp] succeeded!

Een geblokkeerde poort blijft vijf seconden hangen en faalt daarna:

nc: connect to gmail-smtp-in.l.google.com port 25 (tcp) timed out: Operation now in progress

Deze timeout duidt op een blokkade. Het is een netwerkfilter aan de zijde van de provider en geen fout in uw eigen firewall; lokale wijzigingen lossen dit niet op. Open een ticket met de tekst: "Please enable outbound TCP port 25 for my VPS at <IP>; I am running a legitimate mail server." Installeer mailcow pas wanneer dit proces is geslaagd. Let op: inbound poort 25 (verkeer van andere servers naar u toe) is een apart pad en staat meestal open. Providers beperken specifiek de outbound zijde.

Stap 2 — Stel nu de DNS-records in

DNS-wijzigingen hebben tijd nodig om te propageren. Publiceer daarom alles wat mogelijk is voordat u begint met installeren. Ga ervan uit dat uw domein example.com is, uw mailhost mail.example.com is en het IP-adres 10.0.0.10 is. Maak in uw zone het volgende aan:

mail.example.com.        A      10.0.0.10
mail.example.com.        AAAA   2001:db8::10          ; only if you have IPv6
example.com.             MX  10 mail.example.com.
example.com.             TXT    "v=spf1 mx -all"
_dmarc.example.com.      TXT    "v=DMARC1; p=none; rua=mailto:postmaster@example.com"

Het SPF-record geeft aan: "alleen mijn MX mag e-mail verzenden voor dit domein, weiger de rest". Begin met DMARC op p=none zodat u rapportages kunt bekijken zonder uw eigen e-mail te blokkeren; verscherp dit naar p=quarantine en vervolgens naar p=reject zodra de alignment is bewezen. Twee records ontbreken opzettelijk nog: DKIM, wat mailcow voor u genereert in Stap 6, en PTR, wat u nu instelt in het paneel van uw provider.

Stel de PTR (reverse DNS) in voor 10.0.0.10 op mail.example.com — de exacte waarde van MAILCOW_HOSTNAME. Dit is het enige record dat de meeste gebruikers vergeten, en grote providers weigeren e-mail hierdoor. Als uw paneel geen rDNS-veld heeft, dien dan een ticket in.

Stap 3 — Docker installeren

mailcow heeft Docker Engine nodig met de Compose v2 plugin. Gebruik het officiële convenience script van Docker in plaats van het Ubuntu docker.io package. Dat laatste bevat namelijk geen Compose plugin:

curl -fsSL https://get.docker.com | sudo sh
sudo docker compose version

U dient een Docker Compose version v2.x regel te zien. Als docker compose version docker: 'compose' is not a docker command weergeeft, is Docker Engine geïnstalleerd maar ontbreekt de Compose plugin. Installeer de plugin vanuit het repository van Docker — voer het bovenstaande script opnieuw uit, of volg onze Docker Compose basisgids, waarmee beide vanuit het eigen apt-repository van Docker wordt geïnstalleerd.

Stap 4 — Clone mailcow en genereer de configuratie

cd /opt
sudo git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
umask
sudo ./generate_config.sh

Controleer eerst of umask 0022 weergeeft — mailcow weigert te builden met een afwijkende file mask, en een nieuwe Ubuntu 24.04 root shell geeft standaard al 0022. Het script stelt vervolgens de enige cruciale vraag: de fully qualified hostname. Voer mail.example.com in — de waarde moet exact overeenkomen met uw A-record en PTR-record. Het script schrijft mailcow.conf, het enige environment file dat de gehele stack gebruikt. Open dit bestand indien u de web ports (HTTP_PORT, HTTPS_PORT) wilt wijzigen of ClamAV wilt uitschakelen op een systeem met weinig resources:

MAILCOW_HOSTNAME=mail.example.com
HTTP_PORT=80
HTTPS_PORT=443
SKIP_CLAMD=n          # set to y to drop the virus scanner on a <2.5 GiB box

SKIP_FTS=y is de andere optie voor een systeem met weinig RAM: full-text search is de tweede grote geheugenverbruiker in de mailcow-documentatie. Het uitschakelen hiervan beperkt alleen de zoekfunctie voor de tekstinhoud in webmail.

Laat HTTP_PORT=80 en HTTPS_PORT=443 ongewijzigd, tenzij andere services op de host deze poorten al gebruiken — de ingebouwde ACME-client van mailcow vereist dat poort 80 bereikbaar is via het internet om het certificaat te verkrijgen. Dit is de reden waarom u een aparte nginx-plus-Certbot setup niet op dezelfde machine draait; mailcow regelt de interne uitgifte en vernieuwing van TLS zelf, en een tweede service op poort 80/443 blokkeert dit proces.

Stap 5 — Start de stack en log in

sudo docker compose pull
sudo docker compose up -d
sudo docker compose ps

De pull haalt ongeveer twee dozijn images binnen; dit duurt enkele minuten. Wanneer docker compose ps aangeeft dat elke container running (of healthy) is, opent u https://mail.example.com in een browser. De standaard admin-login is gebruikersnaam admin, wachtwoord moohoo. Wijzig dit wachtwoord direct in de admin UI onder Access → Administrators. Als de browser NET::ERR_CERT_AUTHORITY_INVALID aangeeft, is het ACME-certificaat nog niet uitgegeven — raadpleeg de ACME-foutmelding hieronder voordat u concludeert dat het systeem defect is; een self-signed placeholder is normaal gedurende de eerste minuten.

Stap 6 — Voeg een domein, een mailbox toe en publiceer DKIM

Open in de admin UI de pagina Mail Setup (Configuration → Mail Setup). Klik onder het tabblad Domains op Add domain en voer example.com in. Klik vervolgens onder Mailboxes op Add mailbox om you@example.com aan te maken met een wachtwoord. Dit is een werkende mailbox die direct via IMAP bereikbaar is.

Nu de DKIM-sleutel. Ga naar Configuration → ARC/DKIM keys. mailcow heeft mogelijk al een sleutel gegenereerd toen u het domein toevoegde. Als dit niet het geval is, genereer dan een sleutel op die plek. Selecteer het domein, behoud de selector dkim, kies 2048-bit en klik op Add. Kopieer de lange TXT-waarde die wordt weergegeven en publiceer deze als:

dkim._domainkey.example.com.  TXT  "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqh...long-key...QAB"

De Domains-pagina van mailcow heeft een DNS-knop. Deze lijst alle records die nodig zijn en toont een groen vinkje of een rood kruis bij de records die daadwerkelijk gepubliceerd zijn. Gebruik dit als uw checklist. Zorg dat elke regel groen is voordat u de leverbaarheid test. Een rode DKIM-regel na publicatie betekent meestal dat de sleutel onjuist is opgesplitst in TXT-chunks. Een 2048-bit sleutel is langer dan de limiet van 255 tekens voor een enkele TXT-string. Plak de waarde daarom als één logische waarde; laat uw DNS-host de splitsing in chunks voor u verzorgen.

Stap 7 — Test de leverbaarheid en streef naar 10/10

Ga naar mail-tester.com, kopieer het weergegeven willekeurige adres en stuur een bericht naar dit adres vanaf uw nieuwe mailbox — log in op de SOGo webmail bij https://mail.example.com/SOGo en verstuur het bericht vanaf daar. Klik vervolgens op "Then check your score".

Streef naar een score van 10/10. Veelvoorkomende puntenaftrek en de oorzaken:

  • SPF niet uitgelijnd — uw MX/SPF-record ontbreekt of het verzendende IP-adres is niet opgenomen. Controleer de SPF TXT-record opnieuw.
  • DKIM-handtekening kan niet worden geverifieerd — de dkim._domainkey TXT-record ontbreekt, is nog aan het propageren of is beschadigd. Dit is de meest voorkomende fout.
  • Geen PTR / PTR-mismatch — reverse DNS lost niet op naar mail.example.com. Los dit op bij de provider.
  • Op een blocklist geplaatst — de eerdere reputatie van uw IP-adres. Vraag een delisting aan of vraag om een IP-adres met een betere reputatie.

Stuur geen echte e-mails naar Gmail of Outlook totdat de score 10/10 is. Een lage score in combinatie met een nieuw IP-adres zorgt ervoor dat uw domein direct wordt gemarkeerd.

Stap 8 — Verbind een echte mailclient

Configureer Thunderbird, Apple Mail of uw telefoon met de volgende instellingen. De serverhost is voor alle opties mail.example.com:

  • IMAP: poort 993, SSL/TLS (of 143 met STARTTLS)
  • SMTP submission: poort 465, SSL/TLS (of 587 met STARTTLS)
  • Gebruikersnaam: het volledige adres, you@example.com
  • Wachtwoord: het wachtwoord dat u voor de mailbox heeft ingesteld

Verzend nooit mail via poort 25. Deze poort is uitsluitend voor server-naar-server verkeer. mailcow biedt daar geen geauthentiseerde submission aan. Verzoeken van een client op deze poort worden geweigerd. Als een client Relay access denied rapporteert, probeert deze te verzenden via poort 25 of zonder authenticatie. Schakel over naar poort 465 of 587 met uw mailbox-gegevens.

Stap 9 — Maak een back-up van de essentiële gegevens

mailcow levert een back-upscript dat snapshots maakt van alle stateful volumes. Voer dit script uit naar een externe schijf of een gemount remote volume:

sudo MAILCOW_BACKUP_LOCATION=/opt/mailcow-backups \
  ./helper-scripts/backup_and_restore.sh backup all

all legt zes onderdelen vast. Het verlies van één onderdeel betekent dataverlies: vmail (de eigenlijke mailboxen), crypt (de sleutels voor de vmail-decryptie — onbruikbaar zonder deze sleutels), mysql (de MariaDB met domeinen, gebruikers, aliassen en instellingen), redis (de status van de queue en cache), rspamd (geleerde spam/ham-gegevens), en postfix (de mail queue). Het script draait in een helper container die gecomprimeerde archieven schrijft. Hierdoor blijven de back-ups consistent terwijl de stack actief is. Automatiseer dit met een dagelijkse cron job en voeg --delete-days 14 toe om oude sets te verwijderen. Herstellen gebeurt met hetzelfde script via restore. Hiermee worden de snapshots vermeld en kunt u selecteren welke gegevens u wilt herstellen. Een back-up die nooit is getest via een restore is een hoop, geen back-up — voer een test uit op een schone VPS.

Stap 10 — Updaten volgens een schema

mailcow wordt bijgewerkt via een eigen script. Dit script haalt nieuwe code op, migreert mailcow.conf, haalt images vooraf op en herstart containers in deze volgorde:

cd /opt/mailcow-dockerized
sudo ./update.sh --check   # reports whether an update exists, changes nothing
sudo ./update.sh           # applies it

Maak eerst een back-up (Stap 9), omdat een schema-migratie moeilijk ongedaan te maken is. Er zijn regelmatig updates beschikbaar met beveiligingspatches voor internet-georiënteerde daemons. Laat een mailserver daarom niet maandenlang zonder updates draaien. Als een update ervoor zorgt dat een container de status unhealthy krijgt, geeft sudo docker compose logs --tail=50 <service>-mailcow de naam van de daemon die niet opnieuw is opgestart.

Een opmerking over hardening

mailcow gebruikt een eigen netfilter-service (netfilter-mailcow). Deze blokkeert IP-adressen die te veel verzoeken sturen naar de mail- en webmail-poorten. De mail-zijde is hierdoor standaard beveiligd. Dit beschermt echter niet de SSH-verbinding op de host zelf. Deze blijft blootgesteld aan brute-force aanvallen. Gebruik daarom Fail2ban om het SSH auth-log te monitoren in combinatie met login via SSH-keys. Gebruik een sterk wachtwoord voor de mailcow admin UI. Het is ideaal om deze UI buiten het publieke internet of achter een VPN te plaatsen.

Foutmodi, met de exacte strings

Mail queues en nooit bezorgd. Voer sudo docker compose exec postfix-mailcow postqueue -p uit, of bekijk de mail queue in de admin UI; vermeldingen staan op 'deferred' met:

status=deferred (connect to gmail-smtp-in.l.google.com[142.250.x.x]:25: Connection timed out)

Dit betekent dat poort 25 voor uitgaand verkeer is geblokkeerd door uw provider (Stap 1). Een configuratiewijziging lost dit niet op — open een ticket. Het ligt niet aan DNS of TLS; de aanwijzing is het woord timed out bij een externe MX op poort 25.

Gmail markeert alles als spam, of weigert de levering. Open het bericht in Gmail, kies "Show original" en bekijk de auth results. dkim=fail of dkim=none betekent dat uw dkim._domainkey TXT-record ontbreekt, onjuist is of nog niet is gepropageerd — publiceer exact wat de ARC/DKIM-pagina aangeeft en wacht tot de TTL is verstreken. spf=fail betekent dat de SPF/MX-records uw IP-adres niet dekken. Alignment is essentieel; één mislukte controle is voldoende om in de spam te belanden.

Afgewezen door grote providers bij verbinding. Bounces of Postfix-logs bevatten de PTR-afwijzing van Gmail:

550-5.7.25 [10.0.0.10] The IP address sending this message does not have a PTR
550-5.7.25 record setup, or the corresponding forward DNS entry does not match
550 5.7.25 the sending IP. As a policy, Gmail does not accept messages from IPs
550 5.7.25 with missing PTR records.

De 550 5.7.25 code duidt op een ontbrekende of onjuiste reverse DNS. Stel de PTR voor uw IP-adres in op mail.example.com bij de provider (Stap 2). Forward (A) en reverse (PTR) moeten overeenstemmen, en beide moeten dezelfde hostnaam gebruiken waarmee mailcow andere servers begroet.

Browser toont een certificaatwaarschuwing die niet verdwijnt. De acme-mailcow container is mislukt bij het ophalen van een echt certificaat. Controleer het logboek:

sudo docker compose logs acme-mailcow | tail -n 40

Een regel zoals Cannot validate any hostnames, skipping Let's Encrypt for 1 hour. of een mislukte challenge betekent dat poort 80 niet bereikbaar is vanaf het internet, of dat het A-record niet naar deze server wijst. Controleer of mail.example.com naar deze machine verwijst, open poort 80 en 443 in de firewall van de host, en zorg dat geen andere proces deze poorten gebruikt. Herstart de client met sudo docker compose restart acme-mailcow nadat de oorzaak is hersteld, in plaats van de wachtperiode van een uur af te wachten.

FAQ

Is self-hosting email actually worth it?

Als u eigenaarschap over uw gegevens, onbeperkte aliassen en volledige controle wilt, dan is het antwoord ja. mailcow biedt een professionele stack voor de prijs van een VPS. De leverbaarheid vereist echter constante aandacht: het monitoren van de IP-reputatie, DNS-alignement en blocklists is een blijvende taak. Voor een zakelijk e-mailadres dat essentieel is voor uw bedrijf, waarbij één dag in de spamfolder schadelijk is, is een beheerde provider de pragmatische keuze. Kies voor self-hosting als u controle belangrijker vindt dan gemak en als u bereid bent het systeem te onderhouden.

How do I know if outbound port 25 is blocked?

Voer nc -vz -w 5 gmail-smtp-in.l.google.com 25 uit vanaf de server. "succeeded!" betekent dat de poort open is; een timed out na de pauze betekent dat uw provider de poort blokkeert. Dit is de meest voorkomende reden waarom een zelfgehoste server wel e-mail kan ontvangen maar nooit kan verzenden. De enige oplossing is dat uw provider de poort opent; lokale instellingen kunnen dit niet oplossen.

Why does my mail still land in Gmail's spam folder?

Dit komt bijna altijd door een defecte authenticatieketen. Gebruik "Show original" in Gmail en zoek naar spf=pass, dkim=pass en dmarc=pass. Een dkim=fail wijst op een ontbrekend of incorrect dkim._domainkey TXT-record. Ook een mismatch in de PTR-record of een nieuwe IP zonder verzendgeschiedenis veroorzaakt problemen. Zorg eerst dat mail-tester.com een score van 10/10 geeft. Warm de IP daarna langzaam op door het aantal berichten per dag geleidelijk te verhogen, in plaats van direct een groot volume te verzenden.

What exactly do I need to back up?

Voer backup_and_restore.sh backup all uit en bewaar de volledige set buiten de server. Deze backup bevat vmail (de mailboxen), crypt (de sleutels voor de decryptie), de MariaDB-database (domeinen, gebruikers, aliassen, instellingen), Redis, de geleerde data van Rspamd en de Postfix-wachtrij. De crypt-volume wordt vaak vergeten; zonder deze volume is de vmail-backup onleesbare ciphertext. Test een restore minimaal één keer op een testomgeving.

Can I run mailcow on a 2 GB VPS?

Niet zonder problemen. generate_config.sh biedt de optie om ClamAV uit te schakelen bij minder dan circa 2.5 GiB. Zelfs dan concurreren Rspamd, ClamAV, Dovecot en MariaDB om het geheugen. Bij enige echte belasting zult u tegen swap-limieten aanlopen en OOM-kills ervaren. Beschouw 6 GiB plus 1 GiB swap als het minimum voor een stabiele installatie voor één gebruiker. Schakel over naar 8 GiB zodra meer dan twee personen het systeem gebruiken.

#mailcow#email#self-hosting#docker#dns