SSD Nodes Learn
Mga Gabay Matt ConnorNi Matt Connor · Na-update 2026-07-24

Mailcow sa VPS: paano para sa Gmail

I-check muna ang outbound port 25 bago mag-install ng mailcow. Iwasan ang Gmail 550 5.7.25 PTR rejection sa pamamagitan ng tamang DNS configuration.

Ang iyong bubuuin

Isang kumpletong mail server sa sarili mong server: SMTP para sa pagpapadala at pagtanggap ng email, IMAP para sa sync ng iyong phone at laptop, isang webmail client, at isang spam filter na nag-iiscore sa bawat mensahe sa parehong direksyon. Pinagsasama ng mailcow-dockerized ang Postfix, Dovecot, Rspamd, SOGo webmail, MariaDB, Redis, at isang ACME client sa isang Docker Compose stack, kaya hindi ang software ang mahirap na bahagi. Mapapatakbo mo na ito sa loob ng kalahating oras.

Ang mahirap na bahagi ay ang lahat ng nasa paligid nito. Ang email ay ang serbisyo kung saan ang ibang bahagi ng internet ay hindi agad nagtitiwala sa isang bagong server. Ang agwat sa pagitan ng "gumagana ito" at "kinakain ng Gmail ang lahat ng mensahe" ay nakadepende sa apat na DNS records at isang IP-reputation setting na maaaring hindi mo lubos na kontrolado. Basahin ang mga prerequisites sa ibaba bago mag-rent ng server. Kung pagkatapos magbasa ay magpasya kang hindi sulit ang hirap sa reputation, valid na sagot iyon — ang aming rundown sa kung ano ang sulit i-self-host sa 2026 na naglilista ng mga email sa ilalim ng "only if you mean it" dahil sa mga eksaktong rason na ito.

Ang mga prerequisites ay ang mismong proyekto

Kapag may kulang sa mga ito, hindi darating ang mga ipapadala mong email. Narito ang listahan base sa dalas ng nagiging sanhi ng error:

Dapat bukas ang outbound port 25. Nagpapadala ang iyong server sa Gmail at Microsoft gamit ang TCP port 25. Maraming VPS at cloud providers ang naka-block sa outbound 25 by default para iwas spam. Ang block na ito ay silent — walang error sa boot at mukhang healthy ang lahat, pero ang mail ay mananatili lang sa queue habambuhay. I-test ito bago mag-install ng kahit ano. Kung blocked ito, ang tanging solusyon ay mag-submit ng support ticket sa provider para buksan ito; ang iba ay binubuksan ito para sa mga lumang account, ang iba naman ay hindi kailanman gagawin.

Malinis na IP na may maayos na reputation. Ang mga recycled na VPS IP ay madalas nang nasa blocklists dahil sa spam ng nakaraang tenant. I-check ang iyong IP sa mga serbisyo tulad ng Spamhaus lookup o mxtoolbox bago magsimula. Ang isang listed IP ay nangangahulugan ng mga rejection na hindi kayang ayusin sa pamamagitan ng coding.

Kontrol sa DNS at tamang PTR record. Kailangan mong magdagdag ng mga record sa zone ng iyong domain, at kailangan mo ng reverse DNS (PTR) para ang server IP ay nakaturo pabalik sa iyong mail hostname. Ang PTR ay halos hindi kailanman naka-set sa iyong DNS panel — nasa kontrol ito ng may-ari ng IP, kaya dapat itong i-set sa control panel ng iyong VPS provider o sa pamamagitan ng ticket.

Ang 6 GiB RAM at 2 vCPU ang minimum para sa maayos na takbo. Ang minimum ng mailcow para sa private install ay 6 GiB RAM plus 1 GiB swap, at pinapayo ang 8 GiB kapag marami na ang gumagamit nito. Kapag mababa sa 2.5 GiB, may opsyon ang generate_config.sh na i-disable ang ClamAV virus scanner para hindi magsimulang mag-kill ng containers ang kernel. Maglaan ng 20 GB na SSD sa simula.

Isang DNS name, hindi lang basta IP. Pumili ng hostname tulad ng mail.example.com. Ang pangalang ito ang magiging MAILCOW_HOSTNAME mo, ang iyong TLS certificate subject, ang iyong PTR target, at ang iyong SMTP banner. Panatilihin itong consistent sa lahat ng bahagi.

