mirror of
https://github.com/myronblair/ProxMailcow
synced 2026-06-30 17:50:40 -05:00
Initial infrastructure: NPM + Mailcow on Proxmox
- VM 200: Nginx Proxy Manager (10.48.200.80) - VM 201: Mailcow email server (10.48.200.82) - Cloud-init automation for both VMs - FortiGate VIP/policy documentation - DNS records for web.orbishosting.com - NPM proxy host setup guide - Mailcow post-install checklist - Cert sync script (NPM → Mailcow) External IP: 97.176.15.26
This commit is contained in:
@@ -1,2 +1,62 @@
|
|||||||
# ProxMailcow
|
# ProxMailcow — Proxmox + Nginx Proxy Manager + Mailcow
|
||||||
Proxmox and Mailcow Configuration
|
|
||||||
|
Full mail server stack for **web.orbishosting.com** hosted on Proxmox at `10.48.200.90`.
|
||||||
|
|
||||||
|
## Infrastructure Overview
|
||||||
|
|
||||||
|
| Service | VM ID | Hostname | LAN IP | Role |
|
||||||
|
|---------|-------|----------|--------|------|
|
||||||
|
| Nginx Proxy Manager | 200 | npm.web.orbishosting.com | 10.48.200.80 | Reverse proxy, SSL termination |
|
||||||
|
| Mailcow | 201 | mail.web.orbishosting.com | 10.48.200.82 | Full mail server |
|
||||||
|
|
||||||
|
**External IP:** `97.176.15.26`
|
||||||
|
**Domain:** `web.orbishosting.com`
|
||||||
|
**Gateway:** `10.48.200.1` (FortiGate)
|
||||||
|
**FusionPBX** (do not disturb): `orbisne.fortiddns.com` — existing SIP rules left untouched
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Start Order
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Configure DNS records → docs/dns-records.md
|
||||||
|
2. Run Proxmox VM scripts → proxmox/
|
||||||
|
3. Wait for VMs to boot (~5 min)
|
||||||
|
4. Configure NPM proxy hosts → nginx-proxy-manager/
|
||||||
|
5. Configure FortiGate → docs/fortigate-changes.md (REVIEW BEFORE APPLYING)
|
||||||
|
6. Set up Mailcow domains/users → mailcow/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Default Credentials (Change Immediately!)
|
||||||
|
|
||||||
|
| Service | URL | Username | Password |
|
||||||
|
|---------|-----|----------|----------|
|
||||||
|
| NPM Admin | http://10.48.200.80:81 | admin@example.com | changeme |
|
||||||
|
| Mailcow Admin | https://mail.web.orbishosting.com | admin | moohoo |
|
||||||
|
| NPM VM SSH | 10.48.200.80 | ubuntu | mailstack2024! |
|
||||||
|
| Mailcow VM SSH | 10.48.200.82 | ubuntu | mailstack2024! |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
FortiGate (97.176.15.26 / 10.48.200.1)
|
||||||
|
│
|
||||||
|
├── Port 80, 443 ──────────────► NPM VM (10.48.200.80)
|
||||||
|
│ │
|
||||||
|
│ └── Proxies ──► Mailcow web UI (10.48.200.82:8080)
|
||||||
|
│
|
||||||
|
├── Port 25, 465, 587 ─────────► Mailcow VM (10.48.200.82)
|
||||||
|
└── Port 143, 993, 110, 995 ──► Mailcow VM (10.48.200.82)
|
||||||
|
```
|
||||||
|
|
||||||
|
SSL flow:
|
||||||
|
- NPM obtains Let's Encrypt cert for `mail.web.orbishosting.com` (web UI)
|
||||||
|
- Mailcow's internal ACME obtains its own cert via HTTP-01 challenge forwarded through NPM
|
||||||
|
- Mailcow uses its cert for all mail protocols (SMTP/IMAP/POP3)
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# DNS Records — web.orbishosting.com
|
||||||
|
|
||||||
|
Configure these at your DNS registrar/provider. External IP: **97.176.15.26**
|
||||||
|
|
||||||
|
## Required Records
|
||||||
|
|
||||||
|
### A Records
|
||||||
|
| Name | Type | Value | TTL |
|
||||||
|
|------|------|-------|-----|
|
||||||
|
| `web.orbishosting.com` | A | `97.176.15.26` | 3600 |
|
||||||
|
| `mail.web.orbishosting.com` | A | `97.176.15.26` | 3600 |
|
||||||
|
| `npm.web.orbishosting.com` | A | `97.176.15.26` | 3600 |
|
||||||
|
|
||||||
|
### MX Record
|
||||||
|
| Name | Type | Priority | Value | TTL |
|
||||||
|
|------|------|----------|-------|-----|
|
||||||
|
| `web.orbishosting.com` | MX | `10` | `mail.web.orbishosting.com` | 3600 |
|
||||||
|
|
||||||
|
### SPF (TXT)
|
||||||
|
| Name | Type | Value |
|
||||||
|
|------|------|-------|
|
||||||
|
| `web.orbishosting.com` | TXT | `v=spf1 mx a ip4:97.176.15.26 ~all` |
|
||||||
|
|
||||||
|
### DMARC (TXT)
|
||||||
|
| Name | Type | Value |
|
||||||
|
|------|------|-------|
|
||||||
|
| `_dmarc.web.orbishosting.com` | TXT | `v=DMARC1; p=quarantine; rua=mailto:postmaster@web.orbishosting.com; ruf=mailto:postmaster@web.orbishosting.com; fo=1` |
|
||||||
|
|
||||||
|
### Autodiscover / Autoconfig (for mail clients)
|
||||||
|
| Name | Type | Value |
|
||||||
|
|------|------|-------|
|
||||||
|
| `autodiscover.web.orbishosting.com` | CNAME | `mail.web.orbishosting.com` |
|
||||||
|
| `autoconfig.web.orbishosting.com` | CNAME | `mail.web.orbishosting.com` |
|
||||||
|
|
||||||
|
### DKIM (add AFTER Mailcow is running)
|
||||||
|
1. Log into Mailcow admin: https://mail.web.orbishosting.com
|
||||||
|
2. Go to **Configuration → Domains → web.orbishosting.com → DKIM**
|
||||||
|
3. Copy the TXT record value shown
|
||||||
|
4. Add to DNS:
|
||||||
|
|
||||||
|
| Name | Type | Value |
|
||||||
|
|------|------|-------|
|
||||||
|
| `dkim._domainkey.web.orbishosting.com` | TXT | *(copy from Mailcow admin)* |
|
||||||
|
|
||||||
|
### PTR Record (Reverse DNS)
|
||||||
|
Contact your ISP and request a PTR record:
|
||||||
|
- IP: `97.176.15.26`
|
||||||
|
- Points to: `mail.web.orbishosting.com`
|
||||||
|
|
||||||
|
This is critical for email deliverability. Without it, many servers will reject your mail.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Commands (run after DNS propagates)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check A record
|
||||||
|
dig mail.web.orbishosting.com A
|
||||||
|
|
||||||
|
# Check MX record
|
||||||
|
dig web.orbishosting.com MX
|
||||||
|
|
||||||
|
# Check SPF
|
||||||
|
dig web.orbishosting.com TXT
|
||||||
|
|
||||||
|
# Test mail score
|
||||||
|
# Visit: https://www.mail-tester.com and send a test email
|
||||||
|
```
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
# FortiGate Configuration Changes
|
||||||
|
|
||||||
|
FortiGate URL: https://10.48.200.1:9443
|
||||||
|
Login: admin / (your password)
|
||||||
|
|
||||||
|
**REVIEW BEFORE APPLYING. FusionPBX rules are NOT touched.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1 — Create Virtual IPs (VIPs)
|
||||||
|
|
||||||
|
Go to: **Policy & Objects → Virtual IPs → Create New → Virtual IP**
|
||||||
|
|
||||||
|
### VIP 1: NPM (Web Traffic)
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `VIP-NPM-HTTP` |
|
||||||
|
| Interface | WAN interface (the one with 97.176.15.26) |
|
||||||
|
| External IP | `97.176.15.26` |
|
||||||
|
| Mapped IP | `10.48.200.80` |
|
||||||
|
| Port Forwarding | Enabled |
|
||||||
|
| Protocol | TCP |
|
||||||
|
| External Port | `80` |
|
||||||
|
| Mapped Port | `80` |
|
||||||
|
|
||||||
|
### VIP 2: NPM (HTTPS)
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `VIP-NPM-HTTPS` |
|
||||||
|
| Interface | WAN interface |
|
||||||
|
| External IP | `97.176.15.26` |
|
||||||
|
| Mapped IP | `10.48.200.80` |
|
||||||
|
| Port Forwarding | Enabled |
|
||||||
|
| Protocol | TCP |
|
||||||
|
| External Port | `443` |
|
||||||
|
| Mapped Port | `443` |
|
||||||
|
|
||||||
|
### VIP 3: Mailcow SMTP (Port 25)
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `VIP-MAIL-SMTP` |
|
||||||
|
| Interface | WAN interface |
|
||||||
|
| External IP | `97.176.15.26` |
|
||||||
|
| Mapped IP | `10.48.200.82` |
|
||||||
|
| Port Forwarding | Enabled |
|
||||||
|
| Protocol | TCP |
|
||||||
|
| External Port | `25` |
|
||||||
|
| Mapped Port | `25` |
|
||||||
|
|
||||||
|
### VIP 4: Mailcow SMTPS (Port 465)
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `VIP-MAIL-SMTPS` |
|
||||||
|
| Interface | WAN interface |
|
||||||
|
| External IP | `97.176.15.26` |
|
||||||
|
| Mapped IP | `10.48.200.82` |
|
||||||
|
| Port Forwarding | Enabled |
|
||||||
|
| Protocol | TCP |
|
||||||
|
| External Port | `465` |
|
||||||
|
| Mapped Port | `465` |
|
||||||
|
|
||||||
|
### VIP 5: Mailcow Submission (Port 587)
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `VIP-MAIL-SUBMISSION` |
|
||||||
|
| Interface | WAN interface |
|
||||||
|
| External IP | `97.176.15.26` |
|
||||||
|
| Mapped IP | `10.48.200.82` |
|
||||||
|
| Port Forwarding | Enabled |
|
||||||
|
| Protocol | TCP |
|
||||||
|
| External Port | `587` |
|
||||||
|
| Mapped Port | `587` |
|
||||||
|
|
||||||
|
### VIP 6: Mailcow IMAP (Port 143)
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `VIP-MAIL-IMAP` |
|
||||||
|
| Interface | WAN interface |
|
||||||
|
| External IP | `97.176.15.26` |
|
||||||
|
| Mapped IP | `10.48.200.82` |
|
||||||
|
| Port Forwarding | Enabled |
|
||||||
|
| Protocol | TCP |
|
||||||
|
| External Port | `143` |
|
||||||
|
| Mapped Port | `143` |
|
||||||
|
|
||||||
|
### VIP 7: Mailcow IMAPS (Port 993)
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `VIP-MAIL-IMAPS` |
|
||||||
|
| Interface | WAN interface |
|
||||||
|
| External IP | `97.176.15.26` |
|
||||||
|
| Mapped IP | `10.48.200.82` |
|
||||||
|
| Port Forwarding | Enabled |
|
||||||
|
| Protocol | TCP |
|
||||||
|
| External Port | `993` |
|
||||||
|
| Mapped Port | `993` |
|
||||||
|
|
||||||
|
### VIP 8: Mailcow POP3 (Port 110) — Optional
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `VIP-MAIL-POP3` |
|
||||||
|
| Interface | WAN interface |
|
||||||
|
| External IP | `97.176.15.26` |
|
||||||
|
| Mapped IP | `10.48.200.82` |
|
||||||
|
| Port Forwarding | Enabled |
|
||||||
|
| Protocol | TCP |
|
||||||
|
| External Port | `110` |
|
||||||
|
| Mapped Port | `110` |
|
||||||
|
|
||||||
|
### VIP 9: Mailcow POP3S (Port 995) — Optional
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `VIP-MAIL-POP3S` |
|
||||||
|
| Interface | WAN interface |
|
||||||
|
| External IP | `97.176.15.26` |
|
||||||
|
| Mapped IP | `10.48.200.82` |
|
||||||
|
| Port Forwarding | Enabled |
|
||||||
|
| Protocol | TCP |
|
||||||
|
| External Port | `995` |
|
||||||
|
| Mapped Port | `995` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2 — Create Firewall Policies
|
||||||
|
|
||||||
|
Go to: **Policy & Objects → Firewall Policy → Create New**
|
||||||
|
|
||||||
|
### Policy 1: Allow Web Traffic to NPM
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `WAN-to-NPM-Web` |
|
||||||
|
| Incoming Interface | WAN |
|
||||||
|
| Outgoing Interface | LAN (internal) |
|
||||||
|
| Source | `all` |
|
||||||
|
| Destination | `VIP-NPM-HTTP`, `VIP-NPM-HTTPS` |
|
||||||
|
| Schedule | `always` |
|
||||||
|
| Service | `HTTP`, `HTTPS` |
|
||||||
|
| Action | `ACCEPT` |
|
||||||
|
| NAT | Enabled |
|
||||||
|
| Log | Enabled (recommended) |
|
||||||
|
|
||||||
|
### Policy 2: Allow Mail Traffic to Mailcow
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `WAN-to-Mailcow-Mail` |
|
||||||
|
| Incoming Interface | WAN |
|
||||||
|
| Outgoing Interface | LAN (internal) |
|
||||||
|
| Source | `all` |
|
||||||
|
| Destination | `VIP-MAIL-SMTP`, `VIP-MAIL-SMTPS`, `VIP-MAIL-SUBMISSION`, `VIP-MAIL-IMAP`, `VIP-MAIL-IMAPS` |
|
||||||
|
| Schedule | `always` |
|
||||||
|
| Service | Custom (ports 25, 465, 587, 143, 993) |
|
||||||
|
| Action | `ACCEPT` |
|
||||||
|
| NAT | Enabled |
|
||||||
|
| Log | Enabled |
|
||||||
|
|
||||||
|
> **NOTE:** If you also want POP3, add `VIP-MAIL-POP3` and `VIP-MAIL-POP3S` to Policy 2.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3 — Verify FusionPBX Rules Are Intact
|
||||||
|
|
||||||
|
After applying the above, confirm your existing SIP/RTP rules still exist:
|
||||||
|
- Port `5060` UDP/TCP → FusionPBX host
|
||||||
|
- Port `5061` UDP/TCP → FusionPBX host
|
||||||
|
- Ports `10000-20000` UDP → FusionPBX host (RTP)
|
||||||
|
|
||||||
|
Do NOT remove or modify these.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4 — (Optional) Block SMTP relay abuse
|
||||||
|
|
||||||
|
Add a firewall policy to prevent internal hosts from sending SMTP directly (forces use of Mailcow):
|
||||||
|
- Outgoing port 25 from LAN → blocked (except from 10.48.200.82)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
After applying:
|
||||||
|
```bash
|
||||||
|
# Test from external network or use mxtoolbox.com:
|
||||||
|
# https://mxtoolbox.com/SuperTool.aspx
|
||||||
|
|
||||||
|
# Test SMTP
|
||||||
|
telnet 97.176.15.26 25
|
||||||
|
|
||||||
|
# Test IMAP
|
||||||
|
telnet 97.176.15.26 143
|
||||||
|
|
||||||
|
# Test web
|
||||||
|
curl -I http://97.176.15.26
|
||||||
|
curl -Ik https://97.176.15.26
|
||||||
|
```
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
# Mailcow Post-Installation Steps
|
||||||
|
|
||||||
|
Access Mailcow admin: **https://mail.web.orbishosting.com**
|
||||||
|
Default login: `admin` / `moohoo`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1: Change Admin Password
|
||||||
|
|
||||||
|
**Configuration → Access → Administrator accounts → admin → Edit**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2: Add Your Domain
|
||||||
|
|
||||||
|
**Configuration → Mail Setup → Domains → Add domain**
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Domain | `web.orbishosting.com` |
|
||||||
|
| Description | Orbis Hosting Mail |
|
||||||
|
| Max. aliases | 400 |
|
||||||
|
| Max. mailboxes | 10 (adjust as needed) |
|
||||||
|
| Max. quota | 10240 MB |
|
||||||
|
| Default mailbox quota | 1024 MB |
|
||||||
|
| Active | On |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3: Create Mailboxes
|
||||||
|
|
||||||
|
**Configuration → Mail Setup → Mailboxes → Add mailbox**
|
||||||
|
|
||||||
|
Suggested mailboxes to create:
|
||||||
|
- `admin@web.orbishosting.com`
|
||||||
|
- `postmaster@web.orbishosting.com` (required for RFC compliance)
|
||||||
|
- `abuse@web.orbishosting.com` (required for RFC compliance)
|
||||||
|
- Your personal email address
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4: Get DKIM Key
|
||||||
|
|
||||||
|
**Configuration → Domains → web.orbishosting.com → DKIM**
|
||||||
|
|
||||||
|
Click **Generate** if no key exists, then copy the TXT record and add it to your DNS:
|
||||||
|
```
|
||||||
|
dkim._domainkey.web.orbishosting.com TXT "v=DKIM1; k=rsa; p=YOURKEY..."
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Verify Mail Configuration
|
||||||
|
|
||||||
|
**Configuration → Diagnostics** — Run all checks and ensure green on:
|
||||||
|
- DNS MX record
|
||||||
|
- SPF record
|
||||||
|
- DMARC record
|
||||||
|
- Reverse DNS (PTR)
|
||||||
|
- DKIM
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 6: Configure Mail Clients
|
||||||
|
|
||||||
|
Use these settings for Outlook, Thunderbird, Apple Mail, etc.:
|
||||||
|
|
||||||
|
### Incoming Mail (IMAP)
|
||||||
|
| Setting | Value |
|
||||||
|
|---------|-------|
|
||||||
|
| Server | `mail.web.orbishosting.com` |
|
||||||
|
| Port | `993` |
|
||||||
|
| Security | SSL/TLS |
|
||||||
|
| Username | full email address (e.g., user@web.orbishosting.com) |
|
||||||
|
|
||||||
|
### Outgoing Mail (SMTP)
|
||||||
|
| Setting | Value |
|
||||||
|
|---------|-------|
|
||||||
|
| Server | `mail.web.orbishosting.com` |
|
||||||
|
| Port | `587` |
|
||||||
|
| Security | STARTTLS |
|
||||||
|
| Authentication | Normal password |
|
||||||
|
| Username | full email address |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 7: Test Email Deliverability
|
||||||
|
|
||||||
|
1. Send a test email from your new mailbox to an external address (Gmail, Outlook)
|
||||||
|
2. Check spam score: https://www.mail-tester.com
|
||||||
|
3. Check blacklists: https://mxtoolbox.com/blacklists.aspx
|
||||||
|
|
||||||
|
**Target score:** 10/10 on mail-tester.com
|
||||||
|
|
||||||
|
Common issues if score is low:
|
||||||
|
- Missing PTR record → contact ISP
|
||||||
|
- Missing DKIM → check Step 4
|
||||||
|
- Missing DMARC → check dns-records.md
|
||||||
|
- On a residential ISP blacklist → consider a mail relay (SendGrid, Mailgun) for outbound
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mailcow Useful Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh ubuntu@10.48.200.82
|
||||||
|
cd /opt/mailcow-dockerized
|
||||||
|
|
||||||
|
# View all container status
|
||||||
|
sudo docker compose ps
|
||||||
|
|
||||||
|
# View logs for specific container
|
||||||
|
sudo docker compose logs -f postfix-mailcow
|
||||||
|
sudo docker compose logs -f dovecot-mailcow
|
||||||
|
sudo docker compose logs -f acme-mailcow
|
||||||
|
|
||||||
|
# Restart all Mailcow containers
|
||||||
|
sudo docker compose restart
|
||||||
|
|
||||||
|
# Update Mailcow
|
||||||
|
sudo docker compose pull
|
||||||
|
sudo docker compose up -d
|
||||||
|
|
||||||
|
# Update Mailcow (official method)
|
||||||
|
sudo ./update.sh
|
||||||
|
```
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Sync SSL certificates from NPM to Mailcow
|
||||||
|
# Run on the NPM VM (10.48.200.80) via cron after cert renewal
|
||||||
|
#
|
||||||
|
# Cron entry (on NPM VM): 0 3 * * * /opt/sync-certs.sh
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# 1. SSH key from NPM VM to Mailcow VM is set up (no password needed)
|
||||||
|
# Run on NPM VM: ssh-keygen -t ed25519 -f ~/.ssh/mailcow_sync
|
||||||
|
# Run on Mailcow VM: echo "<pub key>" >> ~/.ssh/authorized_keys
|
||||||
|
#
|
||||||
|
# 2. DOMAIN below matches the cert folder in NPM's letsencrypt directory
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DOMAIN="mail.web.orbishosting.com"
|
||||||
|
MAILCOW_HOST="10.48.200.82"
|
||||||
|
MAILCOW_USER="ubuntu"
|
||||||
|
MAILCOW_SSH_KEY="/root/.ssh/mailcow_sync"
|
||||||
|
|
||||||
|
NPM_CERT_DIR="/opt/npm/letsencrypt/live/${DOMAIN}"
|
||||||
|
MAILCOW_CERT_DIR="/opt/mailcow-dockerized/data/assets/ssl"
|
||||||
|
|
||||||
|
# Check if cert exists
|
||||||
|
if [ ! -f "${NPM_CERT_DIR}/fullchain.pem" ]; then
|
||||||
|
echo "ERROR: Certificate not found at ${NPM_CERT_DIR}"
|
||||||
|
echo "Make sure the NPM proxy host for ${DOMAIN} has an active SSL cert."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Syncing certs for ${DOMAIN} to Mailcow at ${MAILCOW_HOST}..."
|
||||||
|
|
||||||
|
# Copy certs to Mailcow
|
||||||
|
scp -i "${MAILCOW_SSH_KEY}" \
|
||||||
|
"${NPM_CERT_DIR}/fullchain.pem" \
|
||||||
|
"${MAILCOW_USER}@${MAILCOW_HOST}:${MAILCOW_CERT_DIR}/cert.pem"
|
||||||
|
|
||||||
|
scp -i "${MAILCOW_SSH_KEY}" \
|
||||||
|
"${NPM_CERT_DIR}/privkey.pem" \
|
||||||
|
"${MAILCOW_USER}@${MAILCOW_HOST}:${MAILCOW_CERT_DIR}/key.pem"
|
||||||
|
|
||||||
|
# Reload Mailcow services that use the cert
|
||||||
|
ssh -i "${MAILCOW_SSH_KEY}" "${MAILCOW_USER}@${MAILCOW_HOST}" \
|
||||||
|
"cd /opt/mailcow-dockerized && sudo docker compose restart postfix-mailcow dovecot-mailcow nginx-mailcow"
|
||||||
|
|
||||||
|
echo "Done. Certs synced and Mailcow services restarted."
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
# Nginx Proxy Manager — Proxy Host Configuration
|
||||||
|
|
||||||
|
After NPM is running, configure it via the web UI at **http://10.48.200.80:81**
|
||||||
|
|
||||||
|
Default login: `admin@example.com` / `changeme` — **change immediately**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Proxy Host 1: Mailcow Web UI (HTTPS)
|
||||||
|
|
||||||
|
Go to: **Hosts → Proxy Hosts → Add Proxy Host**
|
||||||
|
|
||||||
|
### Details Tab
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Domain Names | `mail.web.orbishosting.com` |
|
||||||
|
| Scheme | `http` |
|
||||||
|
| Forward Hostname / IP | `10.48.200.82` |
|
||||||
|
| Forward Port | `8080` |
|
||||||
|
| Cache Assets | Off |
|
||||||
|
| Block Common Exploits | On |
|
||||||
|
| Websockets Support | **On** (required for Mailcow) |
|
||||||
|
|
||||||
|
### SSL Tab
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| SSL Certificate | Request a new SSL Certificate |
|
||||||
|
| Force SSL | On |
|
||||||
|
| HTTP/2 Support | On |
|
||||||
|
| HSTS Enabled | On |
|
||||||
|
| Let's Encrypt Email | postmaster@web.orbishosting.com |
|
||||||
|
| I Agree to ToS | Checked |
|
||||||
|
|
||||||
|
Click **Save** — NPM will automatically get a Let's Encrypt certificate.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Proxy Host 2: NPM Admin UI (Optional — for remote management)
|
||||||
|
|
||||||
|
If you want to access the NPM admin panel via your domain:
|
||||||
|
|
||||||
|
### Details Tab
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Domain Names | `npm.web.orbishosting.com` |
|
||||||
|
| Scheme | `http` |
|
||||||
|
| Forward Hostname / IP | `127.0.0.1` |
|
||||||
|
| Forward Port | `81` |
|
||||||
|
| Block Common Exploits | On |
|
||||||
|
|
||||||
|
### SSL Tab
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| SSL Certificate | Request a new SSL Certificate |
|
||||||
|
| Force SSL | On |
|
||||||
|
| Let's Encrypt Email | postmaster@web.orbishosting.com |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Proxy Host 3: Redirect www → root domain (Optional)
|
||||||
|
|
||||||
|
### Details Tab
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Domain Names | `www.web.orbishosting.com` |
|
||||||
|
| Scheme | `https` |
|
||||||
|
| Forward Hostname / IP | `web.orbishosting.com` |
|
||||||
|
| Forward Port | `443` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Enable Mailcow's Own ACME (for mail protocol SSL)
|
||||||
|
|
||||||
|
After NPM proxy is working for `mail.web.orbishosting.com`, SSH into the Mailcow VM and enable its own Let's Encrypt:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh ubuntu@10.48.200.82
|
||||||
|
|
||||||
|
# Edit mailcow.conf
|
||||||
|
sudo nano /opt/mailcow-dockerized/mailcow.conf
|
||||||
|
|
||||||
|
# Ensure these settings:
|
||||||
|
# SKIP_LETS_ENCRYPT=n ← Mailcow will get its own cert via HTTP challenge
|
||||||
|
# HTTP_PORT=8080 ← NPM forwards port 80 → this port
|
||||||
|
# HTTPS_PORT=8443
|
||||||
|
# HTTPS_BIND=127.0.0.1
|
||||||
|
|
||||||
|
# Restart acme container
|
||||||
|
cd /opt/mailcow-dockerized
|
||||||
|
sudo docker compose restart acme-mailcow
|
||||||
|
|
||||||
|
# Watch the ACME container get the cert
|
||||||
|
sudo docker compose logs -f acme-mailcow
|
||||||
|
```
|
||||||
|
|
||||||
|
The ACME challenge goes:
|
||||||
|
`Let's Encrypt → port 80 → FortiGate → NPM → port 8080 on Mailcow → acme responds`
|
||||||
|
|
||||||
|
Once Mailcow's ACME succeeds, it will automatically use that cert for Postfix/Dovecot.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verify Everything Works
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From outside your network or use mxtoolbox.com:
|
||||||
|
|
||||||
|
# Test HTTPS web UI
|
||||||
|
curl -I https://mail.web.orbishosting.com
|
||||||
|
|
||||||
|
# Test SMTP banner
|
||||||
|
telnet 97.176.15.26 25
|
||||||
|
|
||||||
|
# Test IMAP
|
||||||
|
openssl s_client -connect 97.176.15.26:993
|
||||||
|
|
||||||
|
# Test SMTP with TLS
|
||||||
|
openssl s_client -starttls smtp -connect 97.176.15.26:587
|
||||||
|
```
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Complete NPM VM 200 setup
|
||||||
|
# The cloud image disk was already imported as unused0 during initial VM creation.
|
||||||
|
# This script attaches the disk, configures cloud-init, resizes, and starts the VM.
|
||||||
|
#
|
||||||
|
# Run on Proxmox host: bash proxmox/01-complete-npm-vm.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VMID=200
|
||||||
|
VMNAME="NginxProxyManager"
|
||||||
|
IP="10.48.200.80"
|
||||||
|
GW="10.48.200.1"
|
||||||
|
DNS="8.8.8.8,1.1.1.1"
|
||||||
|
DISK_SIZE="20G"
|
||||||
|
SNIPPETS_DIR="/var/lib/vz/snippets"
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
echo "=== Configuring VM ${VMID}: ${VMNAME} ==="
|
||||||
|
|
||||||
|
# Attach the imported disk as scsi0
|
||||||
|
echo "[1/7] Attaching disk..."
|
||||||
|
qm set ${VMID} --scsi0 local-lvm:vm-${VMID}-disk-0,discard=on,ssd=1
|
||||||
|
|
||||||
|
# Add cloud-init CD-ROM drive
|
||||||
|
echo "[2/7] Adding cloud-init drive..."
|
||||||
|
qm set ${VMID} --ide2 local-lvm:cloudinit
|
||||||
|
|
||||||
|
# Set boot order
|
||||||
|
echo "[3/7] Setting boot order..."
|
||||||
|
qm set ${VMID} --boot order=scsi0
|
||||||
|
|
||||||
|
# Upload cloud-init snippet
|
||||||
|
echo "[4/7] Uploading cloud-init snippet..."
|
||||||
|
mkdir -p ${SNIPPETS_DIR}
|
||||||
|
cp "${SCRIPT_DIR}/snippets/npm-cloud-init.yaml" "${SNIPPETS_DIR}/npm-cloud-init.yaml"
|
||||||
|
|
||||||
|
# Configure cloud-init parameters
|
||||||
|
echo "[5/7] Configuring cloud-init..."
|
||||||
|
qm set ${VMID} \
|
||||||
|
--ciuser ubuntu \
|
||||||
|
--cipassword 'mailstack2024!' \
|
||||||
|
--ipconfig0 ip=${IP}/24,gw=${GW} \
|
||||||
|
--nameserver "${DNS}" \
|
||||||
|
--searchdomain web.orbishosting.com \
|
||||||
|
--cicustom "vendor=local:snippets/npm-cloud-init.yaml"
|
||||||
|
|
||||||
|
# Resize disk
|
||||||
|
echo "[6/7] Resizing disk to ${DISK_SIZE}..."
|
||||||
|
qm resize ${VMID} scsi0 ${DISK_SIZE}
|
||||||
|
|
||||||
|
# Start VM
|
||||||
|
echo "[7/7] Starting VM ${VMID}..."
|
||||||
|
qm start ${VMID}
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== VM ${VMID} started ==="
|
||||||
|
echo "IP: ${IP}"
|
||||||
|
echo "SSH: ssh ubuntu@${IP} (password: mailstack2024!)"
|
||||||
|
echo "NPM Admin UI: http://${IP}:81"
|
||||||
|
echo ""
|
||||||
|
echo "Cloud-init will run for ~3-5 minutes to install Docker and start NPM."
|
||||||
|
echo "Monitor with: ssh ubuntu@${IP} 'sudo tail -f /var/log/cloud-init-output.log'"
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Create and configure Mailcow VM 201
|
||||||
|
# Run on Proxmox host: bash proxmox/02-create-mailcow-vm.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VMID=201
|
||||||
|
VMNAME="Mailcow"
|
||||||
|
IP="10.48.200.82"
|
||||||
|
GW="10.48.200.1"
|
||||||
|
DNS="8.8.8.8,1.1.1.1"
|
||||||
|
DISK_SIZE="80G"
|
||||||
|
RAM=8192
|
||||||
|
CORES=4
|
||||||
|
CLOUD_IMAGE="/var/lib/vz/template/iso/noble-server-cloudimg-amd64.img"
|
||||||
|
SNIPPETS_DIR="/var/lib/vz/snippets"
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
echo "=== Creating VM ${VMID}: ${VMNAME} ==="
|
||||||
|
|
||||||
|
# Create VM
|
||||||
|
echo "[1/8] Creating VM..."
|
||||||
|
qm create ${VMID} \
|
||||||
|
--name "${VMNAME}" \
|
||||||
|
--memory ${RAM} \
|
||||||
|
--cores ${CORES} \
|
||||||
|
--sockets 1 \
|
||||||
|
--cpu x86-64-v2-AES \
|
||||||
|
--net0 virtio,bridge=vmbr0 \
|
||||||
|
--ostype l26 \
|
||||||
|
--scsihw virtio-scsi-pci \
|
||||||
|
--boot order=scsi0 \
|
||||||
|
--serial0 socket \
|
||||||
|
--vga serial0 \
|
||||||
|
--agent enabled=1 \
|
||||||
|
--onboot 1 \
|
||||||
|
--description "Mailcow Email Server - mail.web.orbishosting.com"
|
||||||
|
|
||||||
|
# Import cloud image
|
||||||
|
echo "[2/8] Importing cloud image (this takes ~2 minutes)..."
|
||||||
|
qm importdisk ${VMID} "${CLOUD_IMAGE}" local-lvm --format raw
|
||||||
|
|
||||||
|
# Attach disk
|
||||||
|
echo "[3/8] Attaching disk..."
|
||||||
|
qm set ${VMID} --scsi0 local-lvm:vm-${VMID}-disk-0,discard=on,ssd=1
|
||||||
|
|
||||||
|
# Add cloud-init CD-ROM
|
||||||
|
echo "[4/8] Adding cloud-init drive..."
|
||||||
|
qm set ${VMID} --ide2 local-lvm:cloudinit
|
||||||
|
|
||||||
|
# Upload cloud-init snippet
|
||||||
|
echo "[5/8] Uploading cloud-init snippet..."
|
||||||
|
mkdir -p ${SNIPPETS_DIR}
|
||||||
|
cp "${SCRIPT_DIR}/snippets/mailcow-cloud-init.yaml" "${SNIPPETS_DIR}/mailcow-cloud-init.yaml"
|
||||||
|
|
||||||
|
# Configure cloud-init
|
||||||
|
echo "[6/8] Configuring cloud-init..."
|
||||||
|
qm set ${VMID} \
|
||||||
|
--ciuser ubuntu \
|
||||||
|
--cipassword 'mailstack2024!' \
|
||||||
|
--ipconfig0 ip=${IP}/24,gw=${GW} \
|
||||||
|
--nameserver "${DNS}" \
|
||||||
|
--searchdomain web.orbishosting.com \
|
||||||
|
--cicustom "vendor=local:snippets/mailcow-cloud-init.yaml"
|
||||||
|
|
||||||
|
# Resize disk
|
||||||
|
echo "[7/8] Resizing disk to ${DISK_SIZE}..."
|
||||||
|
qm resize ${VMID} scsi0 ${DISK_SIZE}
|
||||||
|
|
||||||
|
# Start VM
|
||||||
|
echo "[8/8] Starting VM ${VMID}..."
|
||||||
|
qm start ${VMID}
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== VM ${VMID} started ==="
|
||||||
|
echo "IP: ${IP}"
|
||||||
|
echo "SSH: ssh ubuntu@${IP} (password: mailstack2024!)"
|
||||||
|
echo "Mailcow Web: http://${IP}:8080 (internal only until NPM proxy is set up)"
|
||||||
|
echo ""
|
||||||
|
echo "Mailcow cloud-init takes ~10-15 minutes (Docker pull + image downloads)."
|
||||||
|
echo "Monitor with: ssh ubuntu@${IP} 'sudo tail -f /var/log/cloud-init-output.log'"
|
||||||
|
echo ""
|
||||||
|
echo "NEXT: Configure NPM proxy hosts — see nginx-proxy-manager/ directory."
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#cloud-config
|
||||||
|
# Mailcow VM - Ubuntu 24.04
|
||||||
|
# VM 201 | IP: 10.48.200.82
|
||||||
|
# Hostname: mail.web.orbishosting.com
|
||||||
|
|
||||||
|
package_update: true
|
||||||
|
package_upgrade: true
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- curl
|
||||||
|
- ca-certificates
|
||||||
|
- git
|
||||||
|
- htop
|
||||||
|
- net-tools
|
||||||
|
- nftables
|
||||||
|
- qemu-guest-agent
|
||||||
|
|
||||||
|
runcmd:
|
||||||
|
# Enable and start qemu-guest-agent
|
||||||
|
- systemctl enable qemu-guest-agent
|
||||||
|
- systemctl start qemu-guest-agent
|
||||||
|
|
||||||
|
# Set hostname (Mailcow requires this to match MAILCOW_HOSTNAME)
|
||||||
|
- hostnamectl set-hostname mail.web.orbishosting.com
|
||||||
|
- echo "127.0.0.1 mail.web.orbishosting.com mail" >> /etc/hosts
|
||||||
|
|
||||||
|
# Install Docker
|
||||||
|
- curl -fsSL https://get.docker.com | sh
|
||||||
|
- systemctl enable docker
|
||||||
|
- usermod -aG docker ubuntu
|
||||||
|
|
||||||
|
# Install Mailcow
|
||||||
|
- git clone https://github.com/mailcow/mailcow-dockerized /opt/mailcow-dockerized
|
||||||
|
|
||||||
|
# Generate Mailcow config non-interactively
|
||||||
|
- |
|
||||||
|
cd /opt/mailcow-dockerized
|
||||||
|
MAILCOW_HOSTNAME=mail.web.orbishosting.com \
|
||||||
|
MAILCOW_TZ=America/New_York \
|
||||||
|
./generate_config.sh
|
||||||
|
|
||||||
|
# Configure Mailcow to run behind NPM reverse proxy
|
||||||
|
# HTTP on 8080 (proxied by NPM), HTTPS bound only to localhost
|
||||||
|
- |
|
||||||
|
sed -i 's/^HTTP_PORT=.*/HTTP_PORT=8080/' /opt/mailcow-dockerized/mailcow.conf
|
||||||
|
sed -i 's/^HTTP_BIND=.*/HTTP_BIND=0.0.0.0/' /opt/mailcow-dockerized/mailcow.conf
|
||||||
|
sed -i 's/^HTTPS_PORT=.*/HTTPS_PORT=8443/' /opt/mailcow-dockerized/mailcow.conf
|
||||||
|
sed -i 's/^HTTPS_BIND=.*/HTTPS_BIND=127.0.0.1/' /opt/mailcow-dockerized/mailcow.conf
|
||||||
|
|
||||||
|
# Pull images and start Mailcow
|
||||||
|
- cd /opt/mailcow-dockerized && docker compose pull
|
||||||
|
- cd /opt/mailcow-dockerized && docker compose up -d
|
||||||
|
|
||||||
|
# Add Mailcow startup service
|
||||||
|
- |
|
||||||
|
cat > /etc/systemd/system/mailcow.service << 'SERVICE'
|
||||||
|
[Unit]
|
||||||
|
Description=Mailcow Email Server
|
||||||
|
After=docker.service
|
||||||
|
Requires=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
WorkingDirectory=/opt/mailcow-dockerized
|
||||||
|
ExecStart=/usr/bin/docker compose up -d
|
||||||
|
ExecStop=/usr/bin/docker compose down
|
||||||
|
TimeoutStartSec=0
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
SERVICE
|
||||||
|
|
||||||
|
- systemctl enable mailcow.service
|
||||||
|
|
||||||
|
final_message: |
|
||||||
|
Mailcow VM is ready.
|
||||||
|
Web UI accessible internally at: http://10.48.200.82:8080
|
||||||
|
Default admin: admin / moohoo
|
||||||
|
CHANGE THE PASSWORD IMMEDIATELY after DNS and NPM proxy are configured.
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#cloud-config
|
||||||
|
# Nginx Proxy Manager VM - Ubuntu 24.04
|
||||||
|
# VM 200 | IP: 10.48.200.80
|
||||||
|
|
||||||
|
package_update: true
|
||||||
|
package_upgrade: true
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- curl
|
||||||
|
- ca-certificates
|
||||||
|
- git
|
||||||
|
- htop
|
||||||
|
- net-tools
|
||||||
|
- qemu-guest-agent
|
||||||
|
|
||||||
|
runcmd:
|
||||||
|
# Enable and start qemu-guest-agent
|
||||||
|
- systemctl enable qemu-guest-agent
|
||||||
|
- systemctl start qemu-guest-agent
|
||||||
|
|
||||||
|
# Install Docker
|
||||||
|
- curl -fsSL https://get.docker.com | sh
|
||||||
|
- systemctl enable docker
|
||||||
|
- usermod -aG docker ubuntu
|
||||||
|
|
||||||
|
# Create NPM directory
|
||||||
|
- mkdir -p /opt/npm/data /opt/npm/letsencrypt
|
||||||
|
|
||||||
|
# Write docker-compose.yml
|
||||||
|
- |
|
||||||
|
cat > /opt/npm/docker-compose.yml << 'COMPOSE'
|
||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
npm:
|
||||||
|
image: jc21/nginx-proxy-manager:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "81:81"
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./letsencrypt:/etc/letsencrypt
|
||||||
|
environment:
|
||||||
|
DISABLE_IPV6: "true"
|
||||||
|
COMPOSE
|
||||||
|
|
||||||
|
# Start NPM
|
||||||
|
- cd /opt/npm && docker compose up -d
|
||||||
|
|
||||||
|
# Add compose startup on boot
|
||||||
|
- |
|
||||||
|
cat > /etc/systemd/system/npm.service << 'SERVICE'
|
||||||
|
[Unit]
|
||||||
|
Description=Nginx Proxy Manager
|
||||||
|
After=docker.service
|
||||||
|
Requires=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
WorkingDirectory=/opt/npm
|
||||||
|
ExecStart=/usr/bin/docker compose up -d
|
||||||
|
ExecStop=/usr/bin/docker compose down
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
SERVICE
|
||||||
|
|
||||||
|
- systemctl enable npm.service
|
||||||
|
|
||||||
|
final_message: |
|
||||||
|
NPM VM is ready.
|
||||||
|
Admin UI: http://10.48.200.80:81
|
||||||
|
Default login: admin@example.com / changeme
|
||||||
|
CHANGE THE PASSWORD IMMEDIATELY.
|
||||||
Reference in New Issue
Block a user