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:
2026-04-23 04:37:56 +00:00
parent ca6fd7688e
commit b60db8a0d0
10 changed files with 917 additions and 2 deletions
+62 -2
View File
@@ -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)
+68
View File
@@ -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
```
+194
View File
@@ -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
```
+126
View File
@@ -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
```
+46
View File
@@ -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."
+119
View File
@@ -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
```
+63
View File
@@ -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'"
+83
View File
@@ -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."
+80
View File
@@ -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.
+76
View File
@@ -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.