Step 1 — Patunayan na open ang outbound port 25

Gawin muna ito. Walang saysay ang ibang steps kung mabigo ito. Mula sa bagong VPS, subukang mag-open ng SMTP conversation sa isang totoong mail server:

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

Kapag gumagana, agad itong magbibigay ng resulta:

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

Kapag blocked ang port, maghihintay ng limang segundo bago mag-fail:

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

Ang timeout na iyan ang indikasyon ng block. Ito ay network filter sa panig ng provider, hindi sa iyong firewall, kaya walang local change ang makakaayos nito. Mag-open ng ticket: "Please enable outbound TCP port 25 for my VPS at <IP>; I am running a legitimate mail server." Huwag munang mag-install ng mailcow hangga't hindi "succeeded" ang resulta. Tandaan na ang inbound 25 (mga server na kumokonekta sa iyo) ay ibang path at karaniwang open — ang outbound side ang madalas i-throttle ng mga provider.

Step 2 — I-set na ang mga DNS record ngayon

Matatagalan ang propagation ng mga DNS change, kaya i-publish na ang lahat ng posibleng record bago mag-install. I-assume na ang domain mo ay example.com, ang mail host ay mail.example.com, at ang IP ay 10.0.0.10. Sa iyong zone, i-create ang mga ito:

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"

Ang SPF record ay nagsasabing "ang MX ko lang ang pwedeng magpadala para sa domain na ito, i-reject ang iba". Simulan ang DMARC sa p=none para ma-monitor ang mga report nang hindi naba-bounce ang sarili mong mail; i-tighten ito sa p=quarantine at pagkatapos ay p=reject kapag napatunayan na ang alignment. Dalawang record ang sadyang kulang: ang DKIM, na i-ge-generate ng mailcow para sa iyo sa Step 6, at ang PTR, na i-se-set mo ngayon sa panel ng iyong provider.

I-set ang PTR (reverse DNS) para sa 10.0.0.10 sa mail.example.com — ang eksaktong value ng MAILCOW_HOSTNAME. Ito ang isang record na madalas makalimutan ng mga tao, at ito ang dahilan kung bakit nire-reject ng mga malalaking provider ang mail. Kung walang rDNS field ang iyong panel, mag-raise ng ticket.

Step 3 — Install Docker

Kailangan ng mailcow ang Docker Engine na may Compose v2 plugin. Gamitin ang official convenience script ng Docker sa halip na ang docker.io package ng Ubuntu, dahil walang kasamang Compose plugin ang Ubuntu package:

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

Dapat makakita ka ng Docker Compose version v2.x na linya. Kung ang docker compose version ay nag-print ng docker: 'compose' is not a docker command, installed ang Docker Engine pero wala ang Compose plugin. I-install ang plugin mula sa repository ng Docker — i-rerun ang script sa itaas, o sundin ang our Docker Compose basics guide, na nagse-setup ng dalawa mula sa sariling apt repository ng Docker.

Step 4 — I-clone ang mailcow at i-generate ang config

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

Siguraduhing naka-print ang umask bilang 0022 — hindi magbu-build ang mailcow kung hindi tugma ang file mask, at ang fresh Ubuntu 24.04 root shell ay mayroon nang 0022. Itatanong ng script ang pinaka-importanteng detalye: ang fully qualified hostname. I-enter ang mail.example.com — dapat eksaktong tumugma ang value na ito sa iyong A record at PTR. Isusulat nito ang mailcow.conf, ang tanging environment file na binabasa ng buong stack. Buksan ito kung kailangang palitan ang mga web port (HTTP_PORT, HTTPS_PORT) o i-disable ang ClamAV sa mga machine na may maliit na capacity:

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

Ang SKIP_FTS=y ay isa pang setting para sa low-RAM na box: ang full-text search ang pangalawang malakas kumonsumo ng memory ayon sa docs ng mailcow, at ang pag-skip dito ay magreresulta lamang sa kawalan ng body-text search sa webmail.

