Tujuan panduan ini: dari Proxmox kosong menjadi mesin virtual Ubuntu 24 yang langsung menjalankan n8n dengan HTTPS, database Postgres, dan Caddy sebagai reverse proxy (ACME otomatis). Di akhir, Anda mengimpor workflow contoh untuk memeriksa email Gmail.
Prasyarat
- Proxmox VE dapat diakses (Web UI & SSH) dengan hak
root. - Storage tersedia (mis.
local-lvmuntuk disk VM,localuntuk berkas/snippets). - Jembatan jaringan (mis.
vmbr0) yang terhubung ke internet publik. - Domain untuk n8n (mis.
automasi.example.com). - SSH key publik untuk Cloud-Init (disarankan).
Penting: Arahkan DNS ke Server Ini
Auntukautomasi.example.com→IP_PUBLIK_VM- (Opsional IPv6)
AAAA→IPv6_VM
Lakukan sebelum atau sesudah pembuatan VM; Caddy akan mengeluarkan sertifikat ketika domain sudah mengarah benar.
Skrip Proxmox: Buat VM Ubuntu 24 + Cloud-Init n8n
Skrip berikut akan: mengunduh image Ubuntu 24 cloud, membuat VM, paket Cloud-Init untuk Docker + n8n + Postgres + Caddy, membuka port 80/443, lalu menyalakan VM. Silakan sesuaikan variabel di bagian atas.
/root/proxmox-n8n-vm.sh#!/usr/bin/env bash
# File: /root/proxmox-n8n-vm.sh
# Purpose: Membuat VM Ubuntu 24 untuk n8n (Docker + Postgres + Caddy/HTTPS) via Cloud-Init
set -euo pipefail
# ====== PARAMETER (SESUAIKAN) ======
VMID="${VMID:-9100}"
VM_NAME="${VM_NAME:-n8n-ubuntu24}"
STORAGE="${STORAGE:-local-lvm}"
BRIDGE="${BRIDGE:-vmbr0}"
CPU_CORES="${CPU_CORES:-2}"
RAM_MB="${RAM_MB:-4096}"
DISK_GB="${DISK_GB:-20}"
# Jaringan (pilih salah satu: dhcp / static)
IPCFG_MODE="${IPCFG_MODE:-dhcp}" # dhcp | static
IPADDR="${IPADDR:-10.10.150.215/24}" # jika static
GATEWAY="${GATEWAY:-10.10.150.1}" # jika static
VLAN_TAG="${VLAN_TAG:-}" # kosongkan jika tidak pakai VLAN
# Cloud-Init user
CI_USER="${CI_USER:-ubuntu}"
CI_SSH_KEY="${CI_SSH_KEY:-}" # isi kunci SSH publik Anda (ssh-ed25519/ssh-rsa)
HOSTNAME="${HOSTNAME:-n8n-vm}"
NAMESERVER="${NAMESERVER:-1.1.1.1}"
SEARCHDOMAIN="${SEARCHDOMAIN:-example.local}"
# n8n + domain + kredensial dasar
N8N_DOMAIN="${N8N_DOMAIN:-automasi.example.com}"
N8N_BASIC_AUTH_USER="${N8N_BASIC_AUTH_USER:-admin}"
N8N_BASIC_AUTH_PASSWORD="${N8N_BASIC_AUTH_PASSWORD:-ganti_password_n8n}"
POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-ganti_password_postgres}"
TIMEZONE="${TIMEZONE:-Asia/Jakarta}"
# ===================================
WORKDIR=/tmp
IMG="$WORKDIR/ubuntu-24.04-noble-amd64-cloudimg.img"
IMG_URL="https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
echo "[INFO] Mengunduh image Ubuntu 24 (noble)..."
mkdir -p "$WORKDIR"
if [ ! -f "$IMG" ]; then
wget -O "$IMG" "$IMG_URL"
fi
echo "[INFO] Membuat VM $VMID ($VM_NAME)..."
qm create "$VMID" --name "$VM_NAME" --memory "$RAM_MB" --cores "$CPU_CORES" --ostype l26
NETOPTS="virtio,bridge=$BRIDGE"
if [ -n "$VLAN_TAG" ]; then NETOPTS="$NETOPTS,tag=$VLAN_TAG"; fi
qm set "$VMID" --net0 "$NETOPTS"
echo "[INFO] Impor disk ke $STORAGE..."
qm importdisk "$VMID" "$IMG" "$STORAGE"
echo "[INFO] Set disk, boot, agent, cloud-init..."
qm set "$VMID" --scsihw virtio-scsi-pci --scsi0 "$STORAGE:vm-$VMID-disk-0"
qm set "$VMID" --boot order=scsi0 --serial0 socket --vga serial0
qm set "$VMID" --agent enabled=1
qm set "$VMID" --ide2 "$STORAGE:cloudinit"
echo "[INFO] Resize disk root menjadi ${DISK_GB}G..."
qm disk resize "$VMID" scsi0 "${DISK_GB}G"
echo "[INFO] Konfigurasi Cloud-Init (user, ssh, dns, hostname)..."
if [ -n "$CI_SSH_KEY" ]; then
qm set "$VMID" --ciuser "$CI_USER" --sshkey <(echo "$CI_SSH_KEY")
else
qm set "$VMID" --ciuser "$CI_USER"
fi
qm set "$VMID" --nameserver "$NAMESERVER" --searchdomain "$SEARCHDOMAIN"
qm set "$VMID" --hostname "$HOSTNAME"
echo "[INFO] Konfigurasi jaringan VM..."
if [ "$IPCFG_MODE" = "dhcp" ]; then
qm set "$VMID" --ipconfig0 ip=dhcp
else
qm set "$VMID" --ipconfig0 ip="$IPADDR",gw="$GATEWAY"
fi
echo "[INFO] Menulis user-data Cloud-Init untuk n8n..."
mkdir -p /var/lib/vz/snippets
cat > /var/lib/vz/snippets/n8n-userdata.yaml <<YAML
#cloud-config
timezone: "$TIMEZONE"
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
- ufw
- docker.io
- docker-compose-plugin
write_files:
- path: /opt/n8n/docker-compose.yml
owner: root:root
permissions: "0644"
content: |
version: "3.8"
services:
postgres:
image: postgres:15
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: n8n
volumes:
- pg_data:/var/lib/postgresql/data
restart: unless-stopped
n8n:
image: docker.io/n8nio/n8n:latest
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
DB_POSTGRESDB_DATABASE: n8n
GENERIC_TIMEZONE: "$TIMEZONE"
N8N_HOST: ${N8N_DOMAIN}
N8N_PORT: 5678
N8N_PROTOCOL: https
N8N_WEBHOOK_URL: https://${N8N_DOMAIN}/
N8N_BASIC_AUTH_ACTIVE: "true"
N8N_BASIC_AUTH_USER: ${N8N_BASIC_AUTH_USER}
N8N_BASIC_AUTH_PASSWORD: ${N8N_BASIC_AUTH_PASSWORD}
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
restart: unless-stopped
caddy:
image: caddy:2-alpine
ports:
- "80:80"
- "443:443"
volumes:
- caddy_data:/data
- caddy_config:/config
- /opt/n8n/Caddyfile:/etc/caddy/Caddyfile:ro
depends_on:
- n8n
restart: unless-stopped
volumes:
pg_data:
n8n_data:
caddy_data:
caddy_config:
- path: /opt/n8n/Caddyfile
owner: root:root
permissions: "0644"
content: |
${N8N_DOMAIN} {
encode gzip
reverse_proxy n8n:5678
}
runcmd:
- [ ufw, allow, "80/tcp" ]
- [ ufw, allow, "443/tcp" ]
- [ ufw, allow, "OpenSSH" ]
- [ systemctl, enable, --now, qemu-guest-agent ]
- [ bash, -lc, "mkdir -p /opt/n8n && cd /opt/n8n && docker compose up -d" ]
YAML
qm set "$VMID" --cicustom "user=local:snippets/n8n-userdata.yaml"
echo "[INFO] Menyalakan VM..."
qm start "$VMID"
echo "[SELESAI] VM n8n dibuat. Arahkan DNS ke IP VM dan tunggu sertifikat otomatis oleh Caddy."
echo "Akses: https://${N8N_DOMAIN} (Basic Auth aktif)"
Cara Menjalankan Skrip Proxmox
- Masuk SSH ke node Proxmox, buat file skrip, beri izin eksekusi:
ssh root@IP_NODE_PROXMOX
nano /root/proxmox-n8n-vm.sh # tempel isi skrip di atas
chmod +x /root/proxmox-n8n-vm.sh- Jalankan dengan variabel yang Anda inginkan (contoh static IP pada jaringan 10.10.150.0/24):
export VMID=9100 VM_NAME=n8n-ubuntu24 STORAGE=local-lvm BRIDGE=vmbr0
export CPU_CORES=2 RAM_MB=4096 DISK_GB=30
export IPCFG_MODE=static IPADDR=10.10.150.215/24 GATEWAY=10.10.150.1
export CI_USER=ubuntu CI_SSH_KEY="$(cat ~/.ssh/id_ed25519.pub)"
export HOSTNAME=n8n-vm NAMESERVER=1.1.1.1 SEARCHDOMAIN=karangturi.or.id
export N8N_DOMAIN=automasi.karangturi.or.id
export N8N_BASIC_AUTH_USER=admin N8N_BASIC_AUTH_PASSWORD='GantiPasswordN8N!'
export POSTGRES_PASSWORD='GantiPasswordPostgres!' TIMEZONE=Asia/Jakarta
/root/proxmox-n8n-vm.shApa yang Terpasang di VM
- Docker & Docker Compose plugin
- n8n (container) + Postgres 15 (persistent volume)
- Caddy (reverse proxy) — menerbitkan sertifikat Let’s Encrypt otomatis untuk
N8N_DOMAIN - UFW membuka port 80/443
- Basic Auth untuk n8n (user/password dari variabel N8N_BASIC_AUTH_*)
Sample Workflow n8n: Cek Gmail (IMAP + App Password)
Contoh berikut memakai node IMAP Email (Trigger) untuk membaca email baru dari Gmail. Karena Google tidak mengizinkan “less secure apps”, buat App Password (Google Account → Security → 2-Step Verification → App passwords) untuk akun Gmail Anda, lalu buat IMAP Credentials di n8n:
- n8n → Credentials → New → IMAP
- Name:
gmail-imap - User:
alamat@gmail.com - Password:
APP_PASSWORD_16_KARAKTER - Host:
imap.gmail.com, Port:993, SSL/TLS: aktif
- Name:
- Impor workflow JSON di bawah ini (n8n → Import from file / clipboard).
Gmail IMAP (UNSEEN → log parsial){
"name": "Gmail IMAP Check (UNSEEN → Parse & Log)",
"nodes": [
{
"parameters": {
"mailbox": "INBOX",
"download": false,
"options": {
"criteria": "UNSEEN",
"markAsSeen": true
}
},
"id": "imap1",
"name": "IMAP Gmail (App Password)",
"type": "n8n-nodes-base.imapEmail",
"typeVersion": 1,
"position": [ 260, 300 ],
"credentials": {
"imap": { "name": "gmail-imap" }
}
},
{
"parameters": {
"functionCode": "return items.map(item => ({ json: { from: item.json.from, subject: item.json.subject, date: item.json.date, snippet: (item.json.text || '').slice(0, 200) } }));"
},
"id": "fn1",
"name": "Parse & Log",
"type": "n8n-nodes-base.function",
"typeVersion": 2,
"position": [ 560, 300 ]
}
],
"connections": {
"IMAP Gmail (App Password)": {
"main": [
[ { "node": "Parse & Log", "type": "main", "index": 0 } ]
]
}
}
}Hasil: setiap email baru yang belum dibaca (UNSEEN) akan diparsing (from, subject, date, snippet). Anda bisa menambahkan node “Send Email” untuk meneruskan ringkasan, atau “IF” untuk filter subjek tertentu.
Verifikasi & Uji Cepat
# Di dalam VM (SSH)
sudo systemctl status qemu-guest-agent
docker ps
# Cek log n8n:
docker logs -f $(docker ps --format '{{.Names}}' | grep n8n)# Uji DNS mengarah ke IP VM:
dig +short A automasi.example.com
# Buka https://automasi.example.com lalu login Basic Auth n8nTroubleshooting Ringkas
- HTTPS gagal terbit → Pastikan DNS A/AAAA untuk
N8N_DOMAINmengarah tepat ke IP VM; tunggu propagasi (TTL). Cek log Caddy:docker logs -f $(docker ps --format '{{.Names}}' | grep caddy) - n8n tidak start → Cek log container dan Postgres:
docker logs -f $(docker ps --format '{{.Names}}' | grep n8n) docker logs -f $(docker ps --format '{{.Names}}' | grep postgres) - IMAP Gmail gagal autentikasi → Aktifkan 2FA di akun Google, buat App Password baru, pakai di kredensial IMAP n8n. Host:
imap.gmail.com, Port:993, TLS aktif. - Port bentrok → Pastikan VM mendapat IP publik/jembatan yang benar; jika ada reverse proxy eksternal, sesuaikan expose/ports di Docker Compose.
Kesimpulan
Dengan skrip Proxmox + Cloud-Init ini, Anda memperoleh VM Ubuntu 24 yang langsung siap melayani n8n ber-HTTPS (Caddy/ACME otomatis), database Postgres persisten, dan contoh workflow cek Gmail. Kunci keberhasilan ada pada penataan DNS yang tepat dan kredensial IMAP Gmail (App Password). Selanjutnya, Anda tinggal mengembangkan alur-alur n8n sesuai proses bisnis.

