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
+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.