Hayaan lang ang HTTP_PORT=80 at HTTPS_PORT=443 maliban kung may ibang service na sa host ang gumagamit sa mga ito — kailangang accessible ang port 80 mula sa internet para sa built-in ACME client ng mailcow upang makakuha ng certificate. Ito ang dahilan kung bakit hindi dapat gumamit ng separate nginx-plus-Certbot setup sa parehong box; ang mailcow ang nag-i-issue at nagre-renew ng sarili nitong TLS internally, at masisira ang proseso kung may pangalawang service na gumagamit ng 80/443.

Step 5 — Simulan ang stack at mag-log in

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

Magda-download ang pull ng humigit-kumulang dalawang dosenang images; maghintay ng ilang minuto. Kapag ipinapakita na ng docker compose ps ang lahat ng container na running (o healthy), buksan ang https://mail.example.com sa isang browser. Ang default na admin login ay username na admin at password na moohoo. Palitan agad ang password na iyan sa admin UI sa ilalim ng Access → Administrators. Kung mag-warn ang browser ng NET::ERR_CERT_AUTHORITY_INVALID, hindi pa na-issue ang ACME certificate — tingnan ang ACME failure sa ibaba bago isiping sira ito; normal ang self-signed placeholder sa unang minuto o dalawang minuto.

Step 6 — Magdagdag ng domain, mailbox, at i-publish ang DKIM

Sa admin UI, buksan ang Mail Setup page (Configuration → Mail Setup). Sa ilalim ng Domains tab, i-click ang Add domain at i-enter ang example.com. Pagkatapos, sa ilalim ng Mailboxes, i-click ang Add mailbox para gumawa ng you@example.com na may password. Ang mailbox na ito ay maaari nang gamitin via IMAP.

Para sa DKIM key: Pumunta sa Configuration → ARC/DKIM keys. Maaaring may generated na key ang mailcow pagkatapos mong i-add ang domain. Kung wala, gumawa ng bago doon — piliin ang domain, panatilihin ang selector na dkim, piliin ang 2048-bit, at i-click ang Add. I-copy ang mahabang TXT value na lalabas at i-publish ito bilang:

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

Ang Domains page ng mailcow ay may DNS button na naglilista ng lahat ng kailangang record. Nagpapakita ito ng green tick o red cross base sa kung ano ang naka-publish na. Gamitin ito bilang checklist — siguraduhing green ang lahat ng row bago i-test ang deliverability. Ang red na DKIM row pagkatapos i-publish ay karaniwang nangangahulugang mali ang pagkakahati ng key sa mga TXT chunks; ang 2048-bit key ay mas mahaba sa 255-character limit para sa isang single TXT string. I-paste ito bilang isang logical value at hayaan ang iyong DNS host na hatiin ito sa mga chunks.

Step 7 — I-test ang deliverability at abutin ang 10/10

Pumunta sa mail-tester.com, i-copy ang random address na ipapakita nito, at magpadala ng mensahe mula sa iyong bagong mailbox — mag-log in sa SOGo webmail sa https://mail.example.com/SOGo at magpadala mula doon. Pagkatapos, i-click ang "Then check your score".

Targetin ang 10/10. Narito ang mga karaniwang dahilan ng pagbaba ng score:

  • SPF not aligned — kulang ang iyong MX/SPF record o hindi kasama ang sending IP. I-verify muli ang SPF TXT.
  • DKIM signature does not verify — kulang, hindi pa kumakalat (propagating), o mali ang dkim._domainkey TXT. Ito ang pinakakaraniwang pagkakamali.
  • No PTR / PTR mismatch — hindi nagre-resolve ang reverse DNS sa mail.example.com. Ayusin ito sa provider.
  • Listed on a blocklist — dahil sa reputasyon ng iyong IP. Mag-request ng delisting o humingi ng bagong IP.

Huwag muna magpadala ng totoong email sa Gmail o Outlook hangga't hindi ito umaabot sa 10/10. Ang mababang score na sinamahan ng bagong IP ang magiging dahilan para ma-flag ang iyong domain sa unang araw pa lang.

Step 8 — Mag-connect sa isang real mail client

I-set up ang Thunderbird, Apple Mail, o ang iyong phone gamit ang mga settings na ito. Ang server host para sa lahat ay mail.example.com:

  • IMAP: port 993, SSL/TLS (o 143 gamit ang STARTTLS)
  • SMTP submission: port 465, SSL/TLS (o 587 gamit ang STARTTLS)
  • Username: ang buong address, you@example.com
  • Password: ang password ng mailbox na iyong itinakda

