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
|
||||
Proxmox and Mailcow Configuration
|
||||
# ProxMailcow — Proxmox + Nginx Proxy Manager + Mailcow
|
||||
|
||||
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