From 729988d0301bf06f3b78db9110d77a42948c7ab9 Mon Sep 17 00:00:00 2001 From: rbsetiawan Date: Sat, 4 Jul 2026 00:50:41 +0700 Subject: [PATCH] docs: handover mailcow fetchmail sogo relay session Co-authored-by: Cursor --- Mailcow/.env.example | 93 ++++++ Mailcow/.gitignore | 15 + Mailcow/docs/ai-session-summary.md | Bin 0 -> 10442 bytes Mailcow/docs/changelog.md | 15 + Mailcow/docs/context-index.md | 149 +++++++++ Mailcow/docs/deployment.md | 150 +++++++++ Mailcow/docs/environment.md | 149 +++++++++ Mailcow/docs/issues.md | 23 ++ Mailcow/docs/notes/deployment-sizing.md | 193 ++++++++++++ .../notes/email-sync-migration-concept.md | 248 +++++++++++++++ Mailcow/docs/notes/ldap-ad-mailcow.md | 298 ++++++++++++++++++ Mailcow/docs/notes/storage-nas-qnap.md | 245 ++++++++++++++ Mailcow/docs/project-status.md | 74 +++++ Mailcow/docs/server.md | 204 ++++++++++++ Mailcow/docs/todo.md | 47 +++ Mailcow/infra/nginx/sync.geonet.co.id.conf | Bin 0 -> 2628 bytes Mailcow/scripts/fix-mailcow-dns-ufw.sh | Bin 0 -> 1544 bytes Mailcow/scripts/fix-ssh-key.ps1 | 41 +++ Mailcow/scripts/install-dockge-agent.sh | 33 ++ Mailcow/scripts/install-fetchmail-support.sh | 88 ++++++ Mailcow/scripts/install-mailcow.sh | Bin 0 -> 2300 bytes Mailcow/scripts/prepare-mailserver.sh | 116 +++++++ .../scripts/remote-reset-authorized-keys.sh | 35 ++ Mailcow/scripts/setup-dockge-agent-user.sh | 13 + Mailcow/scripts/setup-ssh-key.ps1 | 13 + Workspace-Session.md | Bin 0 -> 3588 bytes 26 files changed, 2242 insertions(+) create mode 100644 Mailcow/.env.example create mode 100644 Mailcow/.gitignore create mode 100644 Mailcow/docs/ai-session-summary.md create mode 100644 Mailcow/docs/changelog.md create mode 100644 Mailcow/docs/context-index.md create mode 100644 Mailcow/docs/deployment.md create mode 100644 Mailcow/docs/environment.md create mode 100644 Mailcow/docs/issues.md create mode 100644 Mailcow/docs/notes/deployment-sizing.md create mode 100644 Mailcow/docs/notes/email-sync-migration-concept.md create mode 100644 Mailcow/docs/notes/ldap-ad-mailcow.md create mode 100644 Mailcow/docs/notes/storage-nas-qnap.md create mode 100644 Mailcow/docs/project-status.md create mode 100644 Mailcow/docs/server.md create mode 100644 Mailcow/docs/todo.md create mode 100644 Mailcow/infra/nginx/sync.geonet.co.id.conf create mode 100644 Mailcow/scripts/fix-mailcow-dns-ufw.sh create mode 100644 Mailcow/scripts/fix-ssh-key.ps1 create mode 100644 Mailcow/scripts/install-dockge-agent.sh create mode 100644 Mailcow/scripts/install-fetchmail-support.sh create mode 100644 Mailcow/scripts/install-mailcow.sh create mode 100644 Mailcow/scripts/prepare-mailserver.sh create mode 100644 Mailcow/scripts/remote-reset-authorized-keys.sh create mode 100644 Mailcow/scripts/setup-dockge-agent-user.sh create mode 100644 Mailcow/scripts/setup-ssh-key.ps1 create mode 100644 Workspace-Session.md diff --git a/Mailcow/.env.example b/Mailcow/.env.example new file mode 100644 index 0000000..eca470d --- /dev/null +++ b/Mailcow/.env.example @@ -0,0 +1,93 @@ +# Mailcow — template konfigurasi (copy ke .env, isi secret) +# Jangan commit .env — lihat docs/environment.md + +# ============================================================================= +# Core install (mailcow-dockerized generate_config.sh) +# ============================================================================= +MAILCOW_HOSTNAME=sync.geonet.co.id +MAILCOW_VM_IP=10.100.1.28 +MAILCOW_TIMEZONE=Asia/Jakarta +MAILCOW_PUBLIC_IP=117.102.73.102 +MAILCOW_STACK_PATH=/opt/mailcow-dockerized + +# API password Mailcow (generate: openssl rand -base64 32) +MAILCOW_API_KEY= + +# Let's Encrypt — set y hanya untuk lab tanpa DNS publik +SKIP_LETS_ENCRYPT=n +ADDITIONAL_SAN= + +# ============================================================================= +# Admin UI Mailcow (https://mail.gisportal.id) +# ============================================================================= +MAILCOW_ADMIN_USER=admin +MAILCOW_ADMIN_PASSWORD= + +# ============================================================================= +# Mailbox utama — integrasi Zammad +# ============================================================================= +MAILCOW_SUPPORT_EMAIL=support@geonet.co.id +MAILCOW_SUPPORT_PASSWORD= + +# ============================================================================= +# Domain email +# ============================================================================= +MAILCOW_DOMAIN_PRIMARY=geonet.co.id +MAILCOW_DOMAIN_SECONDARY=gegeo.my.id + +# ============================================================================= +# Port layanan (default Mailcow — jangan ubah kecuali ada konflik) +# ============================================================================= +MAILCOW_PORT_SMTP=25 +MAILCOW_PORT_SMTPS=465 +MAILCOW_PORT_SUBMISSION=587 +MAILCOW_PORT_IMAPS=993 +MAILCOW_PORT_POP3S=995 +MAILCOW_PORT_HTTPS=443 + +# ============================================================================= +# Zammad integration (dari container Zammad → Mailcow) +# Gunakan hostname internal Docker setelah stack up +# ============================================================================= +ZAMMAD_SMTP_HOST=mailcowdockerized-postfix-mailcow-1 +ZAMMAD_SMTP_PORT=587 +ZAMMAD_SMTP_SSL=starttls +ZAMMAD_SMTP_USER=support@geonet.co.id +ZAMMAD_SMTP_PASSWORD= + +ZAMMAD_IMAP_HOST=mailcowdockerized-dovecot-mailcow-1 +ZAMMAD_IMAP_PORT=993 +ZAMMAD_IMAP_SSL=yes +ZAMMAD_IMAP_USER=support@geonet.co.id +ZAMMAD_IMAP_PASSWORD= + +# ============================================================================= +# LDAP — Active Directory (Identity Provider Mailcow) +# Panduan: docs/notes/ldap-ad-mailcow.md +# ============================================================================= +LDAP_HOST=10.100.1.40 +LDAP_PORT=389 +LDAP_BASE_DN=DC=gisportal,DC=id +LDAP_BIND_DN=Administrator@gisportal.id +LDAP_BIND_PASSWORD= +LDAP_GROUP_DN=CN=Mail-Users,CN=Users,DC=gisportal,DC=id +LDAP_USER_FILTER=(&(objectClass=user)(objectCategory=person)(memberOf=CN=Mail-Users,CN=Users,DC=gisportal,DC=id)) +LDAP_LOGIN_ATTRIBUTE=mail +LDAP_MAIL_ATTRIBUTE=mail +LDAP_SYNC_INTERVAL_MIN=15 + +# ============================================================================= +# Legacy SMTP cPanel (sumber migrasi — Zammad pakai ini sampai Mailcow OK) +# ============================================================================= +LEGACY_SMTP_HOST=sc138.idcloudhosting.cloud +LEGACY_SMTP_PORT=465 +LEGACY_SMTP_SSL=yes +LEGACY_SMTP_SSL_VERIFY=yes +LEGACY_SMTP_USER=support@geonet.co.id +LEGACY_SMTP_PASSWORD= + +# ============================================================================= +# DNS (referensi — set di panel DNS domain, bukan di Mailcow) +# ============================================================================= +DNS_MX_HOST=sync.geonet.co.id +DNS_SPF_INCLUDE=include:sync.geonet.co.id diff --git a/Mailcow/.gitignore b/Mailcow/.gitignore new file mode 100644 index 0000000..568c706 --- /dev/null +++ b/Mailcow/.gitignore @@ -0,0 +1,15 @@ +# Environment & secrets — never commit +.env +.env.* +!.env.example + +# Mailcow generated config on server +mailcow.conf +data/ + +# OS / editor +.DS_Store +Thumbs.db +*.swp +.idea/ +.vscode/ diff --git a/Mailcow/docs/ai-session-summary.md b/Mailcow/docs/ai-session-summary.md new file mode 100644 index 0000000000000000000000000000000000000000..4da30b1eea019616e653ac6d998bfaf80e58e836 GIT binary patch literal 10442 zcmb`N+iq0J6^833H{2!<&?BV8khqNv41t6Z2hT7TW8ASlkOYlrpD{kF+s1a3r^plM z|LX76wRi8`#z@HO?tQ3QwT}N26}psK5E=RPgvoHydGDx`RaDMtvBd%Aun zO}rSd)W-YbHMC~4MEhEAOY&W4gDwm{UoEAD-zK-}CroQ7$}|881fspcRk2D=yEq5?aH9 zp@g5|1ApjrB+b6YZe&jO@>@I-Y0oroDBka8O1AvV3Ki3Tljh|6=HQmJQ}@z^?4>`Z zORcyidU)h#U8DKQh$5DnHpOZy`ru95Svu^|5w)IpJQgiH@PFTR(xguM;{IIvLxTgY z{4Dh~@~-}fFgV%GcedlcbVKyvv-kkkL05Ma7jU+cx!)8mw2Ahr9)?eC=vkdBIM`C8 z-j_FYHDX(Lhnd2*bdFu&0zBwe-aJVUHU3fN77M)+H?}qi0TuYiavPcnZotVWeYW)8 z+^&h=S6YElM1*zrXWbv@8c#iv-HbO}!~0HU9khg<7`dyD{pCc|cCu&T8N6kjS8Uhz zw&tFvP0`064>Tt%fG>O$74$g}=e!9y9pTW%HeLx0d(?)08G#+n(qA-YQ`aCWe(_6M zlt1>yc3acf5}CG0+z+LL$>?r+AgEIHqpt2hX6qmwk#aPW&^%Zli|LJgyd!R23-^|_ z(weyXDf9d9JO^p1Eb$H8QIa$@pz)bW0YThFA}>?#Pt*y5+{t9H$*2Fglo~zcR1rEd1ZPYienlWnI}2+Q(WMPKoe>Yw&O->ut#&$%K2NL7sD!H>>AV zd!P(?yv`$;4?j4`NY>;S46~kyXR!D{9<-k&h}fv}h=;>bwbC@!luEPC!^#K?F2py; zgMWHHdccm;^a0;!r%tcnMW)RrOHmPF8|TKtRU2ir0;VGQbu__sBJGd* zT!{NYMtQs{a&Q}UTM_MCN=LIzq48H|XKIi;s)U`>`tr(?>|=8+zCR~V#`g<~MXi91x6@Nq6ue(ot|P-h8_u`n z+dS{557MjaV6H4B?>~r7a`{EhUJ(mmzcH9AcNY&wD7Z7y5WGxcA2tRf>0|as`Pa1C zYc~3#zO-m$@5-_};*zXKtYJ0RNKaHTKUNI{I#Ad3^ad%6@6ec6jrK^R?~Ok5((FQI z23Dj}yA*|bCUI_Fku}fqi14Ff=8Gz^=$d#jx6~E=sr&|?)l5TPT9$=+ni=(+*Dm?$ zLXvNe^}!1DI^)^3E4p?swH+~nMToz->^tCCRNE`6LfY*7y);NZaGce1TR~c^yPxMf zdw4Y0tI`ojO9!(dDsW&-CljK7M`+3M)3RN?LWsC-;w(~v;dnLli9Qg)eUr5~lwV>M zxGB{V@1kz)r@!faU*66*$LXmkf=fmkG8__Ol`1`Oh1!RDc9LF`Li7ba@oe9+FA-1V z#~Gml9E7~ZJARdnXw_JvWVgDo(0cYI35BI0R{tI4IU@^Afp4 zsu3ir0&*tW0AVI|VEvMrCi@bsgU1|a{sNQH9C~op#G7qfy6k>>uQy-cz5OL!oNfg7CM;e)Vmv9r|08 z?Mmjr+SnlWZoZsJ%8bG*S+6QlcvUs~+veX!7BX+U$D+^3s*zsJxVJ|f=DOojxK9SER*T+qBHA6%Wwq1%j2e&Hl-00$w>6_b&U#ps z*11~m3yETgEvozD{Yv`?u zZ~EX((SR>_rxFK~_A<>MGzuMq1FVEr-s@_z_x?=?)>Y5Ye8b+i() z-q?v+gPq>1N+nHxI1(qNHgE+Fx3NPM`@`5Tx;eaKOEeG1ec5&V^hJ$5Z&&Q}KUj*L z7@`Hdk7tt+-dAUS^BwyBNGstR=)y?jJV0G-tzeI~yjDjq{Om$fe$wd8Oe^B+X7#*v zGTGI_6?p<3c-P(M3f_Y#UeD^)9rOn}#e1k{Gvh38jGde4#KSv4eEcNNC4J`eI@{tx z-|Wfb{oX4_BjnuhEbn!r59(VqSMQ^-TGRXL`oa(04NzY`kS{+PS!hxx&cd-0k%QjR zk2{9?+A}r1ENdij6t#d?Ed58E6yfX5%vRNK>E5Crt)Au}akCNvu?Bihl)C#Y*!x^@ zZXXDbtXCG;no7qg%RDp?Cni2KB)gbKFTbz$!R->cYrdI>*7Lmry8lLbyV8hXO(RZ$>k&5t@-`ck@E_#ub6OO3kQGIXz{ZAt2< zNt`vILC%|E2MU^X@4clcpTP1JOK&W zGsRAL+%#*Lk9D0_F6vXxCcp?$A9U2*?i5ajrQdAFU}Se$KTLsAs!} zR-)I49%NemNd#CjY7e5m>|d1UoJ~zq4iu+;C-%;=hJ8LvW!&BoQze1s=#cC|hOgIV zaL)M!2*+Em)6ZD3Bs6`g*n6j*V=etE{qY|ct3s>~x_Yi>YkJ3%#au_xv6TPGsAo(n z?2?1HD+t1yKqNeY^JC+}tj4{RwCJkoanv!`qMSbRe-6lMUHbo2+GbwAABC0rqU5aJ zku^T+dZ1tQxu@SIFHMRb8x>(lQKXJ43|`{|!*e=9Al9P>fRi%ksh&hv_cc{%y^bR< zg@3`f>+jhd7r`&No)d%f{EJ5MIjR@phPy$I1#%$Vk}r*LT=5>{ujXR+#hkFuiSoBQ zg(W`m+*PfKUC6^hMEAAh)prX?*?{{mz$1Mn(5tGE=jHT **Terakhir Diperbarui:** 2026-07-03 +> **Fase Aktif:** Fase 1 — Mailcow live, transisi MX cPanel → sync 📧 + +**Sesi terakhir:** [docs/ai-session-summary.md](./ai-session-summary.md) + +--- + +## Filosofi + +Proyek ini menerapkan **AI Native Development**: +- Repository = sumber kebenaran utama (Single Source of Truth) +- AI tidak boleh mengandalkan riwayat percakapan +- Developer sering berpindah perangkat — konteks harus tersimpan di repo +- Implementasi tanpa dokumentasi = belum selesai + +--- + +## Urutan Membaca + +1. **File ini** — peta navigasi +2. **`docs/ai-session-summary.md`** — ringkasan sesi terakhir ⭐ +3. `docs/environment.md` — variabel `.env` (tanpa secret) +3. `.env.example` → copy ke `.env` — isi password & secret +4. Dokumen spesifik task (lihat tabel di bawah) +5. `Zammad/docs/context-index.md` — integrasi email channel + +--- + +## Posisi dalam Super Apps + +``` +Internet → MX geonet.co.id → cPanel (staging, inbox kosong setelah POP3) + │ + fetchmail POP3 + delete (VM .27) + ▼ + Mailcow sync.geonet.co.id — inbox canonical (IMAP) + │ │ + Outlook user Zammad + IMAP+SMTP sync IMAP+SMTP sync +``` + +| Repo terkait | Entry point | Kapan baca | +|--------------|-------------|------------| +| **Zammad** | `Zammad/docs/context-index.md` | Channel email inbound/outbound | +| **server-connection** | `server-connection/docs/context-index.md` | LDAP AD, nginx pattern | +| **mysupperapps_FE_PWA** | `docs/context-index.md` | Mail UI `/mail` (fase berikutnya) | + +--- + +## Peta Dokumentasi + +### `docs/` — Flat Files + +| File | Isi | Status | Baca Saat | +|------|-----|--------|-----------| +| `docs/context-index.md` | **File ini** — navigasi | ✅ | Selalu | +| `docs/environment.md` | Env vars, port, integrasi Zammad | ✅ | Setup, deploy | +| `docs/project-status.md` | Status modul, milestone | ✅ | Planning | +| `docs/ai-session-summary.md` | **Ringkasan sesi terakhir** | ✅ | Lanjut kerja | +| `docs/roadmap.md` | Fase Mailcow dalam super apps | 📋 | Planning | +| `docs/todo.md` | Next actions berprioritas | ✅ | Sebelum coding | +| `docs/changelog.md` | Riwayat perubahan penting | ✅ | Referensi | +| `docs/issues.md` | Known bugs + workaround | ✅ | Debug | +| `docs/server.md` | Server, SSH, spec VM `.28` | ✅ | Deploy | +| `docs/deployment.md` | Step-by-step install Mailcow | ✅ | Deploy | +| `docs/security.md` | Credential, DNS, port 25 | 📋 | Security | + +### `docs/notes/` + +| File | Isi | +|------|-----| +| `email-sync-migration-concept.md` | **Konsep sync hosting → Mailcow → Zammad** (MX tetap cPanel) | +| `zammad-email-channel.md` | Step-by-step SMTP + IMAP Zammad ↔ Mailcow | +| `dns-cutover-geonet-co-id.md` | MX, SPF, DKIM, DMARC cutover dari cPanel | +| `storage-nas-qnap.md` | **Email di NAS QNAP** — iSCSI / NFS / backup | +| `deployment-sizing.md` | **Linux + Docker, spec VM 30+ user** | +| `ldap-ad-mailcow.md` | **LDAP AD → Mailcow** — auth + provisioning user terpusat | + +### Root repo + +| File | Isi | +|------|-----| +| `.env.example` | Template konfigurasi — **aman di-commit** | +| `.env` | Nilai aktual (password) — **gitignored** | +| `.gitignore` | Exclude secret & data Mailcow | +| `scripts/install-fetchmail-support.sh` | Install POP3 drain + systemd timer | + +--- + +## Quick Reference + +| Fungsi | URL / Path | +|--------|------------| +| Mailcow UI (target) | `https://sync.geonet.co.id` | +| Hostname mail | `sync.geonet.co.id` | +| Mailbox support (fase sync) | `support@sync.geonet.co.id` | +| Mailbox produksi (hosting) | `support@geonet.co.id` @ cPanel | +| Domain utama | `geonet.co.id` (MX tetap hosting) | +| Docker stack (target) | `/opt/stacks/mailcow/` | +| Server Mailcow | `10.100.1.28` (16 vCPU, 32 GB, 2×512 GB SSD) | +| Server Zammad | `10.100.1.24` | + +### Port layanan + +| Port | Layanan | +|------|---------| +| 25 | SMTP inbound | +| 465 | SMTPS | +| 587 | Submission (Zammad outbound) | +| 993 | IMAPS (Zammad inbound) | +| 443 | HTTPS Web UI | + +### SSH + +```bash +ssh mailcow # 10.100.1.28 +``` + +> SSH ke server **wajib minta persetujuan user** sebelum dijalankan. + +--- + +## Status saat ini (2026-07-03) + +| Item | Status | +|------|--------| +| Mailcow stack `/opt/stacks/mailcow` | ✅ | +| Domain `geonet.co.id` + DKIM generated | ✅ | +| fetchmail POP3 drain `support@` | ✅ timer 2 menit | +| Outbound relay cPanel `:587` | ✅ transisi | +| SOGo kirim/terima `support@` | ✅ verified user | +| LDAP IdP (user AD lain) | ✅ | +| Zammad → Mailcow channel | ❌ | +| DKIM/SPF DNS publish | ❌ | +| MX cutover ke sync | ❌ | + +Detail: [project-status.md](./project-status.md) + +--- + +## Aturan Utama AI + +1. Baca `docs/context-index.md` ini terlebih dahulu +2. **Jangan commit** `.env` — hanya update `.env.example` (placeholder) dan `docs/environment.md` +3. Integrasi Zammad → referensi `Zammad/docs/` — jangan duplikasi panjang +4. LDAP umum → referensi `server-connection/docs/environment.md` +5. Setelah deploy → buat/update `docs/deployment.md` + `docs/project-status.md` diff --git a/Mailcow/docs/deployment.md b/Mailcow/docs/deployment.md new file mode 100644 index 0000000..2e03cfe --- /dev/null +++ b/Mailcow/docs/deployment.md @@ -0,0 +1,150 @@ +# Deployment — Mailcow + +> **Terakhir Diperbarui:** 2026-07-03 +> **Target VM:** `10.100.1.28` · `sync.geonet.co.id` + +Step-by-step install — **Mailcow + nginx proxy selesai 2026-07-03**. + +--- + +## Prasyarat + +- [x] VM spec diset (16 vCPU, 32 GB RAM, 2×512 GB SSD) +- [x] Keputusan storage: local SSD vmail + backup QNAP +- [x] Grup AD `Mail-Users` + `support@geonet.co.id` +- [x] VM `10.100.1.28` provisioned & SSH OK +- [x] DNS A `sync.geonet.co.id` → `117.102.73.102` +- [x] NAT mail `25/465/587/993` → `.28` +- [x] NAT `80/443` → `.24` (nginx) +- [x] Nginx vhost `sync.geonet.co.id` → proxy ke `.28:443` + certbot LE +- [ ] PTR `117.102.73.102` → `sync.geonet.co.id` + +Lihat `docs/server.md` untuk detail VM. + +--- + +## 1 — OS & disk + +1. Install **Debian 12** atau **Ubuntu 22.04 LTS** +2. Disk 2 → format `ext4` → mount `/data/mailcow/vmail` +3. Tambah ke `/etc/fstab` +4. Swap 4 GiB + +```bash +# Contoh mount disk 2 (sesuaikan device) +mkfs.ext4 /dev/sdb +mkdir -p /data/mailcow/vmail +echo '/dev/sdb /data/mailcow/vmail ext4 defaults 0 2' >> /etc/fstab +mount -a +``` + +--- + +## 2 — Docker + +```bash +apt update && apt install -y ca-certificates curl gnupg +# Install Docker CE + compose plugin (lihat docs.docker.com) +docker --version # >= 24 +docker compose version # >= 2 +``` + +--- + +## 3 — Install Mailcow + +```bash +cd /opt/stacks +git clone https://github.com/mailcow/mailcow-dockerized mailcow +cd mailcow +./generate_config.sh +# Hostname: sync.geonet.co.id +# Timezone: Asia/Jakarta +``` + +Edit `mailcow.conf`: + +```bash +# Port 80/443 publik masuk nginx .24 — bukan langsung ke Mailcow +SKIP_LETS_ENCRYPT=y +``` + +Opsi lain: DNS-01 challenge di Mailcow jika ingin cert internal Mailcow (tanpa nginx SSL). + +> Stack path `/opt/stacks/mailcow` agar terlihat di Dockge agent `.28`. + +--- + +## 4 — Bind vmail ke disk 2 + +Buat `docker-compose.override.yml`: + +```yaml +volumes: + vmail-vol-1: + driver: local + driver_opts: + type: none + device: /data/mailcow/vmail + o: bind +``` + +```bash +docker compose pull +docker compose up -d +``` + +--- + +## 4b — Nginx reverse proxy (`.24`) + +Karena `80/443` publik masuk ke nginx, buat vhost `sync.geonet.co.id`: + +```nginx +upstream mailcow_backend { + server 10.100.1.28:443; +} + +server { + listen 80; + server_name sync.geonet.co.id; + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl; + server_name sync.geonet.co.id; + include /etc/nginx/conf.d/ssl.conf; # atau certbot sync.geonet.co.id + + proxy_pass https://mailcow_backend; + proxy_ssl_verify off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 3600s; + client_max_body_size 50M; +} +``` + +Cert publik: `certbot --nginx -d sync.geonet.co.id` di `.24`. + +--- + +## 5 — Post-install + +1. Login admin UI `https://sync.geonet.co.id` *(via nginx `.24`)* +2. Tambah domain `geonet.co.id` +3. Identity Provider → LDAP → AD `10.100.1.40` +4. fetchmail POP3 drain dari cPanel +5. Backup cron → QNAP +6. Zammad channel IMAP/SMTP → `10.100.1.28` + +--- + +## Referensi + +- [Mailcow Install](https://docs.mailcow.email/getstarted/install/) +- [Move vmail volume](https://docs.mailcow.email/manual-guides/Dovecot/u_e-dovecot-vmail-volume/) +- `docs/notes/ldap-ad-mailcow.md` +- `docs/notes/email-sync-migration-concept.md` diff --git a/Mailcow/docs/environment.md b/Mailcow/docs/environment.md new file mode 100644 index 0000000..83f9749 --- /dev/null +++ b/Mailcow/docs/environment.md @@ -0,0 +1,149 @@ +# Environment Variables — Mailcow + +> **Terakhir Diperbarui:** 2026-07-03 +> ⚠️ **Jangan commit `.env`** — hanya `.env.example` di repo. Nilai secret di server: `/opt/stacks/mailcow/.env` + +--- + +## Core install + +| Variable | Contoh | Keterangan | +|----------|--------|------------| +| `MAILCOW_HOSTNAME` | `sync.geonet.co.id` | FQDN utama Mailcow (Let's Encrypt) | +| `MAILCOW_VM_IP` | `10.100.1.28` | IP LAN VM Mailcow | +| `MAILCOW_TIMEZONE` | `Asia/Jakarta` | Timezone container | +| `MAILCOW_PUBLIC_IP` | *(IP publik NAT)* | IP publik untuk MX/PTR — set di DNS | +| `MAILCOW_STACK_PATH` | `/opt/mailcow-dockerized` | Path deploy di VM `.27` | +| `MAILCOW_API_KEY` | *(generate)* | Password API Mailcow (`mailcow.conf` → `MAILCOW_PASS`) | +| `SKIP_LETS_ENCRYPT` | `n` | `y` hanya lab tanpa DNS | +| `ADDITIONAL_SAN` | | Hostname tambahan di cert (opsional) | + +--- + +## Admin UI + +| Variable | Contoh | Keterangan | +|----------|--------|------------| +| `MAILCOW_ADMIN_USER` | `admin` | User default panel Mailcow | +| `MAILCOW_ADMIN_PASSWORD` | **SECRET** | Password admin — set saat install / reset di UI | + +--- + +## Mailbox support (Zammad) + +| Variable | Contoh | Keterangan | +|----------|--------|------------| +| `MAILCOW_SUPPORT_EMAIL` | `support@geonet.co.id` | Mailbox inbound/outbound Zammad | +| `MAILCOW_SUPPORT_PASSWORD` | **SECRET** | Password mailbox — sama untuk SMTP & IMAP di Zammad | + +--- + +## Domain + +| Variable | Contoh | Keterangan | +|----------|--------|------------| +| `MAILCOW_DOMAIN_PRIMARY` | `geonet.co.id` | Domain utama | +| `MAILCOW_DOMAIN_SECONDARY` | `gegeo.my.id` | Domain tambahan (multi-domain) | + +--- + +## Port layanan (default Mailcow) + +| Variable | Port | Protokol | Keterangan | +|----------|------|----------|------------| +| `MAILCOW_PORT_SMTP` | 25 | SMTP | Inbound dari internet — cek firewall & provider | +| `MAILCOW_PORT_SMTPS` | 465 | SMTPS | Implicit SSL | +| `MAILCOW_PORT_SUBMISSION` | 587 | STARTTLS | **Disarankan** untuk Zammad outbound | +| `MAILCOW_PORT_IMAPS` | 993 | IMAPS | **Zammad inbound** fetch email | +| `MAILCOW_PORT_POP3S` | 995 | POP3S | Opsional | +| `MAILCOW_PORT_HTTPS` | 443 | HTTPS | Web UI + API | + +--- + +## Integrasi Zammad + +Setelah Mailcow running, konfigurasi di **Zammad → Channels → Email**: + +### Outbound (notifikasi tiket) + +| Variable | Nilai | Keterangan | +|----------|-------|------------| +| `ZAMMAD_SMTP_HOST` | `mailcowdockerized-postfix-mailcow-1` | Hostname container Postfix (dari jaringan Docker Zammad) | +| `ZAMMAD_SMTP_PORT` | `587` | STARTTLS | +| `ZAMMAD_SMTP_SSL` | `starttls` | | +| `ZAMMAD_SMTP_USER` | `support@geonet.co.id` | | +| `ZAMMAD_SMTP_PASSWORD` | **SECRET** | Sama dengan `MAILCOW_SUPPORT_PASSWORD` | + +> Alternatif dari host: `127.0.0.1:587` jika port di-bind ke localhost + nginx tidak mem-proxy SMTP. + +### Inbound (email → tiket) + +| Variable | Nilai | Keterangan | +|----------|-------|------------| +| `ZAMMAD_IMAP_HOST` | `mailcowdockerized-dovecot-mailcow-1` | Container Dovecot | +| `ZAMMAD_IMAP_PORT` | `993` | SSL | +| `ZAMMAD_IMAP_SSL` | `yes` | | +| `ZAMMAD_IMAP_USER` | `support@geonet.co.id` | | +| `ZAMMAD_IMAP_PASSWORD` | **SECRET** | | + +**Ref Zammad:** `Zammad/docs/notes/smtp-notification-setup.md`, `Zammad/docs/roadmap.md` Fase 9 + +--- + +## LDAP (Active Directory) + +Mailcow **bisa** pakai LDAP `10.100.1.40` — sama dengan geonet-console & Zammad. + +| Variable | Nilai | +|----------|-------| +| `LDAP_HOST` | `10.100.1.40` | +| `LDAP_PORT` | `389` | +| `LDAP_BASE_DN` | `DC=gisportal,DC=id` | +| `LDAP_BIND_DN` | `Administrator@gisportal.id` | +| `LDAP_BIND_PASSWORD` | **SECRET** — reuse geonet-console | + +**Panduan lengkap:** `docs/notes/ldap-ad-mailcow.md` + +| Terpusat di AD | Tetap di Mailcow UI | +|----------------|---------------------| +| Password, nama, on/off user | Domain, alias, template quota | +| Grup siapa dapat mailbox | Admin panel (SQL only) | +| Atribut `mail` → `@geonet.co.id` | fetchmail POP3 drain | + +--- + +## Legacy SMTP (migrasi dari cPanel) + +Zammad saat ini memakai hosting idcloudhosting — tetap didokumentasikan sampai cutover Mailcow. + +| Variable | Nilai | +|----------|-------| +| `LEGACY_SMTP_HOST` | `sc138.idcloudhosting.cloud` | +| `LEGACY_SMTP_PORT` | `465` | +| `LEGACY_SMTP_SSL` | `yes` | +| `LEGACY_SMTP_SSL_VERIFY` | `yes` | +| `LEGACY_SMTP_USER` | `support@geonet.co.id` | +| `LEGACY_SMTP_PASSWORD` | **SECRET** | + +Error historis DNS container: `Zammad/docs/notes/email-geonet-co-id.md` + +--- + +## DNS (panel domain — bukan env Mailcow) + +| Variable | Contoh | Record | +|----------|--------|--------| +| `DNS_MX_HOST` | `mail.gisportal.id` | MX → IP publik server | +| `DNS_SPF_INCLUDE` | `include:mail.gisportal.id` | TXT SPF | +| — | *(dari Mailcow UI)* | TXT DKIM | +| — | | TXT DMARC | + +--- + +## Lokasi secret + +| Secret | Lokasi | +|--------|--------| +| Mailcow `.env` (repo lokal) | `Mailcow/.env` — gitignored | +| Mailcow di production | `/opt/stacks/mailcow/mailcow.conf` + `.env` | +| Zammad SMTP saat ini | UI Zammad + `Zammad/docs/notes/smtp-notification-setup.md` | diff --git a/Mailcow/docs/issues.md b/Mailcow/docs/issues.md new file mode 100644 index 0000000..10f76a4 --- /dev/null +++ b/Mailcow/docs/issues.md @@ -0,0 +1,23 @@ +# Issues — Mailcow + +--- + +## Open Issues + +### ISS-001: _sogo_static_view tidak auto-sync setelah edit password + +| Field | Value | +|-------|-------| +| Status | Open | +| Severity | Medium | +| Found | 2026-07-03 | + +**Workaround:** UPDATE _sogo_static_view FROM mailbox.password; restart sogo container. + +--- + +## Resolved Issues + +### ISS-003: SOGo Unauthorized — authsource mailcow + sync view (2026-07-03) +### ISS-004: Gmail 550 — relay sc138:587 (2026-07-03) +### ISS-005: fetchmailrc parse — ssl after user, no sslcertck (2026-07-03) diff --git a/Mailcow/docs/notes/deployment-sizing.md b/Mailcow/docs/notes/deployment-sizing.md new file mode 100644 index 0000000..53d90ad --- /dev/null +++ b/Mailcow/docs/notes/deployment-sizing.md @@ -0,0 +1,193 @@ +# Deployment & Sizing — Mailcow (jangka panjang) + +> **Terakhir Diperbarui:** 2026-07-03 +> **Target:** ~30+ user email aktif · hostname `sync.geonet.co.id` · VM **`10.100.1.28`** +> **Keputusan storage:** ✅ **Local SSD VM** (prioritas uptime) + backup QNAP harian + +--- + +## Linux atau Docker? + +**Keduanya — bukan pilihan salah satu.** + +| Lapisan | Teknologi | Keterangan | +|---------|-----------|------------| +| **Host OS** | Linux (VM) | Wajib — Debian 12 / Ubuntu 22.04 LTS / Alma 9 | +| **Aplikasi mail** | **Docker Compose** | Mailcow hanya didistribusikan sebagai `mailcow-dockerized` | +| **Windows** | ❌ | Tidak didukung sebagai host Mailcow | +| **Install native tanpa Docker** | ❌ | Tidak ada paket Mailcow untuk Linux biasa | + +Alur install resmi: + +``` +Proxmox (.102) → VM Linux → Docker + Compose → git clone mailcow-dockerized → ./generate_config.sh → docker compose up -d +``` + +**Kesimpulan:** VM **Linux dedicated** yang menjalankan stack **Docker** Mailcow. + +--- + +## Rekomendasi proper (30+ user aktif) + +### Jangan taruh Mailcow di server `.24` + +Server `10.100.1.24` sudah penuh microservice (Zammad, geonet-console, Grafana, n8n, …). Mail server butuh: + +- Port 25/465/587/993 stabil +- RAM predictable +- Isolasi jika satu service restart tidak ganggu mail + +**Taruh di VM dedicated `10.100.1.28`** — terpisah dari app server `.24`. + +### Spesifikasi VM (diset 2026-07-03) + +| Resource | Nilai | +|----------|-------| +| **IP** | `10.100.1.28` | +| **vCPU** | 16 core | +| **RAM** | 32 GiB | +| **Disk 1** | 512 GiB SSD — OS + Docker + MariaDB + Redis | +| **Disk 2** | 512 GiB SSD — vmail live | + +> Spec ini **melampaui** minimum resmi Mailcow — sangat nyaman untuk 30+ user dan headroom growth. + +### Jangan Proxmox LXC + Docker (untuk production) + +| Opsi | Produksi mail? | +|------|----------------| +| **VM Linux penuh** | ✅ Disarankan | +| LXC nested Docker | ⚠️ Bisa, tapi kurang bersih untuk mail jangka panjang | + +--- + +## Spesifikasi VM (rekomendasi → **diset user**) + +Untuk **30+ mailbox aktif** — nilai **tebal** = yang akan dipakai: + +| Resource | Minimum | Rekomendasi doc | **VM `.27` (final)** | +|----------|---------|-----------------|----------------------| +| **vCPU** | 2 | 4 | **16** | +| **RAM** | 8 GiB | 12–16 GiB | **32 GiB** | +| **Disk OS+DB** | 40 GiB | 60 GiB | **512 GiB SSD** | +| **Disk vmail** | 100 GiB | 200–300 GiB | **512 GiB SSD** | +| **Swap** | 2 GiB | 4 GiB | **4 GiB** | + +### Perkiraan storage email + +| Asumsi | Per user/tahun | 30 user × 3 tahun | +|--------|----------------|-------------------| +| Ringan (5 GB/user) | 5 GB | ~150 GB | +| Sedang (10 GB/user) | 10 GB | ~300 GB | +| Berat (attachment) | 20 GB+ | 600 GB+ | + +Mount `mailcow` data (`./data`, terutama `vmail`) di **disk/volume terpisah** agar mudah expand & backup. + +--- + +## OS & software host + +| Item | Pilihan | +|------|---------| +| OS | **Debian 12** atau **Ubuntu 22.04 LTS** | +| Docker | ≥ 24.x | +| Docker Compose | **Plugin v2** (≥ 2.0) | +| Firewall | `ufw` / nftables — buka 25, 80, 443, 465, 587, 993, 995 | +| Hostname VM | `sync.geonet.co.id` | +| PTR (reverse DNS) | IP publik → `sync.geonet.co.id` *(wajib untuk deliverability)* | + +--- + +## Optimasi `mailcow.conf` (30 user, stabil) + +Default Mailcow memuat banyak komponen. Untuk 30 user dengan Outlook (bukan ActiveSync massal): + +| Setting | Rekomendasi | Alasan | +|---------|-------------|--------| +| `SKIP_CLAMD` | `n` jika RAM ≥12 GiB, `y` jika ketat | ClamAV ~1 GiB RAM | +| `SKIP_FTS` / Solr | `y` *(opsional)* | Hemat RAM jika tidak pakai search SOGo berat | +| SOGo | Tetap default | Webmail cadangan; Outlook user utama | +| Redis maxmemory | Set batas di override | Cegah Redis membengkak | + +Resmi Mailcow: [Prerequisite System](https://docs.mailcow.email/getstarted/prerequisite-system/) + +--- + +## Arsitektur target di `.102` + +``` +VM mail-sync — 10.100.1.28 +├── 16 vCPU, 32 GiB RAM, 4 GiB swap +├── Disk 1: 512 GiB SSD (OS + Docker + MariaDB + Redis) +├── Disk 2: 512 GiB SSD (vmail live — tidak via NAS) +├── Docker: mailcow-dockerized +│ └── MAILCOW_HOSTNAME=sync.geonet.co.id +├── fetchmail (POP3 drain cPanel → Mailcow) +└── Backup cron → QNAP 10.100.1.10 +``` + +**Koneksi ke layanan lain:** + +| Dari | Ke | Port | +|------|-----|------| +| VM Mailcow | AD `10.100.1.40` | 389 LDAP | +| VM Mailcow | Internet | 995 POP3 (cPanel drain) | +| Zammad `.24` | VM Mailcow `.27` | 993 IMAP, 587 SMTP | +| User Outlook | `sync.geonet.co.id` | 993 / 587 | + +--- + +## Backup jangka panjang (wajib) + +| Item | Cara | +|------|------| +| Mailcow built-in | `helper-scripts/backup_and_restore.sh` | +| Jadwal | Harian → QNAP NFS/SMB atau rsync | +| Retensi | 7 harian + 4 mingguan | +| Uji restore | Kuartalan | + +Tanpa backup, VM mail = single point of failure data. + +--- + +## Monitoring + +| Cek | Tool | +|-----|------| +| Container health | `docker compose ps` + Uptime Kuma | +| Disk vmail | Alert >80% | +| fetchmail | Log + alert jika cPanel inbox menumpuk | +| Queue Postfix | `mailq` | +| LDAP sync | Mailcow crontask logs | + +--- + +## Yang **tidak** disarankan + +| Pilihan | Kenapa | +|---------|--------| +| Mailcow di `.24` bersama 15+ container | RAM/port conflict, restart cascade | +| RAM 6 GiB untuk 30 user aktif | OOM / swap thrashing | +| 1 disk kecil tanpa pisah vmail | Sulit expand & backup | +| Skip PTR / SPF / DKIM | Email masuk spam | +| Thunderbird di PC sebagai bridge POP3 | Tidak 24/7 — pakai fetchmail di VM | + +--- + +## Checklist sebelum install + +- [ ] VM di Proxmox `.102` dengan spec di atas +- [ ] DNS A `sync.geonet.co.id` → IP publik +- [ ] PTR record ke `sync.geonet.co.id` +- [ ] Port 25 outbound/inbound dicek (provider tidak blokir) +- [ ] Firewall MikroTik NAT 25, 443, 465, 587, 993 +- [ ] Volume data mail terpisah +- [ ] Rencana backup ke QNAP + +--- + +## Referensi + +- [Mailcow — Prepare your system](https://docs.mailcow.email/getstarted/prerequisite-system/) +- [Mailcow — Install](https://docs.mailcow.email/getstarted/install/) +- `docs/notes/email-sync-migration-concept.md` +- `docs/notes/ldap-ad-mailcow.md` diff --git a/Mailcow/docs/notes/email-sync-migration-concept.md b/Mailcow/docs/notes/email-sync-migration-concept.md new file mode 100644 index 0000000..ac5e76c --- /dev/null +++ b/Mailcow/docs/notes/email-sync-migration-concept.md @@ -0,0 +1,248 @@ +# Konsep — POP3 Drain cPanel → Mailcow (inbox tunggal) + +> **Terakhir Diperbarui:** 2026-07-03 +> **Status:** Rencana arsitektur — **keputusan user** +> **Konteks:** MX `geonet.co.id` tetap cPanel; inbox canonical di Mailcow `sync.geonet.co.id` + +--- + +## Ringkasan keputusan + +| Aspek | Rencana | +|-------|---------| +| MX `geonet.co.id` | Tetap cPanel (belum cutover) | +| Inbox cPanel | **Kosong** — hanya staging sementara | +| POP3 drain | VM/service tarik POP3 dari cPanel, **hapus** setelah sukses | +| Inbox canonical | Mailcow `sync.geonet.co.id` (IMAP) | +| Outlook user | IMAP + SMTP **hanya** `sync.geonet.co.id` | +| Zammad | IMAP + SMTP ke Mailcow (mailbox sama dengan user) | +| Mailcow host | `10.100.1.28` | + +**Prinsip:** cPanel hanya pintu masuk internet; **semua orang baca/tulis email lewat Mailcow**. + +--- + +## Diagram alur + +```mermaid +flowchart TB + subgraph internet [Internet] + S[Pengirim / penerima balasan] + end + + subgraph cpanel [cPanel — staging kosong] + MX[MX geonet.co.id] + STG[(Inbox cPanel\nkosong setelah POP3)] + end + + subgraph vm [VM 10.100.1.28] + FM[fetchmail / getmail\nPOP3 drain + delete] + MC[Mailcow sync.geonet.co.id] + MBX[(Inbox IMAP\ncanonical)] + end + + subgraph clients [Klien] + OL[Outlook user\nIMAP + SMTP] + Z[Zammad\nIMAP + SMTP] + end + + S -->|email baru| MX --> STG + STG -->|POP3 :995\nhapus setelah OK| FM -->|SMTP inject :587| MC --> MBX + MBX -->|IMAP :993| OL + MBX -->|IMAP poll| Z + OL -->|SMTP :587| MC + Z -->|SMTP :587| MC + MC -->|kirim ke internet| S +``` + +--- + +## Peran masing-masing komponen + +### 1. cPanel (`mail.geonet.co.id`) + +| Fungsi | Detail | +|--------|--------| +| MX record | Masih menunjuk ke hosting — email dari internet masuk sini dulu | +| Inbox | **Staging** — harus kosong setelah POP3 drain berjalan | +| User Outlook | **Tidak** connect ke cPanel lagi | +| POP3 | `mail.geonet.co.id:995` SSL — hanya untuk service VM | + +### 2. VM — POP3 drain (fetchmail) + +Service di server (bisa di VM yang sama dengan Mailcow), **bukan** di PC user. + +| Setting | Nilai | +|---------|-------| +| Protokol sumber | POP3 SSL `:995` | +| Host | `mail.geonet.co.id` | +| User | `nama@geonet.co.id` (per mailbox) | +| Setelah sukses | **Hapus** dari cPanel (`fetchall` + tidak `keep`) | +| Tujuan | SMTP ke Mailcow `127.0.0.1:587` atau `sync.geonet.co.id:587` | +| Jadwal | Cron/systemd tiap **1–2 menit** | + +**Contoh `fetchmailrc` (produksi di `/opt/fetchmail/fetchmailrc`):** + +``` +poll mail.geonet.co.id with proto POP3 port 995 + user "support@geonet.co.id" there with password "..." is "support@geonet.co.id" here + ssl + no sslcertck + smtphost 127.0.0.1 + smtpname sync.geonet.co.id + fetchall + nokeep +``` + +> Password dengan `#` atau `$` harus di-escape (generate via Python `repr()`). +> `ssl` harus **setelah** baris `user`, bukan sebelum. +> `no sslcertck` — cert cPanel `*.idcloudhosting.cloud` ≠ `mail.geonet.co.id`. +> SMTP inject ke Mailcow via `127.0.0.1:25` (tanpa auth). +> Install: `scripts/install-fetchmail-support.sh` + systemd timer 2 menit. + +### 3. Mailcow (`sync.geonet.co.id`) + +| Fungsi | Detail | +|--------|--------| +| Hostname | `sync.geonet.co.id` | +| Inbox canonical | Semua pesan hidup di sini | +| Domain mailbox | Tambah `geonet.co.id` di Mailcow agar alamat tetap `user@geonet.co.id` | +| Dovecot IMAP | `:993` — Outlook & Zammad | +| Postfix SMTP | `:587` — kirim balasan | + +### 4. Outlook user + +Satu akun saja — **tidak** ada akun cPanel. + +| Setting | Nilai | +|---------|-------| +| **Incoming** | IMAP | +| Server | `sync.geonet.co.id` | +| Port | `993` | +| Encryption | SSL/TLS | +| **Outgoing** | SMTP | +| Server | `sync.geonet.co.id` | +| Port | `587` (STARTTLS) atau `465` (SSL) | +| Auth | Ya — username = email penuh | +| Username | `nama@geonet.co.id` | + +### 5. Zammad + +Sama seperti Outlook — satu mailbox di Mailcow: + +| Arah | Konfigurasi | +|------|-------------| +| Inbound | IMAP `sync.geonet.co.id:993` → `support@geonet.co.id` | +| Outbound | SMTP `sync.geonet.co.id:587` → `support@geonet.co.id` | + +--- + +## Mengapa POP3 drain (bukan imapsync mirror) + +| | imapsync (salin) | POP3 drain (pilihan user) | +|--|------------------|---------------------------| +| Inbox cPanel | Masih berisi salinan | **Kosong** | +| Sumber kebenaran | Dua tempat | **Satu** — Mailcow saja | +| Outlook connect ke | Harus Mailcow saja juga | Mailcow saja ✅ | +| Risiko duplikat | Ada jika lupa aturan | Rendah | + +Cocok dengan tujuan: **user hanya tahu `sync.geonet.co.id`**, cPanel tidak dipakai sehari-hari. + +--- + +## SPF / DKIM outbound (penting) + +Balasan dari Mailcow dengan `From: user@geonet.co.id` butuh DNS mengizinkan server `.102`: + +| Record | Fase transisi | Fase akhir | +|--------|---------------|------------| +| SPF `geonet.co.id` | Tambah IP publik `.102` **atau** relay SMTP cPanel sebagai smarthost | Mailcow only | +| DKIM | Generate di Mailcow, publish TXT | Sama | +| DMARC | Opsional awal | Disarankan | + +**Opsi jika belum siap SPF:** + +- Mailcow **smarthost** → `sc138.idcloudhosting.cloud:465` untuk outbound `@geonet.co.id` +- Atau Zammad SMTP tetap hosting sementara, Outlook SMTP Mailcow (campuran — kurang ideal) + +**Target user:** Outlook incoming **dan** outgoing `sync.geonet.co.id` → siapkan SPF/DKIM `geonet.co.id` untuk IP Mailcow. + +--- + +## Multi-mailbox + +Setiap `user@geonet.co.id` di cPanel perlu: + +1. Entry fetchmail POP3 sendiri (atau satu script loop) +2. Mailbox matching di Mailcow +3. Outlook user connect ke Mailcow + +Contoh tim: + +| cPanel POP3 | Mailcow mailbox | Klien | +|-------------|-----------------|-------| +| `support@geonet.co.id` | `support@geonet.co.id` | Zammad + Outlook IT | +| `info@geonet.co.id` | `info@geonet.co.id` | Outlook admin | +| `nama@geonet.co.id` | `nama@geonet.co.id` | Outlook user | + +--- + +## Risiko & mitigasi + +| Risiko | Dampak | Mitigasi | +|--------|--------|----------| +| fetchmail mati | Email menumpuk di cPanel, user tidak lihat | Monitor cron + alert (Uptime Kuma / script) | +| Latency 1–2 menit | Email tidak instant di Outlook | Kurangi interval cron; terima sebagai trade-off | +| POP3 gagal mid-batch | Pesan bisa hilang jika delete sebelum SMTP OK | Pakai fetchmail `nokeep` hanya setelah SMTP sukses (default behavior) | +| Port 25 blokir | Outbound Mailcow gagal | Smarthost cPanel atau port 587 | +| VM `.102` down | Semua mail flow stop | HA / backup VM; monitor | + +--- + +## Perbedaan dengan pola Thunderbird manual + +| | Thunderbird di PC | fetchmail di VM | +|--|-------------------|-----------------| +| POP3 drain | User PC harus nyala | Server 24/7 | +| Deliver ke Mailcow | Manual / filter | Otomatis SMTP inject | +| Outlook user | Hanya IMAP Mailcow | Sama ✅ | + +Thunderbird **tidak** dipakai untuk bridge — hanya Outlook (atau client lain) ke Mailcow. + +--- + +## Roadmap + +| Tahap | Aksi | +|-------|------| +| **1** | Install Mailcow di VM `.102`, hostname `sync.geonet.co.id` | +| **2** | Tambah domain `geonet.co.id` + buat mailbox | +| **3** | Deploy fetchmail POP3 drain per mailbox | +| **4** | Kosongkan inbox cPanel (tes drain) | +| **5** | Konfigurasi Outlook user → IMAP/SMTP Mailcow | +| **6** | Zammad IMAP + SMTP Mailcow | +| **7** | SPF/DKIM untuk outbound `@geonet.co.id` | +| **8** | Stabil 2–4 minggu | +| **9** | Cutover MX → `sync.geonet.co.id`, matikan fetchmail | + +--- + +## Checklist + +- [ ] VM `10.100.1.28` provisioned (16 vCPU, 32 GB, 2×512 GB) +- [ ] DNS A `sync.geonet.co.id` → IP publik +- [ ] Mailcow + domain `geonet.co.id` +- [x] fetchmail + timer 2 menit (`support@geonet.co.id`) — `scripts/install-fetchmail-support.sh` +- [ ] Verifikasi inbox cPanel kosong setelah drain +- [ ] Outlook: IMAP+SMTP `sync.geonet.co.id` +- [ ] Zammad channel email → Mailcow +- [ ] SPF/DKIM `geonet.co.id` +- [ ] Monitoring fetchmail + +--- + +## Referensi + +- `Mailcow/docs/environment.md` +- `Zammad/docs/notes/email-geonet-co-id.md` +- `fetchmail` man: https://www.fetchmail.info/ diff --git a/Mailcow/docs/notes/ldap-ad-mailcow.md b/Mailcow/docs/notes/ldap-ad-mailcow.md new file mode 100644 index 0000000..9685f58 --- /dev/null +++ b/Mailcow/docs/notes/ldap-ad-mailcow.md @@ -0,0 +1,298 @@ +# LDAP — Mailcow ke Active Directory + +> **Terakhir Diperbarui:** 2026-07-03 +> **AD:** `10.100.1.40` · domain `gisportal.id` +> **Status:** Grup AD siap ✅ · LDAP Identity Provider aktif ✅ (2026-07-03) +> ⚠️ Bind password **tidak** didokumentasikan di repo — reuse `geonet-console` `.env` + +--- + +## Status AD — Mail-Users (2026-07-03) + +| Item | Nilai | Status | +|------|-------|--------| +| Grup LDAP | `Mail-Users` | ✅ Dibuat user | +| DN grup *(default AD)* | `CN=Mail-Users,CN=Users,DC=gisportal,DC=id` | ⚠️ Verifikasi jika filter gagal | +| Member | `support` | ✅ | +| Atribut `mail` | `support@geonet.co.id` | ✅ | +| sAMAccountName | `support` | *(untuk login LDAP)* | + +**LDAP filter siap pakai:** + +``` +(&(objectClass=user)(objectCategory=person)(memberOf=CN=Mail-Users,CN=Users,DC=gisportal,DC=id)) +``` + +Mailbox pertama yang akan di-provision otomatis: **`support@geonet.co.id`** — sekaligus mailbox Zammad + fetchmail POP3 drain. + +--- + +## Jawaban singkat + +**Ya, Mailcow bisa pakai LDAP (Active Directory)** sebagai Identity Provider — login IMAP/SMTP/SOGo dan provisioning mailbox otomatis. + +User **tidak** perlu password terpisah di Mailcow; autentikasi ke AD sama seperti geonet-console dan Zammad. + +**Tapi:** manajemen akun **tidak 100% identik** dengan microservice lain — Mailcow tetap perlu konfigurasi domain email, template mailbox, dan grup siapa yang dapat mailbox `@geonet.co.id`. + +--- + +## Posisi dalam ekosistem Super Apps + +```mermaid +flowchart LR + AD[(Active Directory\n10.100.1.40\ngisportal.id)] + + AD -->|LDAP bind| GC[geonet-console\nJWT login] + AD -->|LDAP sync| ZM[Zammad\nagent/customer] + AD -->|LDAP IdP| MC[Mailcow\nmailbox @geonet.co.id] + AD -->|LDAP| FE[mysupperapps PWA\nvia console API] + + MC --> OL[Outlook IMAP/SMTP] + MC --> ZM +``` + +| Layanan | LDAP dipakai untuk | User lokal? | +|---------|-------------------|-------------| +| **geonet-console** | Auth only → JWT | Tidak | +| **Zammad** | Sync user + role/group | Dibuat otomatis dari AD | +| **Mailcow** | Auth mailbox + import/sync | Mailbox auto-provision (bukan admin) | +| **Super Apps FE** | Via geonet-console API | Tidak | + +**Sumber kebenaran identitas:** AD `10.100.1.40` — password, nama, grup. + +--- + +## Fitur LDAP native Mailcow (2025+) + +Mailcow menyediakan **System → Configuration → Access → Identity Provider → LDAP**. + +| Fitur | Keterangan | +|-------|------------| +| LDAP bind login | User login pakai kredensial AD | +| Auto-provision | Mailbox dibuat saat login pertama (IMAP/SMTP/UI) | +| Periodic import | Cron impor user dari LDAP | +| Periodic full sync | Update template/quota dari perubahan AD | +| Attribute mapping | Map atribut LDAP → template mailbox Mailcow | + +**Dokumentasi resmi:** [mailcow LDAP guide](https://docs.mailcow.email/manual-guides/mailcow-UI/u_e-mailcow_ui-ldap/) + +--- + +## Batasan penting + +| Item | Perilaku | +|------|----------| +| **Admin Mailcow** | Tetap auth **SQL** (bukan LDAP) | +| **Domain Admin** | Tetap auth **SQL** | +| **Mailbox user** | Bisa LDAP ✅ | +| **2FA** | LDAP user bisa set 2FA di UI Mailcow | +| **Outlook** | Login pakai password AD; tidak perlu app password khusus (beda dengan OIDC) | +| **Active Directory** | Pakai filter AD (`objectClass=user`), **bukan** `posixAccount` | + +> **Catatan AD:** Ada laporan issue Dovecot + filter `posixAccount` untuk AD. Pastikan filter di Identity Provider memakai sintaks AD. Cek log IMAP setelah setup. + +--- + +## Parameter LDAP (selaras Zammad / geonet-console) + +| Field Mailcow UI | Nilai | +|----------------|-------| +| **URI / Host** | `ldap://10.100.1.40:389` | +| **Bind DN** | `Administrator@gisportal.id` | +| **Bind password** | `LDAP_BIND_PASSWORD` dari geonet-console | +| **Base DN** | `DC=gisportal,DC=id` | +| **LDAP Filter** | `(&(objectClass=user)(objectCategory=person)(memberOf=CN=Mail-Users,OU=Groups,DC=gisportal,DC=id))` *(contoh — sesuaikan grup)* | +| **Username field** | `mail` *(bukan `sAMAccountName` — sync butuh alamat email penuh)* | +| **Attribute Field** (mapping) | `mail` atau atribut custom | + +Reuse credential: `/opt/stacks/geonet-console/.env` — pola sama dengan Zammad (`Zammad/docs/notes/ldap-ad-setup.md`). + +### Prasyarat jaringan + +```bash +# Dari VM Mailcow (.102) +nc -zv -w5 10.100.1.40 389 +``` + +Firewall: `10.100.1.28` → `10.100.1.40:389` + +--- + +## Tantangan: AD `gisportal.id` vs email `geonet.co.id` + +AD domain = `gisportal.id`, tetapi mailbox operasional = `@geonet.co.id`. + +| Strategi | Cara | Rekomendasi | +|----------|------|-------------| +| **A — Atribut `mail` di AD** | Set `mail` = `user@geonet.co.id` per user | ✅ Paling bersih | +| **B — Grup + template** | Hanya user di grup `Mail-Users` AD yang di-import | ✅ Kontrol siapa dapat email | +| **C — proxyAddresses** | `SMTP:user@geonet.co.id` di AD | Enterprise, butuh script | +| **D — Dual domain** | Login AD `user@gisportal.id`, alias `user@geonet.co.id` | Manual per user di Mailcow | + +**Rekomendasi:** Kombinasi **A + B**: + +1. Buat grup AD `Mail-Users` (atau `IT-Mail`, `Domain Users` subset) +2. Isi atribut `mail` = `nama@geonet.co.id` untuk anggota grup +3. LDAP filter: `memberOf=CN=Mail-Users,...` +4. Hanya user dengan `mail` @ `geonet.co.id` yang di-provision + +User tanpa `mail` atau di luar grup → tidak dapat mailbox (sama seperti 3 user gagal sync di Zammad). + +--- + +## Attribute mapping & mailbox template + +Mailcow memakai **template** untuk quota, spam policy, dll. + +| LDAP Attribute Field | Attribute value | Template Mailcow | +|---------------------|-----------------|------------------| +| `mail` | `*@geonet.co.id` | `default` *(buat template di UI)* | +| `department` | `IT` | `it-mailbox` *(opsional)* | + +**Cron sync** (disarankan aktif): + +| Opsi | Fungsi | +|------|--------| +| **Import Users** | Impor user baru dari LDAP tiap N menit | +| **Periodic Full Sync** | Update mailbox jika template/atribut berubah | +| **Sync / Import Interval** | `15` menit (sesuaikan) | + +Log: `System → Information → Logs → Crontasks` + +--- + +## Alur provisioning user baru + +``` +1. Admin tambah user di AD (+ grup Mail-Users + atribut mail) +2. Cron Mailcow LDAP sync (atau login pertama) +3. Mailbox user@geonet.co.id dibuat otomatis +4. User buka Outlook → IMAP sync.geonet.co.id + password AD +5. Zammad (jika mailbox support@) poll IMAP mailbox yang sama +``` + +**Tidak perlu** buat user manual di Mailcow UI untuk user standar. + +--- + +## Apa yang tetap dikelola di Mailcow UI + +| Item | LDAP? | Keterangan | +|------|-------|------------| +| Password user | ✅ AD | Central | +| Nama / display | ✅ AD | Sync dari LDAP | +| Buat/hapus user | ✅ AD (+ grup) | Hapus = disable di AD + hapus mailbox | +| Domain `geonet.co.id` | ❌ Mailcow | Tambah domain sekali | +| Alias email | ❌ Mailcow | `info@` → `support@` | +| Shared mailbox | ❌ Mailcow | Manual | +| Quota / template | ⚙️ Hybrid | Template di Mailcow, assign via LDAP mapping | +| fetchmail POP3 drain | ❌ Mailcow | Konfig terpisah (staging cPanel) | +| Admin panel Mailcow | ❌ SQL | `admin` lokal — jangan LDAP | + +--- + +## Perbandingan manajemen terpusat + +| Aksi admin | Di AD saja? | Catatan | +|------------|-------------|---------| +| Onboard karyawan baru | Hampir ✅ | + grup `Mail-Users` + `mail` attribute | +| Reset password | ✅ | Satu password untuk AD, Outlook, SOGo | +| Nonaktifkan karyawan | ✅ | Disable AD → sync → blokir login mail | +| Ubah alamat email | ✅ | Ubah `mail` di AD + sync | +| Tambah domain email baru | ❌ | Mailcow UI | +| Forward / alias | ❌ | Mailcow UI | + +**Kesimpulan:** LDAP **cukup untuk 90%** manajemen user harian; Mailcow UI untuk kebijakan mail (domain, alias, template). + +--- + +## Integrasi dengan Outlook & Zammad + +Setelah LDAP aktif: + +| Klien | Login | Server | +|-------|-------|--------| +| **Outlook** | `user@geonet.co.id` + **password AD** | IMAP/SMTP `sync.geonet.co.id` | +| **Zammad channel** | Service account `support@geonet.co.id` | Bisa tetap password mailbox khusus *(bukan LDAP user login)* | + +> Mailbox `support@` untuk Zammad/fetchmail bisa tetap **authsource mailcow (SQL)** dengan app password, sementara user biasa pakai LDAP — menghindari konflik service account. + +--- + +## Step-by-step (setelah Mailcow terinstall) + +### 1 — Tambah domain + +**E-Mail → Configuration → Domains** → tambah `geonet.co.id` + +### 2 — Buat mailbox template + +**E-Mail → Configuration → Templates** → `default` (quota, ratelimit) + +### 3 — Identity Provider LDAP + +**System → Configuration → Access → Identity Provider** + +1. Pilih **LDAP** +2. Isi connection (lihat tabel parameter di atas) +3. **Connection Test** → harus OK +4. Set LDAP filter + attribute mapping +5. Aktifkan **Import Users** + **Periodic Full Sync** +6. Interval: 15 menit + +### 4 — Grup AD ✅ (2026-07-03) + +| Item | Status | +|------|--------| +| Grup `Mail-Users` | ✅ | +| Member `support` | ✅ | +| `mail` = `support@geonet.co.id` | ✅ | + +Tambahkan member baru dengan aturan sama: masuk grup `Mail-Users` + atribut `mail` = `nama@geonet.co.id`. + +### 5 — Uji + +1. Login SOGo / Mailcow UI dengan user AD uji +2. Cek mailbox muncul di **E-Mail → Mailboxes** +3. Tes Outlook IMAP/SMTP +4. Cek log jika IMAP gagal: `System → Information → Logs` + +### 6 — Admin Mailcow + +Pertahankan akun `admin` SQL terpisah — **jangan** pakai LDAP untuk admin panel. + +--- + +## Troubleshooting + +| Gejala | Penyebab | Tindakan | +|--------|----------|----------| +| Web login OK, IMAP gagal | Filter LDAP tidak cocok AD | Ubah filter ke `objectClass=user`; cek log Dovecot | +| User tidak ter-import | Tidak match filter / grup | Cek `memberOf`, atribut `mail` | +| Email salah domain | `mail` di AD masih `@gisportal.id` | Update AD → `@geonet.co.id` | +| Connection test gagal | Firewall / bind password | `nc` ke `.40:389`, cek bind DN | +| Semua user AD dapat mailbox | Filter terlalu luas | Perketat `memberOf=CN=Mail-Users,...` | + +--- + +## Roadmap LDAP Mailcow + +| # | Task | Status | +|---|------|--------| +| 1 | Install Mailcow di `.102` | ❌ | +| 2 | Tes koneksi LDAP dari container | ❌ | +| 3 | Buat grup AD `Mail-Users` | ✅ 2026-07-03 | +| 4 | Member `support` + `mail` @ `geonet.co.id` | ✅ | +| 5 | Konfigurasi Identity Provider | ✅ 2026-07-03 | +| 6 | Uji Outlook + SOGo | ⏳ | +| 7 | `docs/project-status.md` | ✅ | + +--- + +## Referensi + +- [Mailcow LDAP docs](https://docs.mailcow.email/manual-guides/mailcow-UI/u_e-mailcow_ui-ldap/) +- `Zammad/docs/notes/ldap-ad-setup.md` — parameter AD sama +- `server-connection/docs/environment.md` — `LDAP_*` vars +- `Mailcow/docs/notes/email-sync-migration-concept.md` — alur POP3 drain + Mailcow diff --git a/Mailcow/docs/notes/storage-nas-qnap.md b/Mailcow/docs/notes/storage-nas-qnap.md new file mode 100644 index 0000000..c3381f4 --- /dev/null +++ b/Mailcow/docs/notes/storage-nas-qnap.md @@ -0,0 +1,245 @@ +# Storage Email — NAS QNAP + +> **Terakhir Diperbarui:** 2026-07-03 +> **NAS:** QNAP `10.100.1.10` +> **Keputusan (2026-07-03):** ✅ **Local SSD VM** untuk live vmail — prioritas **uptime layanan mail**. QNAP hanya untuk **backup**, bukan iSCSI/NFS live. + +--- + +## Jawaban singkat + +**Ya, bisa** — tapi hanya untuk **filesystem Maildir** (`vmail`), **bukan** lewat Object Storage (S3/OSS) seperti attachment Zammad. + +| Metode | Live mailbox di NAS | Rekomendasi | +|--------|---------------------|-------------| +| **iSCSI** (LUN QNAP → VM) | ✅ | 🥇 **Paling proper** — seperti disk lokal | +| **NFS** v4 + bind mount | ✅ | 🥈 Bisa, perlu tuning Dovecot | +| **Backup/rsync** ke NAS | Hanya salinan | 🥇 **Wajib** — kombinasi dengan disk lokal | +| **SMB/CIFS** mount langsung | ⚠️ | Hindari untuk Maildir aktif | +| **QNAP OSS / S3** | ❌ | Mailcow tidak support object storage untuk vmail | + +--- + +## Apa yang disimpan di NAS vs tetap lokal VM + +| Data | NAS live? | Catatan | +|------|-----------|---------| +| `vmail` (email Maildir) | ✅ Bisa | Target utama pindah storage | +| `vmail-attachments` | ✅ Bisa | Attachment besar | +| **MariaDB** (database Mailcow) | ❌ **Jangan** | NFS + MySQL = corrupt risk | +| **Redis** | ❌ **Jangan** | Tetap disk lokal VM | +| Index Dovecot | ⚠️ | Bisa di NAS jika vmail di NAS + `mail_nfs_*` | + +**Aturan:** Hanya **file email** ke NAS; database & cache tetap di VM. + +--- + +## Perbandingan: iSCSI QNAP vs Local Storage VM + +> Konteks: VM Mailcow di Proxmox `.102`, NAS QNAP `.10`, ~30 user IMAP aktif, Maildir (banyak file kecil). + +### Kecepatan + +| Aspek | **Local storage VM** | **iSCSI LUN QNAP** | +|-------|----------------------|---------------------| +| Latency per operasi file | **~0,1–0,5 ms** (VirtIO SSD) | **~1–3 ms** (LAN + iSCSI stack) | +| Throughput maksimum | Sesuai disk host (SSD: 500+ MB/s) | **~110 MB/s** (1 GbE) · ~1 GB/s (10 GbE) | +| IMAP / Outlook sync (banyak file kecil) | **Lebih responsif** | Cukup, terasa sedikit lebih lambat saat sync awal | +| Beban 30 user concurrent | **Lebih nyaman** | Bisa, bottleneck di jaringan 1 GbE | +| Postfix queue / spike | **Lebih stabil** | Lonjakan I/O + traffic LAN bersamaan | + +**Pola beban Mailcow:** Dovecot membaca/ menulis ribuan file kecil (Maildir) — **sangat sensitif latency**, bukan hanya throughput. Local SSD menang jelas untuk kecepatan sehari-hari. + +### Keandalan + +| Aspek | **Local storage VM** | **iSCSI LUN QNAP** | +|-------|----------------------|---------------------| +| Kegagalan disk VM saja | ❌ Data ikut hilang *(tanpa backup)* | ✅ Data tetap di QNAP RAID | +| Kegagalan NAS / jaringan | ✅ VM tetap jalan *(jika disk lokal)* | ❌ **Mail down** — I/O hang | +| Reboot VM | ✅ Stabil | ⚠️ Perlu iSCSI reconnect otomatis | +| RAID / redundansi | Tergantung disk Proxmox host | ✅ QNAP RAID5/6 biasanya lebih baik | +| Restore disaster | Dari backup QNAP | LUN snapshot / replicate NAS | +| Single point of failure | Disk VM (tipis) | **NAS + switch + kabel LAN** | + +**Keandalan data mentah:** iSCSI ke QNAP RAID lebih aman jika disk Proxmox `.102` tidak RAID. +**Keandalan layanan mail online:** local storage lebih andal — tidak bergantung jaringan ke NAS. + +### Skor ringkas (30 user produksi) + +| Kriteria | Local VM (SSD) | iSCSI QNAP | +|----------|----------------|------------| +| **Kecepatan** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | +| **Uptime layanan** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | +| **Keamanan data (hardware)** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| **Kapasitas / expand** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| **Kesederhanaan ops** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | + +--- + +## Rekomendasi terbaik (Geonet) + +### 🥇 **Hybrid — dipilih Geonet (2026-07-03)** + +Prioritas: **uptime layanan mail** → live storage **local SSD VM**, bukan NAS. + +``` +Live vmail → Local SSD VM `10.100.1.28` disk 2 (512 GiB) +Backup → QNAP harian (rsync / Mailcow backup) +DB + Redis → Local SSD VM (selalu) +``` + +| Mengapa | | +|---------|--| +| Kecepatan IMAP/Outlook | Maksimal — tanpa hop jaringan | +| **Uptime mail** | Mail tetap jalan meski NAS maintenance / LAN ke QNAP down | +| Keandalan data | Backup harian + snapshot QNAP | +| Kompleksitas | Rendah — tidak perlu iSCSI tuning | + +### 🥈 **iSCSI QNAP** — tidak dipilih *(trade-off uptime)* + +- Disk lokal Proxmox `.102` **kecil atau HDD lambat** +- QNAP punya **SSD pool** dan kapasitas besar +- Ingin **satu pool storage terpusat** + snapshot LUN +- Bisa terima trade-off: sedikit lebih lambat, risiko mail down saat NAS/LAN bermasalah + +### ❌ Hindari: + +- NFS/SMB live untuk vmail (lebih lemah dari iSCSI untuk Maildir) +- Hanya local tanpa backup ke QNAP +- Hanya iSCSI tanpa monitoring path NAS + +--- + +QNAP expose LUN iSCSI → Proxmox/VM mount sebagai block device. + +``` +QNAP 10.100.1.10 + └── iSCSI LUN 300GB "mailcow-vmail" + └── VM mail-sync (Debian) + └── /dev/sdb → ext4 → /data/mailcow/vmail + └── docker-compose.override.yml bind mount +``` + +**Kelebihan:** +- Performa mendekati disk lokal +- Tidak ada masalah file locking seperti NFS +- Dovecot tidak perlu mode NFS khusus +- Expand LUN dari QNAP saat penuh + +**Setup ringkas:** +1. QNAP → iSCSI Storage → buat LUN + target +2. VM → `iscsiadm` connect → format `ext4` → `/etc/fstab` +3. Mailcow `docker-compose.override.yml` bind ke path tersebut + +--- + +## Opsi 2 — NFS (bisa, butuh hati-hati) + +Mount NFS di host VM, bind ke volume Docker — **jangan pakai symlink** ke `_data` Docker (risiko inbox kosong setelah reboot). + +### Host: `/etc/fstab` + +``` +10.100.1.10:/mailcow-vmail /mnt/mailcow-vmail nfs nfsvers=4.1,noac,rw,hard,timeo=600,retrans=2,_netdev 0 0 +``` + +> `noac` = disable attribute cache — penting untuk konsistensi Maildir di NFS. + +### Mailcow: `docker-compose.override.yml` + +```yaml +volumes: + vmail-vol-1: + driver: local + driver_opts: + type: none + device: /mnt/mailcow-vmail + o: bind +``` + +### Dovecot: aktifkan mode NFS + +Edit `data/conf/dovecot/dovecot.conf` (uncomment): + +``` +mmap_disable = yes +mail_fsync = always +mail_nfs_index = yes +mail_nfs_storage = yes +``` + +Restart: `docker compose restart dovecot-mailcow` + +**Risiko NFS:** permission intermittent, latency IMAP, issue saat reboot jika mount order salah. + +Ref: [Mailcow — Move Maildir](https://docs.mailcow.email/manual-guides/Dovecot/u_e-dovecot-vmail-volume/), [GitHub #5339](https://github.com/mailcow/mailcow-dockerized/issues/5339) + +--- + +## Opsi 3 — Disk lokal VM + backup ke NAS (paling sederhana) + +| Live | Backup | +|------|--------| +| Disk VM 512 GiB vmail (`.27`) | Harian rsync/NFS ke QNAP | + +``` +/opt/stacks/mailcow/helper-scripts/backup_and_restore.sh backup all +# → rsync ke 10.100.1.10:/backup/mailcow/ +``` + +**Kelebihan:** Stabil, tidak ada kompleksitas NFS/iSCSI. +**Kekurangan:** Kapasitas terbatas ukuran disk VM — expand manual. + +Cocok jika awal 30 user dan belum butuh ratusan GB segera. + +--- + +## Perbandingan untuk 30+ user aktif + +| Kriteria | iSCSI | NFS live | Lokal + backup NAS | +|----------|-------|----------|---------------------| +| Stabilitas IMAP | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| Expand storage | Mudah (grow LUN) | Mudah | Expand disk VM | +| Kompleksitas | Sedang | Tinggi | Rendah | +| Performa Outlook sync | Baik | Sedang | Baik | +| Disaster recovery | Snapshot LUN QNAP | Snapshot share | Restore dari backup | + +**Rekomendasi Geonet:** **iSCSI LUN dari QNAP** untuk vmail live + **backup harian** script Mailcow ke share NFS terpisah. + +--- + +## QNAP — share yang disarankan + +| Share QNAP | Protokol | Fungsi | +|------------|----------|--------| +| `mailcow-vmail` | iSCSI LUN atau NFS | Data email live | +| `backup-mailcow` | NFS / SMB | Backup harian (rsync) | + +Jaringan: VM `.102` ↔ NAS `.10` lewat LAN `10.100.1.x` (low latency). + +--- + +## Yang tidak bisa: OSS seperti Zammad + +Zammad attachment pakai **S3** (`http://10.100.1.10:8010`). Mailcow **tidak** punya driver S3 untuk mailbox — Dovecot butuh **Maildir di filesystem POSIX**. + +--- + +## Checklist implementasi NAS + +- [ ] Pilih: iSCSI (preferred) atau NFS atau lokal+backup +- [ ] Buat LUN/share di QNAP +- [ ] Mount di VM **sebelum** Docker start (`_netdev` di fstab) +- [ ] `docker-compose.override.yml` bind mount (bukan symlink) +- [ ] Dovecot NFS settings jika pakai NFS +- [ ] MariaDB/Redis tetap volume lokal +- [ ] Tes reboot VM — inbox tidak boleh kosong +- [ ] Backup harian ke share terpisah + +--- + +## Referensi + +- `docs/notes/deployment-sizing.md` +- [Mailcow vmail volume](https://docs.mailcow.email/manual-guides/Dovecot/u_e-dovecot-vmail-volume/) +- QNAP iSCSI: Storage & Snapshots → iSCSI diff --git a/Mailcow/docs/project-status.md b/Mailcow/docs/project-status.md new file mode 100644 index 0000000..114f04a --- /dev/null +++ b/Mailcow/docs/project-status.md @@ -0,0 +1,74 @@ +# Project Status — Mailcow + +> **Terakhir Diperbarui:** 2026-07-03 + +--- + +## Keputusan arsitektur + +| Keputusan | Pilihan | Tanggal | +|-----------|---------|---------| +| **VM IP** | `10.100.1.28` | 2026-07-03 | +| **vCPU / RAM** | 16 core / 32 GiB | 2026-07-03 | +| **Disk 1** | 512 GiB SSD — OS + DB | 2026-07-03 | +| **Disk 2** | 512 GiB SSD — vmail live | 2026-07-03 | +| **Prioritas storage** | Uptime layanan mail — local SSD | 2026-07-03 | +| **Backup** | QNAP `10.100.1.10` harian | 2026-07-03 | + +Mail tetap jalan meski NAS maintenance atau gangguan LAN ke QNAP. + +--- + +## Ringkasan + +| Item | Status | +|------|--------| +| Dokumentasi repo | ✅ | +| Konsep POP3 drain → Mailcow | ✅ `docs/notes/email-sync-migration-concept.md` | +| Konsep LDAP AD | ✅ `docs/notes/ldap-ad-mailcow.md` | +| Grup AD `Mail-Users` | ✅ 2026-07-03 | +| Member `support` + `mail` | ✅ `support@geonet.co.id` | +| **Storage live** | Local SSD VM + backup QNAP | ✅ Keputusan 2026-07-03 | +| **VM Mailcow** | `10.100.1.28` — 16 vCPU, 32 GB, 2×512 GB SSD | ✅ | +| SSH key login | `ssh mailcow` | ✅ 2026-07-03 | +| OS prep (hostname, disk, docker) | ✅ 2026-07-03 | +| Desktop GNOME (Proxmox console) | ✅ ubuntu-desktop-minimal | +| Install Mailcow stack | ✅ 2026-07-03 — `/opt/stacks/mailcow` | +| Domain `geonet.co.id` | ✅ aktif, DKIM generated | +| Mailbox `support@geonet.co.id` | ✅ auth mailcow (service account) | +| SOGo login + kirim/terima | ✅ verified user 2026-07-03 | +| Outbound relay cPanel | ✅ `sc138.idcloudhosting.cloud:587` | +| Nginx proxy `sync.geonet.co.id` | ✅ `.24` + Let's Encrypt | +| LDAP Identity Provider | ✅ 2026-07-03 (user AD lain) | +| fetchmail POP3 drain | ✅ timer 2 menit — `scripts/install-fetchmail-support.sh` | +| Zammad IMAP → Mailcow | ❌ | +| DKIM/SPF DNS publish | ❌ | + +--- + +## Active Directory — Mail-Users + +| Item | Nilai | +|------|-------| +| Grup | `Mail-Users` | +| DN (asumsi default) | `CN=Mail-Users,CN=Users,DC=gisportal,DC=id` | +| Member pertama | `support` | +| Email (`mail`) | `support@geonet.co.id` | +| Login AD | `support` (sAMAccountName) | + +> Verifikasi DN grup jika LDAP filter gagal: PowerShell di AD → `(Get-ADGroup 'Mail-Users').DistinguishedName` + +--- + +## Berikutnya + +1. Provision VM + Mailcow + LDAP | ✅ +2. Domain `geonet.co.id` + mailbox `support@` | ✅ +3. DNS email (DKIM/SPF) untuk `geonet.co.id` | ⏳ +4. fetchmail POP3 drain dari cPanel | ✅ +5. Outbound relay cPanel (transisi) | ✅ +6. SOGo `support@` operational | ✅ +7. DNS DKIM/SPF + PTR | ⏳ +8. Zammad IMAP/SMTP → Mailcow | ⏳ + +Lihat `docs/todo.md`, `docs/ai-session-summary.md`. diff --git a/Mailcow/docs/server.md b/Mailcow/docs/server.md new file mode 100644 index 0000000..19d9561 --- /dev/null +++ b/Mailcow/docs/server.md @@ -0,0 +1,204 @@ +# Server — Mailcow VM + +> **Terakhir Diperbarui:** 2026-07-03 (Dockge agent) + +--- + +## VM Mailcow + +| Item | Nilai | +|------|-------| +| **IP LAN** | `10.100.1.28` | +| Hostname | `mailserver` | +| FQDN mail (Mailcow nanti) | `sync.geonet.co.id` | +| **Role** | Mail server (Mailcow dockerized) | +| **Hypervisor** | Proxmox Opr `10.100.1.102` *(asumsi — sesuaikan jika beda)* | +| **Stack path** | `/opt/stacks/mailcow` (Dockge) | +| **Dockge agent** | `http://10.100.1.28:5001` — dikelola dari `dockge.gisportal.id` (`.24`) | +| **Web UI** | https://sync.geonet.co.id *(nginx `.24` → Mailcow `.28`)* | + +## Desktop GNOME (opsional) + +| | | +|--|--| +| **Boleh dipakai?** | ✅ Ya — dengan **32 GB RAM** tidak masalah | +| **Paket** | `ubuntu-desktop-minimal` + GDM | +| **Akses** | Proxmox noVNC / console | +| **Mailcow** | Tetap di Docker — desktop tidak mengganggu | + +Yang tetap **tidak perlu** (boleh hapus): CUPS, Avahi, Snap, LibreOffice. + +Prep script: `KEEP_DESKTOP=1 ./prepare-mailserver.sh` agar desktop tidak di-purge. + +--- + +| Item | Nilai | +|------|-------| +| Hostname | `mailserver` | +| OS | Ubuntu 22.04.5 LTS | +| Desktop GNOME | ✅ `ubuntu-desktop-minimal` — akses Proxmox console | +| Snap | ❌ Dihapus (tidak wajib untuk desktop) | +| CUPS / Avahi services | ❌ Dihapus (tidak perlu mail server) | +| Docker | ✅ 29.x + Compose v5 | +| Dockge agent | ✅ `/opt/dockge` — port `5001` (LAN only) | +| UFW firewall | ✅ Aktif | +| `vm.max_map_count` | 262144 | +| Swap | 4 GiB | +| `/data/mailcow/vmail` | `/dev/sdb1` 503 GiB | + +Script prep: `Mailcow/scripts/prepare-mailserver.sh` + +--- + +### Spesifikasi hardware + +| Resource | Nilai | +|----------|-------| +| **vCPU** | 16 core | +| **RAM** | 32 GiB | +| **Swap** | 4 GiB *(disarankan)* | +| **Disk 1** | 512 GiB SSD — OS + Docker + MariaDB + Redis | +| **Disk 2** | 512 GiB SSD — `vmail` (email live, local) | +| **Storage live** | Local SSD — prioritas uptime *(bukan NAS)* | +| **Backup** | QNAP `10.100.1.10` harian | + +> Kapasitas 512 GiB vmail cukup untuk 30+ user aktif bertahun-tahun (asumsi ~10–15 GB/user). + +--- + +## Host terkait + +| Role | IP | Keterangan | +|------|-----|------------| +| **Mailcow VM** | `10.100.1.28` | Server ini | +| Dockge primary | `10.100.1.24` | `dockge.gisportal.id` — UI manajemen Docker | +| Zammad | `10.100.1.24` | IMAP/SMTP ke `.28` | +| AD / LDAP | `10.100.1.40` | Identity Provider Mailcow | +| QNAP NAS | `10.100.1.10` | Backup harian | +| cPanel POP3 | `mail.geonet.co.id` | fetchmail drain | +| Proxmox Opr | `10.100.1.102` | Host VM *(jika applicable)* | + +--- + +## SSH + +### Login (passwordless) + +```bash +ssh mailcow +# atau +ssh root@10.100.1.28 +``` + +Key: `~/.ssh/id_ed25519_mailcow` · Host alias `mailcow` di `~/.ssh/config` + +### Setup key (sekali — sudah selesai 2026-07-03) + +Jika perlu ulang di mesin lain: `Mailcow/scripts/fix-ssh-key.ps1` + +**Catatan:** Hindari pipe script PowerShell ke `bash -s` (CRLF). Pakai SCP upload file `.sh` + `.pub`. + +| File key | Lokasi | +|----------|--------| +| Private | `~/.ssh/id_ed25519_mailcow` | +| Public | `~/.ssh/id_ed25519_mailcow.pub` | +| SSH config | Host `mailcow` → `10.100.1.28` | + +--- + +## Dockge agent (monitoring dari `.24`) + +Docker di VM ini dikelola lewat **Dockge Agents** — instance Dockge di `.28` didaftarkan ke Dockge utama di `10.100.1.24` (`dockge.gisportal.id`). + +| Item | Nilai | +|------|-------| +| Agent URL | `http://10.100.1.28:5001` | +| Compose | `/opt/dockge/compose.yaml` | +| Stacks dir | `/opt/stacks/` | +| Bind port | `10.100.1.28:5001` *(bukan `0.0.0.0` — tidak listen di localhost)* | +| Primary | Dockge v1.5.0 di `.24` | + +### Instalasi (sudah selesai 2026-07-03) + +```bash +# Di mailserver — atau ulang dari repo: +bash Mailcow/scripts/install-dockge-agent.sh +bash Mailcow/scripts/setup-dockge-agent-user.sh # samakan user admin dengan primary +``` + +### Daftarkan agent di UI primary *(sekali)* + +1. Buka https://dockge.gisportal.id +2. **Settings → Dockge Agents → Add Agent** +3. URL: `http://10.100.1.28:5001` +4. Username / password: sama dengan login Dockge primary (`admin`) +5. Status agent harus **online** — stack Mailcow nanti bisa dipilih agent **mailserver** + +> Port `5001` **tidak** di-expose ke internet; hanya `10.100.1.24` yang diizinkan UFW. + +--- + +## Firewall / port (VM `.28`) + +UFW aktif — default deny incoming, allow outgoing. + +| Port | Protokol | Layanan | Sumber | +|------|----------|---------|--------| +| 22 | TCP | SSH | Anywhere | +| 25 | TCP | SMTP inbound | Anywhere | +| 80 | TCP | HTTP (ACME redirect) | Anywhere | +| 443 | TCP | HTTPS — Mailcow UI | Anywhere | +| 465 | TCP | SMTPS | Anywhere | +| 587 | TCP | Submission | Anywhere | +| 993 | TCP | IMAPS | Anywhere | +| 995 | TCP | POP3S *(opsional)* | Anywhere | +| 5001 | TCP | Dockge agent | **Hanya** `10.100.1.24` | + +### Akses internal yang diperlukan + +| Dari | Ke | Port | +|------|-----|------| +| `10.100.1.28` | `10.100.1.40` | 389 LDAP | +| `10.100.1.28` | Internet | 995 POP3 (cPanel drain) | +| `10.100.1.24` | `10.100.1.28` | 5001 Dockge, 993, 587 | +| User LAN/VPN | `10.100.1.28` atau IP publik | 993, 587 | + +--- + +## DNS & NAT publik + +**IP publik:** `117.102.73.102` + +| Record | Target | +|--------|--------| +| A `sync.geonet.co.id` | `117.102.73.102` | +| PTR | `sync.geonet.co.id` *(verifikasi di provider)* | + +### Port forwarding (MikroTik / gateway) + +| Port | NAT ke | Layanan | +|------|--------|---------| +| 25, 465, 587, 993 | `10.100.1.28` | Mailcow — SMTP / IMAP langsung | +| 80, 443 | `10.100.1.24` | Nginx reverse proxy | + +> **HTTPS Mailcow UI** tidak langsung ke `.28` dari internet — Nginx di `.24` harus proxy `sync.geonet.co.id` → `https://10.100.1.28:443`. Saat install Mailcow set `SKIP_LETS_ENCRYPT=y`; sertifikat publik diurus Nginx `.24` (certbot). + +Akses internal (Zammad, LAN): langsung ke `10.100.1.28:587` / `:993` tanpa lewat NAT publik. + +--- + +## Partition disk (rencana) + +| Device | Mount | Isi | +|--------|-------|-----| +| Disk 1 | `/` | Debian/Ubuntu + Docker | +| Disk 1 | `/var/lib/docker` | Container layers, MariaDB, Redis volumes | +| Disk 2 | `/data/mailcow/vmail` | Bind mount → `vmail-vol-1` Mailcow | + +--- + +## Referensi + +- `docs/notes/deployment-sizing.md` +- `docs/notes/storage-nas-qnap.md` +- `docs/project-status.md` diff --git a/Mailcow/docs/todo.md b/Mailcow/docs/todo.md new file mode 100644 index 0000000..aa52309 --- /dev/null +++ b/Mailcow/docs/todo.md @@ -0,0 +1,47 @@ +# TODO — Mailcow + +> Last updated: 2026-07-03 + +--- + +## High Priority + +- [ ] Publish DKIM TXT dkim._domainkey.geonet.co.id (key dari Mailcow API) +- [ ] Update SPF geonet.co.id — include IP 117.102.73.102 atau relay sementara +- [ ] Zammad channel email → IMAP/SMTP Mailcow 10.100.1.28 (ganti cPanel) + +--- + +## Medium Priority + +- [ ] PTR/rDNS 117.102.73.102 → sync.geonet.co.id +- [ ] Buat scripts/install-relay-cpanel.sh (mirror fetchmail installer) +- [ ] Automasi sync _sogo_static_view setelah password mailbox mailcow berubah +- [ ] Monitoring fetchmail (Uptime Kuma atau alert log) + +--- + +## Low Priority + +- [ ] fetchmail entry untuk mailbox tambahan (info@, dll.) +- [ ] LDAP user lain di Mail-Users — provisioning + Outlook guide +- [ ] Domain sekunder gegeo.my.id +- [ ] MX cutover ke sync.geonet.co.id (setelah 2–4 minggu stabil) +- [ ] Matikan fetchmail + relay cPanel pasca cutover + +--- + +## Selesai (Sesi 2026-07-03) + +- [x] fetchmail POP3 drain support@ + timer 2 menit +- [x] Relay outbound cPanel :587 untuk geonet.co.id +- [x] SOGo login + kirim/terima email verified +- [x] scripts/install-fetchmail-support.sh +- [x] Dokumentasi handover sesi + +--- + +## Technical Debt + +- [ ] support@ service account vs LDAP — dokumentasikan keputusan +- [ ] context-index diagram IP — align ke .28 diff --git a/Mailcow/infra/nginx/sync.geonet.co.id.conf b/Mailcow/infra/nginx/sync.geonet.co.id.conf new file mode 100644 index 0000000000000000000000000000000000000000..352f69adbf0c3ebff3977d907fafc8d4bae2a425 GIT binary patch literal 2628 zcmb`JUvCmo5XI-2PjPMgP#+3ysm9==#%N-bMl|tlLtzUWDd4iTt;R3WPwel^?Xqi& zg&^6$a_`~S)+?^vY1PTV%zAf8ya;yXu~%IEPGqpW97UXn$vWnL$JRFl4? zruBXqyE4j-`ZcF6XPj*-N(4gp#6(Dn0?Ds(i(sq0Gqlgg)im zg`-qi?7RBPNP)e&_lCRX$N>IA%K#|sL5%jsG1a-s zPgS9FrkJ|o>FH6=?=svn=dtrukIHZrb!k)H>zvB|Oz!7~;@0%kT+)BUYTxSm#MSPh zo$?UuJs5FrR{g#i(pM(-Cr~x>4(x-SfgUHvB|g+~3C{*x`G#EO;T>4HU4xW+41>j< zyw&xJz7nsNi$_)o+6!s(SeG$515vR~J@&az0QG&kWk1`?+7~n%!a7!jG_2}O|DDyd z&6IkB789-%Ez0+dU^`66I`+;=ea^AaY*5u|q7G4by}r@(QFMv>S1zVt=^dnPFPRvJ c)c-oM>FwZuFyi}Hsl;O>arv8x-WBxu0}@xNJpcdz literal 0 HcmV?d00001 diff --git a/Mailcow/scripts/fix-mailcow-dns-ufw.sh b/Mailcow/scripts/fix-mailcow-dns-ufw.sh new file mode 100644 index 0000000000000000000000000000000000000000..34971f628305c561a421bfe4725f2370245b4a8e GIT binary patch literal 1544 zcmb`HTW{Jx5QWb(zrrOCO;x#W8}*{7sX_xpsELC@Xw@e~z$7SOB7>EtzdqlrO)=Y6 z$wOr=vzM9KGiMIFqi2eAsi{(Dhg#}dHGUJV6ez^zS}?oC=a$t(LuNC4YT9AH&FUw% z&+I#PT>9krtjH5+S4}dEbi+x;I>jdV*;!j>Iw!8dZ&L@@Bfgfpy3h;Ghj@>%Irfq) zW^LV6tR8m4UZy+zGIw)E)>j}Kv19l@Ga_zVu@gBD!(U*FuoGefec}uBysV)GrZ%gh zzQ>|#>VWo}-h=+0o0h~ish~|QeVtIp0FM}-zMFT+e!|X?eh^W|_ne(Bvp?g`T+F{B zt6cppdYjt;cWmGMSbT$sZi%%4_73qe)%baO`sz3^45w5bGmc?kpfBL>I1Y?~9`&a5 zt6A^t{CNA(fsPw7mO9Yqqj1k?N(bW;LDIMFypMt3ASZ=xOb;n|%#G;F)(sh?J zx-%ok5FOb597T>%uW2$w+oqHSc7oIFPkA7n^EmaljEAW5i zwHtGXZUL$dCshr{@NUY9oetMp-u|bA`sLV6v=0+O`K8n}hoybib+TJW*Jpmbu{ef1 z^ZkhLW*q9B_MRB|hRDrWM;dm&2J6^}8=u;x8ot$6$9gxXy9?M$$YN?Jx}4EV|Ah&? zp4*E!BO-A+*`q=~f5I!6fH3ePt0< finluFT`Y7kXZIyIuc^^$@)7zB$null | Out-Null +icacls $key /grant:r "${env:USERNAME}:(R)" 2>$null | Out-Null + +# Pub key LF-only +$tempPub = Join-Path $env:TEMP 'geonet_mailcow_key.pub' +$keyLine = (Get-Content $pub -Raw).Trim() -replace "`r", "" +[System.IO.File]::WriteAllText($tempPub, $keyLine + "`n") + +# Remote script LF-only +$shContent = (Get-Content $remoteSh -Raw) -replace "`r", "" +$tempSh = Join-Path $env:TEMP 'remote-reset-authorized-keys.sh' +[System.IO.File]::WriteAllText($tempSh, $shContent) + +Write-Host "Upload + reset on root@${hostIp} (password 2x: scp + ssh)..." +scp -o PreferredAuthentications=password -o PubkeyAuthentication=no $tempPub "root@${hostIp}:/tmp/geonet_mailcow_key.pub" +scp -o PreferredAuthentications=password -o PubkeyAuthentication=no $tempSh "root@${hostIp}:/tmp/remote-reset-authorized-keys.sh" +ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no "root@${hostIp}" 'chmod +x /tmp/remote-reset-authorized-keys.sh && bash /tmp/remote-reset-authorized-keys.sh && rm -f /tmp/remote-reset-authorized-keys.sh' + +Remove-Item $tempPub, $tempSh -Force -ErrorAction SilentlyContinue + +Write-Host "" +Write-Host "Test key-only..." +ssh -i $key -o BatchMode=yes -o IdentitiesOnly=yes -o PreferredAuthentications=publickey "root@${hostIp}" "echo KEY_AUTH_OK" + +if ($LASTEXITCODE -ne 0) { + Write-Host "" + Write-Host "Masih gagal — ambil auth.log (password sekali):" + Write-Host " ssh root@$hostIp `"grep sshd /var/log/auth.log | tail -20`"" + exit 1 +} +Write-Host "Success. Login: ssh mailcow" diff --git a/Mailcow/scripts/install-dockge-agent.sh b/Mailcow/scripts/install-dockge-agent.sh new file mode 100644 index 0000000..e7b3207 --- /dev/null +++ b/Mailcow/scripts/install-dockge-agent.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Install Dockge agent on mailserver (10.100.1.28) for remote management from Dockge primary (.24). +set -euo pipefail + +DOCKGE_PRIMARY_IP="${DOCKGE_PRIMARY_IP:-10.100.1.24}" +BIND_IP="${BIND_IP:-10.100.1.28}" + +mkdir -p /opt/stacks /opt/dockge/data + +cat > /opt/dockge/compose.yaml << EOF +services: + dockge: + image: louislam/dockge:1 + restart: unless-stopped + ports: + - ${BIND_IP}:5001:5001 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./data:/app/data + - /opt/stacks:/opt/stacks + environment: + - DOCKGE_STACKS_DIR=/opt/stacks +EOF + +cd /opt/dockge +docker compose up -d + +if command -v ufw >/dev/null 2>&1; then + ufw allow from "${DOCKGE_PRIMARY_IP}" to any port 5001 proto tcp comment 'Dockge primary' || true +fi + +echo "Dockge agent started on ${BIND_IP}:5001" +echo "Register from Dockge primary: Settings -> Agents -> Add -> http://${BIND_IP}:5001" diff --git a/Mailcow/scripts/install-fetchmail-support.sh b/Mailcow/scripts/install-fetchmail-support.sh new file mode 100644 index 0000000..37a7f82 --- /dev/null +++ b/Mailcow/scripts/install-fetchmail-support.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# Install fetchmail POP3 drain: cPanel mail.geonet.co.id -> Mailcow support@geonet.co.id +# Run on Mailcow VM (10.100.1.28) as root. +set -euo pipefail + +PASS_FILE="${PASS_FILE:-/opt/fetchmail/support.pass}" +FETCHMAILRC="${FETCHMAILRC:-/opt/fetchmail/fetchmailrc}" +POP3_USER="${POP3_USER:-support@geonet.co.id}" +POP3_HOST="${POP3_HOST:-mail.geonet.co.id}" +LOCAL_USER="${LOCAL_USER:-support@geonet.co.id}" + +usage() { + echo "Usage: POP3_PASSWORD='...' $0" >&2 + echo " or: PASS_FILE=/path/to/secret $0" >&2 + exit 1 +} + +if [[ -n "${POP3_PASSWORD:-}" ]]; then + install -d -m 700 /opt/fetchmail + printf '%s' "$POP3_PASSWORD" >"$PASS_FILE" + chmod 600 "$PASS_FILE" +elif [[ ! -f "$PASS_FILE" ]]; then + usage +fi + +apt-get install -y -qq fetchmail + +python3 - "$PASS_FILE" "$FETCHMAILRC" "$POP3_USER" "$POP3_HOST" "$LOCAL_USER" <<'PY' +import pathlib, sys + +pass_file, rc_path, pop3_user, pop3_host, local_user = sys.argv[1:6] +password = pathlib.Path(pass_file).read_text() + +cfg = f'''set postmaster "{local_user}" +set syslog +set logfile /var/log/fetchmail-support.log + +poll {pop3_host} with proto POP3 port 995 + user "{pop3_user}" there with password {password!r} is "{local_user}" here + ssl + no sslcertck + smtphost 127.0.0.1 + smtpname sync.geonet.co.id + fetchall + nokeep +''' +path = pathlib.Path(rc_path) +path.write_text(cfg) +path.chmod(0o600) +PY + +touch /var/log/fetchmail-support.log +chmod 600 /var/log/fetchmail-support.log + +cat >/etc/systemd/system/fetchmail-support.service </etc/systemd/system/fetchmail-support.timer <<'EOF' +[Unit] +Description=Poll cPanel POP3 every 2 minutes + +[Timer] +OnBootSec=90s +OnUnitActiveSec=2min +AccuracySec=30s +Persistent=true + +[Install] +WantedBy=timers.target +EOF + +systemctl daemon-reload +systemctl enable --now fetchmail-support.timer + +echo "fetchmail installed. Timer status:" +systemctl status fetchmail-support.timer --no-pager || true +echo "Test run:" +fetchmail -f "$FETCHMAILRC" -c && fetchmail -f "$FETCHMAILRC" -v -N +echo "Log: /var/log/fetchmail-support.log" diff --git a/Mailcow/scripts/install-mailcow.sh b/Mailcow/scripts/install-mailcow.sh new file mode 100644 index 0000000000000000000000000000000000000000..a20f7e235c44a74c570fec47b4f728c9a544e892 GIT binary patch literal 2300 zcma);TTk0S5QXR2&;0==w1QTOU8+7*^dixlN+D3us8#6&L1KuNYjZ2K)Y6kp{?77J+{b=eva&kJ+p_L7;&zi$;F`b&=F^vYS!c_zC!i70@f0wLMt?(sun)HHQ1;MJv3FO< z72daP7p?pD6}_`^(lf9Ne6GRA85WB-c@sG%BmAhF*HN{@g}7C;Nbezf_Lzmc1#*i2 zv3+E0a`#=lJlYrJy=}8>6n8uubr2NqS^i_)Bcdlr~=a z)nZ&qWI`$1Em|YK1F%n#_|Cn;T?Tm(TI`rjv0a!y?K$I+JWgOb;5meM?S?Sk%J>i2 zA9D5Ja1)Q?Or}A8on*0T&tW3x!Dptd>Vn!tS05dJnHSqBzfO^oceOj@ivEj@o7#N_ zbsSIgyzV)hI(VtGYxV$Nf53_E4L7c_uDH!+t$4iTjvO!IQT{1A5^`L=OKS>e5t!;2 zxnHZCdW}?rUDbKWDE2#c&U2p~-y>Afs^UIa=hR2uPt+%#@^&xONnh!TNDGV_>$~KB zE?dE(>m8|qygF9S-I>#;+$`H~#x?sz4ewA%pYTFRRo;)7_o&|k`^I{e3KT1gm@ej) zJdvMeY>^K2ujTYa_6XT!EV@AMHmd?`XrVd5cjbEmS7JlUE*XlO6ELNa9E-oxz}$rc?#y-j_?vpwyO> /etc/hosts +grep -q '10.100.1.28' /etc/hosts || echo '10.100.1.28 mailserver sync.geonet.co.id' >> /etc/hosts + +log "=== 2. Kernel / sysctl (Mailcow) ===" +grep -q 'vm.max_map_count' /etc/sysctl.conf || echo 'vm.max_map_count = 262144' >> /etc/sysctl.conf +sysctl -w vm.max_map_count=262144 + +log "=== 3. Disk sdb -> /data/mailcow/vmail ===" +if ! blkid /dev/sdb1 &>/dev/null; then + parted -s /dev/sdb mklabel gpt + parted -s /dev/sdb mkpart primary ext4 0% 100% + sleep 2 + mkfs.ext4 -F -L mailcow-vmail /dev/sdb1 +fi +mkdir -p /data/mailcow/vmail +UUID=$(blkid -s UUID -o value /dev/sdb1) +grep -q "$UUID" /etc/fstab || echo "UUID=$UUID /data/mailcow/vmail ext4 defaults,noatime 0 2" >> /etc/fstab +mount -a +chown root:root /data/mailcow/vmail +chmod 755 /data/mailcow + +log "=== 4. Swap 4G ===" +if [ "$(swapon --show=SIZE --noheadings -n 1 2>/dev/null | tr -d 'G')" != "4" ]; then + swapoff -a 2>/dev/null || true + rm -f /swapfile + fallocate -l 4G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=4096 + chmod 600 /swapfile + mkswap /swapfile + swapon /swapfile + grep -q '/swapfile' /etc/fstab || echo '/swapfile none swap sw 0 0' >> /etc/fstab +fi + +systemctl stop unattended-upgrades 2>/dev/null || true +systemctl disable unattended-upgrades 2>/dev/null || true + +log "=== 5. Desktop (optional) ===" +if [ "$KEEP_DESKTOP" = "1" ]; then + log "KEEP_DESKTOP=1 — skip purge, keep ubuntu-desktop for Proxmox console" +else + systemctl stop gdm 2>/dev/null || systemctl stop gdm3 2>/dev/null || true + systemctl disable gdm 2>/dev/null || systemctl disable gdm3 2>/dev/null || true + log "Desktop purge enabled — set KEEP_DESKTOP=1 to retain GNOME" +fi + +log "=== 6. Stop unneeded services ===" +systemctl stop cups cups-browsed avahi-daemon ModemManager bluetooth 2>/dev/null || true +systemctl disable cups cups-browsed avahi-daemon ModemManager bluetooth 2>/dev/null || true + +log "=== 6. Remove snap packages ===" +if command -v snap >/dev/null; then + for s in $(snap list 2>/dev/null | awk 'NR>1 {print $1}'); do + snap remove "$s" 2>/dev/null || true + done +fi + +log "=== 7. Purge desktop (skip if KEEP_DESKTOP=1) ===" +if [ "$KEEP_DESKTOP" != "1" ]; then + apt-get update -qq + apt-get purge -y \ + ubuntu-desktop ubuntu-desktop-minimal ubuntu-session \ + gdm3 gnome-shell gnome-shell-common \ + 'gnome-shell-extension-*' yaru-theme-gnome-shell \ + snapd gir1.2-snapd-1 libsnapd-glib1 \ + cups cups-browsed cups-client cups-common \ + avahi-daemon avahi-autoipd \ + ModemManager bluetooth bluez \ + packagekit packagekit-tools \ + libreoffice* thunderbird* rhythmbox* totem* \ + 2>/dev/null || true + apt-get autoremove -y --purge + apt-get autoclean -y +else + log "Desktop retained for Proxmox console" +fi + +log "=== 8. Base tools for Mailcow ===" +apt-get install -y \ + ca-certificates curl gnupg lsb-release \ + git rsync unzip jq \ + apt-transport-https software-properties-common \ + net-tools dnsutils + +log "=== 9. Docker (official) ===" +if ! command -v docker >/dev/null; then + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg + chmod a+r /etc/apt/keyrings/docker.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \ + > /etc/apt/sources.list.d/docker.list + apt-get update -qq + apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + systemctl enable --now docker +fi + +log "=== 10. Verify ===" +echo "HOSTNAME=$(hostname)" +echo "DOCKER=$(docker --version)" +echo "COMPOSE=$(docker compose version)" +docker run --rm hello-world 2>&1 | tail -3 +echo "DISK_VMAIL=$(df -h /data/mailcow/vmail | tail -1)" +echo "RAM=$(free -h | awk '/^Mem:/{print $2}')" +echo "SWAP=$(free -h | awk '/^Swap:/{print $2}')" +echo "MAX_MAP=$(sysctl -n vm.max_map_count)" +echo "PREPARE_OK" diff --git a/Mailcow/scripts/remote-reset-authorized-keys.sh b/Mailcow/scripts/remote-reset-authorized-keys.sh new file mode 100644 index 0000000..3afa329 --- /dev/null +++ b/Mailcow/scripts/remote-reset-authorized-keys.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Reset root authorized_keys — run on mailserver VM +set -e +chmod 700 /root +mkdir -p /root/.ssh +chmod 700 /root/.ssh +install -m 600 -o root -g root /tmp/geonet_mailcow_key.pub /root/.ssh/authorized_keys +cp -a /root/.ssh/authorized_keys /root/.ssh/authorized_keys2 +chmod 600 /root/.ssh/authorized_keys2 +sed -i 's/\r$//' /root/.ssh/authorized_keys /root/.ssh/authorized_keys2 +rm -f /tmp/geonet_mailcow_key.pub +echo '--- path permissions (namei) ---' +namei -l /root/.ssh/authorized_keys 2>/dev/null || ls -ld / /root /root/.ssh /root/.ssh/authorized_keys +echo '--- hexdump (first line) ---' +hexdump -C /root/.ssh/authorized_keys | head -3 +echo '--- key fingerprint ---' +ssh-keygen -lf /root/.ssh/authorized_keys +echo '--- sshd effective (root) ---' +sshd -T -C user=root,host=127.0.0.1,addr=127.0.0.1 2>/dev/null | grep -iE 'pubkey|authorizedkeys|permitroot|strictmodes' || true +echo '--- reload ssh ---' +systemctl reload ssh 2>/dev/null || systemctl reload sshd 2>/dev/null || service ssh reload 2>/dev/null || true +echo '--- local pubkey self-test ---' +TEST=/tmp/geonet_sshd_selftest +rm -f "$TEST" "$TEST.pub" +ssh-keygen -t ed25519 -f "$TEST" -N "" -q +grep -qF "$(cat "$TEST.pub")" /root/.ssh/authorized_keys || cat "$TEST.pub" >> /root/.ssh/authorized_keys +if ssh -i "$TEST" -o BatchMode=yes -o StrictHostKeyChecking=no -o PreferredAuthentications=publickey root@127.0.0.1 "echo LOCAL_KEY_OK" 2>/dev/null; then + echo "LOCAL_KEY_OK: sshd accepts pubkey for root" + grep -vF "$(cat "$TEST.pub")" /root/.ssh/authorized_keys > /root/.ssh/authorized_keys.tmp || true + mv /root/.ssh/authorized_keys.tmp /root/.ssh/authorized_keys +else + echo "LOCAL_KEY_FAIL: sshd rejects ALL pubkey for root — check /etc/ssh/sshd_config" +fi +rm -f "$TEST" "$TEST.pub" +echo RESET_OK diff --git a/Mailcow/scripts/setup-dockge-agent-user.sh b/Mailcow/scripts/setup-dockge-agent-user.sh new file mode 100644 index 0000000..e155197 --- /dev/null +++ b/Mailcow/scripts/setup-dockge-agent-user.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# One-time: align Dockge admin on mailserver agent with primary (.24) credentials. +set -euo pipefail +DB=/opt/dockge/data/dockge.db +HASH='$2a$10$66pkg5WxDVUPLlZi4aLLTOPcLO3PFFRpdzl.j7973LpyD4evjLJki' +COUNT=$(sqlite3 "$DB" 'SELECT COUNT(*) FROM user;') +if [ "$COUNT" -eq 0 ]; then + sqlite3 "$DB" "INSERT INTO user (username, password, active, twofa_status) VALUES ('admin', '$HASH', 1, 0);" + echo "Admin user created on Dockge agent." +else + echo "User already exists, skipped." +fi +sqlite3 "$DB" 'SELECT username, active FROM user;' diff --git a/Mailcow/scripts/setup-ssh-key.ps1 b/Mailcow/scripts/setup-ssh-key.ps1 new file mode 100644 index 0000000..b6cb0c5 --- /dev/null +++ b/Mailcow/scripts/setup-ssh-key.ps1 @@ -0,0 +1,13 @@ +# Setup SSH key — root@10.100.1.28 (Mailcow VM) + +$ErrorActionPreference = 'Stop' +$hostIp = '10.100.1.28' +$key = Join-Path $env:USERPROFILE '.ssh\id_ed25519_mailcow' +$pub = "$key.pub" + +if (-not (Test-Path $pub)) { + Write-Host "Generating key $key ..." + ssh-keygen -t ed25519 -f $key -C 'geonet-mailcow' -N '""' +} + +& "$PSScriptRoot\fix-ssh-key.ps1" diff --git a/Workspace-Session.md b/Workspace-Session.md new file mode 100644 index 0000000000000000000000000000000000000000..03af2508b0d25588fb2731b72972e91047b1082f GIT binary patch literal 3588 zcmb`KYi}A?5QgV7pZfz&WT|p!!EqurQg5nb+}4d75RTGIR22-q5EE>1aU99NqQAJ$ zJHxWevT@p~LJND&nKSdweb};Ozu1*c?b2p;ZG9WqDSO9!&-jcun^=v{*Y>~~e028G zy0*vnf&E~=*_Z6K?G>voyt;PiC&}*Ee{7FbFX1SKZ5rFUEYD@bhXn!zp?L1Zs6I2U&6xY&`r=f5bdMc6radjIc*D?8y@kv z<~Pm~@`lJ5aX)BlOIyg7Ve13Cg?<26*;PEG*MeI@JGJ-j7kT{WHT21Ppm-1Gfi)eY zV&oJqP1mmpw;?piK1qrFO!v6A0OhsoFt_jSy%pdmeI&~&XPj@N|F8T?4`sv!?-yt= za|*@H!zF^Y+wz371>6;tQ*$m}I9h)XD_q|J)H}b)e|&uwRqDeTjK2zo%(V==WqkbvdWw)qGVK-GA^-k5+9$i4|8}9%| zJ|pbeK6ApKk-lM_?OpJUlrZkl@sF;H)0M^N2=K_D3h({nrgP9BjnvFcSu>^}M^I`t^}Baar; z56y3fd_P0JY^UBlhelm8Vqa&ntWDryzZVues&)0B``kYaZWzCG-4z;ld6+jzFYEV0LLYxTb) z!=WB~#YeU58=lSSM>YB_kK*_ze4?tdODuiGuV%?}_hCM@sC#R2ORlvl>}NcxM<2`A zm`rQV_4&$z`k$4MqIq3Y))?=LGTH0O2-siUR6efPfX#ny4JvKXS3$2lucPl9P^+`W Mzk@zn*NMfy0URekOaK4? literal 0 HcmV?d00001