Huwag magpapadala ng client mail gamit ang port 25 — ang port na ito ay para sa server-to-server lamang. Hindi nag-aalok ang mailcow ng authenticated submission sa port na ito, kaya tatanggihan ang anumang client na gumagamit nito. Kung mag-report ang client ng Relay access denied, sinusubukan nitong magpadala sa port 25 o nang walang authentication; i-switch ito sa 465 o 587 gamit ang iyong mailbox credentials.

Step 9 — I-back up ang mga mahahalagang data

May kasamang backup script ang mailcow na kumukuha ng snapshot ng bawat stateful volume. Patakbuhin ito sa isang external disk o sa isang mounted remote:

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

Kinukuha ng all ang anim na bagay, at ang pagkawala ng alinman sa mga ito ay nangangahulugang may mawawalang data: vmail (ang mismong mga mailbox), crypt (ang mga key para i-decrypt ang vmail — hindi ito magagamit kung wala ito), mysql (ang MariaDB na naglalaman ng mga domain, user, alias, at settings), redis (ang queue at cache state), rspamd (ang learned spam/ham), at postfix (ang mail queue). Tumatakbo ito sa loob ng isang helper container na gumagawa ng compressed archives, kaya mananatiling consistent ang mga backup kahit live ang stack. I-automate ito gamit ang nightly cron job, at magdagdag ng --delete-days 14 para burahin ang mga lumang set. Ang pag-restore ay gamit ang parehong script na may restore, na naglilista ng mga snapshot at nagbibigay-daan para pumili kung ano ang ibabalik. Ang backup na hindi pa na-test-restore ay isang pag-asa lamang, hindi isang backup — magsagawa ng isang dry run sa isang scratch VPS.

Step 10 — Update on a schedule

Ang mailcow ay nag-a-update gamit ang sarili nitong script. Kinukuha nito ang bagong code, ini-migrate ang mailcow.conf, pini-prefetch ang mga images, at ni-re-restart ang mga container sa pagkakasunod-sunod na ito:

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

Mag-back up muna (Step 9), dahil mahirap i-reverse ang schema migration. Madalas ang mga update at kasama rito ang mga security fix para sa mga internet-facing daemon, kaya huwag hayaang lumipas ang ilang buwan nang hindi nag-u-update ng mail server. Kung ang isang update ay nagresulta sa unhealthy container, tinutukoy ng sudo docker compose logs --tail=50 <service>-mailcow ang daemon na hindi muling nag-start.

A note on hardening

Ang mailcow ay gumagamit ng sariling netfilter service (netfilter-mailcow) na nagba-ban ng mga IP na nag-a-attack sa mail at webmail ports. Dahil dito, protektado na ang mail component out of the box. Hindi nito sakop ang SSH sa mismong host, na exposed pa rin at madalas i-brute-force. Gamitin ang build na ito kasama ang Fail2ban para sa pag-monitor ng SSH auth log at key-only login. Siguraduhing may malakas na password ang mailcow admin UI, at mas mainam kung hindi ito naka-expose sa public internet o nakalagay sa likod ng isang VPN.

Failure modes, with the exact strings

Mail queues and never delivers. Patakbuhin ang sudo docker compose exec postfix-mailcow postqueue -p, o tingnan ang mail queue sa admin UI; ang mga entry ay naka-defer na may:

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

Ibig sabihin nito ay blocked ang outbound port 25 ng iyong provider (Step 1). Hindi ito maaayos sa config — mag-open ng ticket. Hindi ito problema sa DNS o TLS; malalaman ito sa salitang timed out laban sa isang remote MX sa port 25.

Gmail marks everything spam, or bounces it. Buksan ang message sa Gmail, piliin ang "Show original", at basahin ang auth results. Ang dkim=fail o dkim=none ay nangangahulugang kulang, mali ang format, o hindi pa propagated ang iyong dkim._domainkey TXT — i-republish nang eksakto ang nakasaad sa ARC/DKIM page at maghintay sa TTL. Ang spf=fail ay nangangahulugang hindi sakop ng SPF/MX records ang iyong IP. Napakahalaga ng alignment; sapat na ang isang failing check para mapunta sa spam.

Rejected by large providers on connect. Ang mga bounce o Postfix logs ay nagpapakita ng Gmail's PTR rejection:

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.

