Gate: new and expendable, or recoverable before rebuilding
Use this guide for a blank supported Ubuntu Cloud Compute, or a supported Docker host you have already inventoried. Other image paths reuse only their own documented OS, access and service behavior. If an existing VPS carries data you care about, do not use a different image or snapshot as a shortcut to “fix” it: complete control writes → final export → exact-cutoff restore first.
Write these prerequisites into a private procurement record: desired workload, regular/dedicated CPU hypothesis, RAM/disk measurement, exact plan code and region, hostname, IPv4/IPv6 requirement, domain/DNS ownership, backup destination and approved cash budget. Prepare an SSH key and a password manager, and verify you can reach Vultr’s web console for host-level recovery. The reader performs the purchase and server creation; an API key is optional, not a prerequisite for using the console.
# On your own workstation, generate a dedicated key if you do not have one.
# Save the private key in your password manager; upload only the public half.
ssh-keygen -t ed25519 -a 100 -f "$HOME/.ssh/vultr_operator_ed25519" \
-C "vultr-operator-2026"
chmod 600 "$HOME/.ssh/vultr_operator_ed25519"
chmod 644 "$HOME/.ssh/vultr_operator_ed25519.pub"
Use a supported host OS with a planned Docker/Compose deployment if needed. Standard Docker Engine/Ubuntu instructions include the official repository and docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin, and docker-compose-plugin packages. Docker documentation’s non-root group is root-equivalent; its sudo-like access is an administrative privilege, not a sandbox. Match that institutional responsibility to your intended user.
Select the product, region, storage and protected address
Your first choice is not a marketing row. For shared general use, compare Regular Performance, High Performance and High Frequency—their generation, SSD/NVMe, RAM/disk, allocation and regional prices. Consider HP/HF 4 GB as a starting hypothesis for a small n8n+Postgres+proxy host only if its actual memory fits; first test can be more constrained. A WordPress host might consider Regular 2 GB if its plugin/DB/backup footprints fit, not because this is a measured visitors-per-RAM minimum.
Verify the exact public plan code and its active availability with your selected control-panel plan list or curl --fail https://api.vultr.com/v2/plans and https://api.vultr.com/v2/regions. The marketing capture has 34 regions including Chennai; the rechecked public endpoint still has 33 without Chennai. Neither confirms every family or SKU’s stock. The normal discussion is about local users and data paths; preserve your selected location’s displayed currency and regional price privately with its capture timestamp. Do not equate nearby users with uniform stock, latency or a global price multiplier.
Choose based on these explicit branches:
- Dedicated Optimized: compare current CPU/memory/storage variant and invoice separately; do not infer universal application speed.
- VX1: identify local-NVMe/block/mixed storage, boot-disk and data-volume costs, current no-cap versus 672h ambiguity, backup/snapshot eligibility and supported operating system. Current guide says no Automatic Backups or Windows. Local storage is expendable until independent recovery proves otherwise.
- Cloud GPU / Bare Metal: treat as separate hardware, driver and SLA/restore exercises; do not follow a blank Ubuntu Cloud Compute guide expecting identical capabilities.
- IPv4 or IPv6-only: select public IPv4 if external webhooks/API/package/callback requires it. The default ordinary plan IPv4 and the $3/month Reserved IPv4 are not interchangeable; the added-attached IPv4 price is unknown. Verify before charging the $1 smallest-plan difference as universal IP pricing.
Reconcile image, features and live order summary
Choose an OS image for a clean OS, Marketplace App for the precise application you have evaluated, or a deliberate backup/snapshot/ISO/iPXE source. A fresh host with unrelated services is not automatically recoverable just because the image is in the catalog. Do not overwrite an existing primary disk to inspect its Marketplace application.
Take a redacted screenshot or write down before deployment:
| Order field | What must be captured | Stop if |
|---|---|---|
| Plan/product/region | Official plan code, vCPU/RAM/disk, generation, active stock and country/region price | Name says one product while hardware/storage or location quote belongs to another |
| Image/OS | Exact Ubuntu release or named Marketplace app/version; preinstalled state expected | Image differs, supports another login, or selected hardware/driver is incompatible |
| Automatic Backups | Current Cloud Compute guide says enabled by default, eligible base +20%; record deliberate opt-in/out selection | Your invoice differs or VX1/other product fallback backup is not established |
| Storage | Which boot/durable/local/Block Storage is actually in the order and its separate charges | Assumes primary-disk snapshot automatically includes an attached volume |
| IP/network | Default/IPv6-only/reserved IP, VPC or NAT plan and port policy | Critical callback or package clients require unavailable IPv4 |
| Extras | DDoS, NAT/load balancer, DB, third-party license, snapshots, tax/currency/credits | Base monthly number is being mistaken for a total-or-cap guarantee |
| Recovery | Independent off-provider/encrypted destination, initial RPO and rehearsal host | No place exists to export final valuable data; image alone is the only “backup” |
A Marketplace install is day zero, not production acceptance. Leaving Auto Backups enabled can be reasonable if quota, recovery destination and RPO permit, but that does not replace application-consistent export. Additional Block Storage is not covered by ordinary primary-disk backup; retained detached volumes and snapshots carry their own supply/cost issue. Backup mechanics remain product-specific.
Establish SSH and limited administration without lockout
Inject an SSH key explicitly supported for the chosen image. Vultr’s Cloud Compute provisioning guide documents an optional limited linuxuser with sudo for supported standard OS images; do not presume that user exists for every Marketplace app. Some images specify different first-login instructions or their own owner/admin flow.
Look up the server IP and initial access details in your live instance view. Prefer matching the host key through a trusted console/recovery session or known-host entry, rather than blindly accepting changed keys. Use the image’s documented username, not every example’s root or preprovisioned limited account:
# Replace only with your actual image-specific user and allocated host.
DISCOVERED_USER='linuxuser' # or root for a standard image whose first login says so
SERVER_IPV4='203.0.113.10' # RFC 5737 example; not a real invoice or target
SSH_KEY="$HOME/.ssh/vultr_operator_ed25519"
ssh -i "$SSH_KEY" -o IdentitiesOnly=yes "$DISCOVERED_USER@$SERVER_IPV4"
The example address is a documentation placeholder; replace it carefully and do not run someone else’s system. If an additional limited admin needs to be created manually on a fresh standard image, you or your administrator should use the currently supported OS method, inspect user state, test its sudo-only access, and save a new credential securely rather than paste password examples. A second successful SSH connection and web-console shell access are prerequisites before restricting root or password logins.
Once signed in, inspect effective SSH configuration without printing sensitive files:
sudo sshd -T 2>/dev/null | \
grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication|allowusers|allowgroups) '
sudo test -f /etc/ssh/sshd_config && stat -c '%a %U:%G %n' /etc/ssh/sshd_config
A first fresh image’s cloud-init can still be configuring repositories, public keys and limited login. Do not repeat default user creation or reset its password if it has not yet completed. Wait and inspect first.
Discover the delivered OS, mounts, routes and services
Read what was actually delivered, before hardening, naming package paths or assuming dashboard hardware details match the user’s environment:
printf '%s\n' '== Image and compute =='
cat /etc/os-release
uname -r
nproc
free -h
swapon --show
printf '%s\n' '== Storage =='
lsblk -o NAME,SIZE,FSTYPE,TYPE,MOUNTPOINTS
df -hT --exclude-type=tmpfs --exclude-type=devtmpfs
findmnt -t ext4,xfs,btrfs,zfs
printf '%s\n' '== Addresses and clock =='
ip -brief address
ip route
timedatectl
printf '%s\n' '== Provisioning and services =='
cloud-init status --long 2>/dev/null || true
systemctl --failed --no-pager
ss -lntup
printf '%s\n' '== Optional Docker runtime =='
if command -v docker >/dev/null 2>&1; then
docker --version
docker compose version
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Mounts}}\t{{.Ports}}'
fi
Record a sanitized baseline—not passwords, tokens or full public-network diagnostics. Compare actual /opt or /var/lib/docker free space and any state volumes to what will be imported, then confirm code/region/order details from the secured console output. The important output files are locations without their secret content.
Stop when you see unexplained existing files/services, cloud-init fail, wrong VM generation or plan, missing privilege, unexpected network listeners or database roots, full disk, proxy failures or unreliable clock. Rediscover before proceeding; the solution is not blindly deleting an unknown Docker volume or package. New OS package installs are performed only if your image supports them and licensing/supported repository requirements check out.
For apt-based fresh standard Ubuntu you may start with:
sudo apt-get update
apt list --upgradable 2>/dev/null
sudo DEBIAN_FRONTEND=noninteractive apt-get -y full-upgrade
# Only if a supported application/version compatibility and backup/recovery window allow:
# Reboot after saving the fresh receipt; then verify SSH from a second session.
# sudo reboot
Do not full-upgrade an unknown heterogeneous Marketplace application merely because the host runs Ubuntu. Inspect current image/documented updatability, database/PHP/agent compatibility and availability window first. Lower-level libraries can affect the installed application even if the provider’s image still launches.
Apply SSH, package and firewall policy deliberately
Preserve the working original SSH session until the second limited-admin session is tested. The exact changes depend on whether your running image configures OpenSSH through an include directory or its main file. Write a dedicated configuration that only narrows root and password login after key-only admin works, and validate the runtime config before reloading:
# Use only after testing key-only limited-admin and console access.
sudo tee /etc/ssh/sshd_config.d/90-operator.conf >/dev/null <<'SSH'
PermitRootLogin prohibit-password
PasswordAuthentication no
SSH
sudo sshd -t
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication) '
# Reload only after the preceding test succeeds and the independent session works.
# sudo systemctl reload ssh
If this is a different application image’s curated authentication scheme, discover and follow its supported path instead of installing conflicting directives. A credential failure is fixed through the preserved console, not by exposing SSH globally with a new password.
| Intended network surface | Correct boundary | Verification before public traffic |
|---|---|---|
| Admin SSH | Restricted known operator sources, key-only; console retained | Second admin session, effective sshd -T route |
| Public web 80/443 | Only the intended proxy/host has them | Actual port owner from ss and Docker listing; TLS via app guide |
| n8n 5678 | Internal Compose backend or loopback behind proxy | No published public backend; successful HTTPS health/url route through Caddy |
| PostgreSQL 5432 | Internal network only | No host ports: entry, no route from web network, firewall check |
| Ollama 11434 / panels / Code Server | Loopback/private authenticated route not bare Internet | Bind/listener/source restrictions and application auth/TLS proof |
| IPv6 | Same intentionality as IPv4 | AAAA only if valid, both address families if actually used |
Vultr Firewall and host UFW/nftables are different layers. Apply corresponding rules only to the actual firewall group/host with a temporary recovery route; do not blanket-disable either because an application cannot connect. Docker’s NAT/IPTables behavior may not show up exactly in the usual ufw overview:
sudo ufw status verbose 2>/dev/null || true
sudo nft list ruleset 2>/dev/null || true
sudo ss -lntup
if command -v docker >/dev/null 2>&1; then
docker ps --format 'table {{.Names}}\t{{.Ports}}'
docker network ls
fi
curl --fail --silent --show-error --connect-timeout 5 --max-time 10 \
https://example.com/ -o /dev/null || true
Your own external connectivity test must target only your own host/allowed resource, from a known network permitted by testing rules. No broad unsolicited scans. Keep a table of destination/source/port/protocol, underlying host/container listener, auth/TLS, owner and last proof. N8n’s public backend and Postgres are not acceptable as an “until it works” opening. Recover private route or authenticated TLS endpoint as appropriate.
Resolve DNS, address-family and TLS compatibility
Reserved IP is not simply an extra ordinary address. Its provisioning, reverse DNS and restart requirements may differ; additional IPv4 pricing is unconfirmed by the reviewed source. Use your current official reserved-IP guide and instance networking docs for the exact selected product if you need subnet isolation. The software’s hostname, allowlists and callback URL must reflect the stable assigned address rather than a guessed resource.
When DNS authority is available, point the A (and only correct functioning AAAA) record to that machine’s intended IP. Changing nameservers is separate; do not perform one just to make a reverse proxy start. Before AAAA-dependent workflows, test your actual DNS resolvers, Docker/container IPv6 settings, package registries and third-party integration clients. Default containers without IPv6 connectivity cannot call “localhost” from a remote integration.
TLS configuration comes from the application guide, not an assumption that every image automatically has Certbot and a certificate. n8n custom HTTPS handles automatic HTTPS through its explicit Caddy configuration and domain variable. On ports 80/443, verify a new empty site with a real domain you own, not the example.com Caddy placeholder input from this article.
Addressing acceptance: correct plan public IP recorded; A/AAAA only intended; working current DNS; services can reach necessary registries and client APIs; intended HTTPS response passes proper certificate verification; no admin/model/database/panel endpoint opened support shortcut. If not, stop domains/certificates and fix the actual network or plan issue.
Inspect the image-specific service before choosing a runbook
Standard Docker image
Discover docker daemon, package origin, effective user, group/Compose plugin, private networks and active ports. Group membership grants Docker-root-equivalence, so choose operators accordingly. hello-world may be a low-risk optional runtime/egress check but needs its own current image/supported driver inventory, and is not n8n readiness.
id
getent group docker
systemctl status docker --no-pager
docker compose version
docker compose ls
docker info --format 'Server={{.ServerVersion}} RootDir={{.DockerRootDir}} Driver={{.Driver}}'
Do not add a half-completed n8n Compose file here; build one coherent deployment next. The image’s “Latest” label is not an immutable pinned upstream application promise.
Vultr-labs WordPress or another listed image
The reviewed WordPress Ubuntu listing describes Nginx/MariaDB, PHPMyAdmin, Certbot, Wordfence, SMTP Mailer, Cockpit:9080 and /var/www/html, but your actual paths and package versions are what you may safely operate. OpenLiteSpeed belongs to another listing. Secure access to Cockpit/PHPMyAdmin/admin proactively rather than treat them as default-public web pages.
systemctl list-units --type=service --state=running --no-pager | \
grep -Ei 'nginx|apache|litespeed|mariadb|mysql|php|cockpit|wordpress|postfix|certbot' || true
ss -lntup
sudo test -d /var/www/html && sudo find /var/www/html -maxdepth 1 -printf '%f\n'
php --version 2>/dev/null || true
df -hT
Review the image’s private credential-delivery instructions with root in the console, but take owner-password secrets to your password manager without photographing terminal or public ticket. Check Nginx configuration, WP core/plugin/site canonical URL and MariaDB service after finding them; never blindly use old listing PHP 8.1 or prefix commands in an updated image. WordPress operations criteria remain appropriate given maintenance and egress needs.
OpenClaw, ComfyUI and AI paths
OpenClaw is an actual agent, not merely a similarly named control panel. Review its actual version and gateway/config path, users/login, Docker access, ~/.openclaw/openclaw.json, model/embedding/telemetry/compaction endpoints, secrets and service listeners without executing the agent’s own install prompts. Replace the Marketplace page’s literal example passwords through your actual credential route. Only after boundary hardening might an operator connect alternate limited accounts; until then expect high privilege, not local assurance.
ComfyUI depends on your selected Cloud GPU image/model/NVIDIA drivers. If driver discovery tools exist, inspect them carefully and record relevant hardware version/VRAM, not generic VM RAM:
# Only if an actually provisioned suitable GPU and vendor tool are present.
if command -v nvidia-smi >/dev/null 2>&1; then
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader
else
printf '%s\n' 'No nvidia-smi found; do not claim this is a working GPU image.'
fi
Day-zero acceptance before valuable data
Create a redacted /root/day-zero-inventory.txt with date/time/source label, selected public plan/region code, currency/tax/boot-volume costs, backup default decision, image/OS version, kernel, resources/disk mounts, actual public addresses/DNS, admin/auth mechanism, service/proxy/runtime versions, effective Vultr/Host firewall/storage posture, listener purpose and last successful fallback connection. Never record actual secret values; locations and owner-only permissions are enough.
Check off:
- Order reconciled: actual host plan, location, disk/storage and optional paid features match invoice expectation—no VX1 unspecified cap/boot-total/backup gap accepted blindly.
- Administrative recovery works: limited user/key succeeds from a fresh session; console available; cloud-init/services understood; OS and future app updates have a supported mechanism.
- Ports intentionally exposed: n8n 5678, PostgreSQL 5432, Ollama 11434, Cockpit 9080 and agent UI/remote tools are not default-public just because their owner exists.
- Storage and cost awareness named: boot and extra persistent disk, backup/snapshot policy, provider network/outbound monitoring and independent restore target have an owner.
- No destructive surprises: unexpected file/data appears only after you understood it, not after a new image overwrite; any existing service has its recovery plan.
- App route chosen: launch the complete n8n stack or model/data-path decision before valuable integrations. An application-specific backup/restore is due before your first valuable secret.
Referenced official behavior: Cloud Compute provisioning, VX1 product guide, Vultr Firewall, automatic snapshots/backups, host Docker installation. Lifecycle and billing remains the canonical decision before any recovery/dismissal.