Membangun VM n8n di Proxmox (Ubuntu 24) + Contoh Workflow Cek Gmail

Panduan lengkap untuk membuat VM Ubuntu 24 di Proxmox dengan Cloud-Init yang otomatis memasang Docker dan men-deploy n8n (beserta Postgres dan Caddy untuk HTTPS otomatis). Disertai skrip siap salin-tempel dan satu contoh workflow n8n untuk memeriksa email Gmail.

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.

Opini singkat: Otomasi yang baik itu seperti kopi yang pas—menghemat waktu dan menjaga fokus pada hal yang penting: alur otomasi Anda.

Prasyarat

  • Proxmox VE dapat diakses (Web UI & SSH) dengan hak root.
  • Storage tersedia (mis. local-lvm untuk disk VM, local untuk 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

Wajib untuk HTTPS otomatis: Buat record DNS pada penyedia Anda (Cloudflare/Route53/dll):
  • A untuk automasi.example.comIP_PUBLIK_VM
  • (Opsional IPv6) AAAAIPv6_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.

File yang direkomendasikan: /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

  1. 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
  1. 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.sh

Apa 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:

  1. 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
  2. Impor workflow JSON di bawah ini (n8n → Import from file / clipboard).
Workflow JSON: 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 n8n

Troubleshooting Ringkas

  • HTTPS gagal terbit → Pastikan DNS A/AAAA untuk N8N_DOMAIN mengarah 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.

Sumber/Referensi


Share the Post:

Related Posts