Ang 550 5.7.25 code ay nangangahulugang kulang o hindi tugma ang reverse DNS. I-set ang PTR para sa iyong IP sa mail.example.com sa iyong provider (Step 2). Dapat magtugma ang Forward (A) at reverse (PTR), at dapat parehong nakapangalan sa host na ginagamit ng mailcow sa pakikipag-ugnayan sa ibang servers.

Browser shows a certificate warning that never clears. Nabigo ang acme-mailcow container na kumuha ng totoong cert. Suriin ang log nito:

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

Ang linya na katulad ng Cannot validate any hostnames, skipping Let's Encrypt for 1 hour. o isang challenge failure ay nangangahulugang hindi ma-reach ang port 80 mula sa internet, o ang A record ay hindi nakaturo sa server na ito. Siguraduhin na ang mail.example.com ay nagre-resolve sa box, i-open ang 80 at 443 sa host firewall, at tiyaking walang ibang proseso ang gumagamit sa mga port na ito. Pagkatapos ayusin ang sanhi, i-restart ang client gamit ang sudo docker compose restart acme-mailcow sa halip na maghintay sa isang oras na back-off.

FAQ

Sulit ba talaga ang mag-self-host ng email?

Kung gusto mo ng data ownership, unlimited aliases, at full control, oo — nagbibigay ang mailcow ng professional stack sa presyo ng isang VPS. Ngunit ang deliverability ay isang tuluy-tuloy na gawain: hindi natatapos ang pag-aalaga sa IP reputation, DNS alignment, at blocklist monitoring. Para sa mga mission-critical na business address kung saan may mawawalang kita kapag napunta sa spam folder, mas praktikal ang managed provider. Mag-self-host lamang kung mas mahalaga sa iyo ang control kaysa sa convenience at handa kang mag-maintain nito.

Paano ko malalaman kung blocked ang outbound port 25?

I-run ang nc -vz -w 5 gmail-smtp-in.l.google.com 25 mula sa server. Ang "succeeded!" ay nangangahulugang open ang port; ang timed out pagkatapos ng pause ay nangangahulugang blocked ito ng iyong provider. Ito ang pinakakaraniwang dahilan kung bakit ang isang self-hosted server ay nakakatanggap ng mail pero hindi makapag-send; ang tanging solusyon ay ang pag-open ng port ng iyong provider — walang local setting ang makakaayos nito.

Bakit napupunta pa rin ang email ko sa spam folder ng Gmail?

Halos laging dahil ito sa sirang authentication chain. Gamitin ang "Show original" sa Gmail at hanapin ang spf=pass, dkim=pass, at dmarc=pass. Ang dkim=fail ay indikasyon ng kulang o maling dkim._domainkey TXT record; ang PTR mismatch o bagong IP na walang sending history ay nakakasama rin. Siguraduhing 10/10 ang score sa mail-tester.com bago mag-warm up ng IP nang dahan-dahan — simulan sa ilang mensahe bawat araw hanggang sa lumaki ang volume — imbes na mag-blast agad ng maraming email sa unang araw.

Ano ba ang eksaktong kailangan kong i-back up?

I-run ang backup_and_restore.sh backup all at i-save ang buong set sa labas ng server. Kasama rito ang vmail (ang mga mailbox), crypt (ang mga keys para i-decrypt ang mga ito), ang MariaDB database (domains, users, aliases, settings), Redis, ang learned data ng Rspamd, at ang Postfix queue. Ang crypt volume ang madalas makalimutan ng mga user — kung wala ito, ang vmail backup ay magiging unreadable ciphertext. Mag-test ng restore sa isang scratch box kahit isang beses.

Kaya ko bang mag-run ng mailcow sa isang 2 GB VPS?

Hindi ito komportable. Nag-aalok ang generate_config.sh na i-disable ang ClamAV kung mababa sa 2.5 GiB ang memory, pero kahit ganoon, nag-aagawan ang Rspamd, ClamAV, Dovecot, at MariaDB sa memory. Magkakaroon ka ng swap at OOM kills sa ilalim ng kahit anong real load. Ituring ang 6 GiB plus 1 GiB swap bilang minimum para sa isang stable na single-user install, at lumipat sa 8 GiB sa sandaling may higit sa dalawang tao na gumagamit nito.

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