26 changed files with 2242 additions and 0 deletions
@ -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 |
||||||
@ -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/ |
||||||
Binary file not shown.
@ -0,0 +1,15 @@ |
|||||||
|
# Changelog — Mailcow |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 2026-07-03 — fetchmail, SOGo, outbound relay |
||||||
|
|
||||||
|
**Ringkasan:** Email flow support@geonet.co.id end-to-end via Mailcow. |
||||||
|
|
||||||
|
**Fitur:** fetchmail POP3 drain; relay cPanel :587; SOGo operational. |
||||||
|
|
||||||
|
**Fix:** SOGo Unauthorized; Gmail 550 smarthost. |
||||||
|
|
||||||
|
**File:** scripts/install-fetchmail-support.sh, docs/* |
||||||
|
|
||||||
|
**Author:** AI Agent (Cursor) |
||||||
@ -0,0 +1,149 @@ |
|||||||
|
# Context Index — Mailcow ⭐ AI Entry Point |
||||||
|
|
||||||
|
> **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` |
||||||
@ -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` |
||||||
@ -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) |
||||||
@ -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/ |
||||||
@ -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`. |
||||||
@ -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` |
||||||
@ -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 |
||||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,41 @@ |
|||||||
|
# Fix SSH key — upload LF scripts via SCP (no CRLF pipe issues) |
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop' |
||||||
|
$hostIp = '10.100.1.28' |
||||||
|
$key = Join-Path $env:USERPROFILE '.ssh\id_ed25519_mailcow' |
||||||
|
$pub = "$key.pub" |
||||||
|
$remoteSh = Join-Path $PSScriptRoot 'remote-reset-authorized-keys.sh' |
||||||
|
|
||||||
|
# Perketat ACL private key (Windows OpenSSH) |
||||||
|
Write-Host "Fixing private key ACL..." |
||||||
|
icacls $key /inheritance:r 2>$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" |
||||||
@ -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" |
||||||
@ -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 <<EOF |
||||||
|
[Unit] |
||||||
|
Description=fetchmail POP3 drain cPanel to Mailcow (${LOCAL_USER}) |
||||||
|
After=network-online.target docker.service |
||||||
|
Wants=network-online.target |
||||||
|
|
||||||
|
[Service] |
||||||
|
Type=oneshot |
||||||
|
ExecStart=/usr/bin/fetchmail -f ${FETCHMAILRC} --nodetach |
||||||
|
SuccessExitStatus=0 1 |
||||||
|
EOF |
||||||
|
|
||||||
|
cat >/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" |
||||||
Binary file not shown.
@ -0,0 +1,116 @@ |
|||||||
|
#!/bin/bash |
||||||
|
# Prepare Ubuntu 22.04 VM for Mailcow — run as root on 10.100.1.28 |
||||||
|
# Set KEEP_DESKTOP=1 to skip desktop purge (Proxmox console UI) |
||||||
|
set -euo pipefail |
||||||
|
export DEBIAN_FRONTEND=noninteractive |
||||||
|
KEEP_DESKTOP="${KEEP_DESKTOP:-0}" |
||||||
|
|
||||||
|
log() { echo "[$(date +%H:%M:%S)] $*"; } |
||||||
|
|
||||||
|
log "=== 1. Hostname mailserver ===" |
||||||
|
hostnamectl set-hostname mailserver |
||||||
|
grep -q '^127.0.1.1' /etc/hosts && sed -i 's/^127.0.1.1.*/127.0.1.1 mailserver sync.geonet.co.id/' /etc/hosts || \ |
||||||
|
echo '127.0.1.1 mailserver sync.geonet.co.id' >> /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" |
||||||
@ -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 |
||||||
@ -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;' |
||||||
@ -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" |
||||||
Binary file not shown.
Loading…
Reference in new issue