Build a selected-instance invoice worksheet before destroying anything
This article owns the Vultr lifecycle: CONTROL WRITES / DEFINE CUTOFF → FINAL EXPORT → VERIFY FINAL-CUTOFF RESTORE → DESTROY → AUDIT. It applies before an ordinary instance resize, application rebuild, migration or cancellation—not merely to brand-new experiment cleanup.
| Ledger field | Exact selected-product evidence | Arithmetic/hypothesis boundary |
|---|---|---|
| Product/SKU | Public current plan code family vCPU/RAM/disk; region code, captured time | Do not match by RAM alone; stock and per-plan regional lists differ |
| Hourly source | Both website/API chosen exact values, source label | Regular 2 GB page $0.015 vs public API $0.014 is unresolved, no guessed conversion or authority |
| Monthly behavior | Ordinary Cloud/Optimized/Bare Metal capture 672h, GPU 730h, one-hour minimums, usually first monthly bill; live exact VX1 | VX1 current pricing says no 672 cap while general non-GPU billing says 672; unknown until actual order/support/invoice |
| Region/currency/tax/credit | Base price, selected location multiplier or line, displayed currency/order tax/promo conditions | Example São Paulo Regular 2GB $15 vs base $10 is product/location captured not global 1.5× |
| Eligible Auto Backups | Live order state, current provisioning guide default on, +20% base | Eligible Ordinary base + backups only e.g. Reg2 $10+$2=$12; Ordinary HP4 $24+$4.80=$28.80; Optimized GP4 $30+$6=$36; Memory8 $40+$8=$48; none apply to VX1 fallback automatically |
| Snapshot/storage | Manual snapshot actually compressed GB ×$0.05/month, boot/data Block Storage selection | Allocated disk/number isn't necessarily compressed snapshot GB; Auto Backups stop covering Block Storage; no inferred free volume |
| Network/IP | Intended default IPv4 or IPv6-only; optional Reserved IPv4 $3/month, actual current extras/LB/NAT/DDoS/VPC | $1 gap between 0.5GB regular entries is not additional-attached IPv4 universal fee; attached extra IPv4 price unknown |
| Application/license | N99panel trial/renewal, external-model/API/mail, OS/Windows/Cockpit/DB services exactly selected | Cloud hourly price doesn't include third-party panel/API contract or cancellation |
| Transfer/remaining account | Current documented allowance, current/outbound units/invoice; current product account/pool | No free automatic all traffic assumption; unstated exceptions must remain separate support/invoice branch |
| Recovery operations | Rehearsal temporary host/storage/egress and your operator maintenance effort | “Backups included” doesn't include independent copy or all restoration downtime |
Save redacted live order/invoice/currency/time/Pricing URL/state not credentials or full billing identity. Cost calculator is a ledger helper—not source-reconciliation or final invoice. Exact product/cap/tax/renewal is vendor controls with independent existing data preserved before changes. Consider adding valid selected 20% eligible backup at selection but don't stretch this to VX1 local/GPU/panel as a known recovery cover.
Stop, destroy, subscription cancellation and account closure differ
Stop pauses compute activity while leaving CPU/RAM/disk/IP allocated under server product/billing captured. Billing accrual may continue. Use a stopped app/writer only as a safety state—not “cancel” and not a backup. Make target ID/product label/current data/cost ownership explicit before terminating anything.
Destroy intends same selected associated instance irreversibly losing local disk while ending instance accrual when provider action completes. It does not prove that detached volume, reserved IP, attached NAT/LB/DDoS/objects, selected backup/snapshot conversion, marketplace third-party panel subscription or external model/mail service ends. Local VX1 NVMe is treated as expendable; ephemerality doesn't somehow imply any VX1 bandwidth/snapshot/general protection is available.
Cancel subscription (TOS) is contractual: current chosen period renews automatically until prior permitted current-term cancellation path; exact refund/renewal/panel terms apply. Close Vultr account is separate broad irreversible after all other billed services/refunds/data/export support route, using current official controls; official close-account guidance. This is last not first step. Manually removing key/session/browser credentials contains none of these actions. Operator requested path must be expressly followed, never confusing lifecycle language.
Useful records before stop: inventory in early stage before writer cutoff across all actual regions and service types. Same selected-server's hostname/region/IP but possibly changed ID need verification; do not select lower cost suspicious-looking unknown service. If there are unexpected usage/billing resources, preserve snapshots/manage evidence without losing data; discover dependency/owners and live resources at target account. No blanket multi-region destroy.
Cloud Compute transfer means a calendar pool plus running plan allocations
The reviewed pooled allocation, overages and console usage guidance scope the formula below to documented Cloud Compute, not all Vultr services:
- account: 2TB free outbound pool per calendar month, no rolling carryforward;
- each documented running instance: own plan allocation accrued at
plan_allowance / 672per eligible running hour, summed in same account/current calendar period; - outbound over current allocated pool: $0.01/GB; can happen mid-cycle before end-month’s hypothetical total if actual use already outpaces running allocation;
- actual console Bandwidth Usage/product units/current meter & invoice govern. No unlimited, instant same plan 2TB at deployment or stopped/deleted unlimited accrual promise.
For unit-converted editorial P=2048GB, running contributing 168 hours: plan share 2048 × 168 / 672 = 512 GB. Account's separate allocation still exists; total other instances, current calendar stage/use and undocumented exclusions matter. This is educational use of stated formula, not vendor rounding/monetary oscillated forecast and not free-window guarantee. Do not substitute $plan allowance GiB into pricing documentation if selected source says TB; show actual conversions you used.
| Usage condition | What to do | Unresolved requiring current support/invoice |
|---|---|---|
| Large model/image/file-exchange burst | Check current pool/run share/outbound time series and app/result bytes; reduce unnecessary external downloads (registries/cache accepted) or any other costs consciously, not evade permissible-use rules | Chosen region/sizes availability, registry/CDN egress category and invoice handling |
| n8n outbound + retry | Measure egress and API calls, remove failed repeated sends carefully and use authorized deadlines/backoff; no blocking bill evidence | Provider endpoint/product classification, external third-party charges separate |
| Backup/export off host | Budget transfer and protected staging/growth; monitor uploads consistency beyond uploaded size | Snapshot/backup/private VPC/object-storage traffic and inbound exclusions must not be generalized |
| Stop/rebuild/delete instance | Keep final recovery before change and capture actual current usage evidence | Document says “running”; stopped/deleted pool attribution needs live support/invoice, not assumed free or retained |
| VX1/hosted-other-product | Its product-specific current quota/invoice, never Cloud Compute copied formula | VX1 applicability/allocation unverified at writing |
If an unexpected bill happens protect/recover data first alongside investigating contributor/invoice/endpoint evidence. Freeze only relevant writer/action intentionally while keeping intact other services; copying/export bytes can affect your pool/cost so choose destination and volume carefully. Never drop files or reboot away evidence. Unbilled not-yet-posted usage and eventual bill lag still needs invoice reconciliation later.
Match the recovery mechanism to product and meaningful application data
| Mechanism | Documented scope | Boundary and current-product branch |
|---|---|---|
| Automatic Backup | Eligible Cloud Compute primary active filesystem; +20% base and selected schedule | Not application consistency/restart/query proof; excludes Block Storage, VX1 unsupported per product guide; reconcile live order default |
| Manual Snapshot | Cloud Compute/Cloud GPU point-in-time disk state, $0.05/compressedGB/mo; deletion/retention operator-controlled | Snapshot doesn't automatically quiesce DB or duplicate identity trust domain; Bare Metal generic exclusion; VX1 eligibility unknown until current explicit support |
| Deleted-instance rescue backup | Official documents say two newest survive destruction and age out; separate restoration page describes seven days | Do not merge into a universal active rotation/two-copy promise nor trust as sole “recycle bin”; details current link remain verified |
| Restore Backup | Replaces primary disk; application is offline; later changes on primary get lost; attached Block Storage not restored | Never “inspect” it on data-bearing host; current unchanged since backup implies safe test. Isolate and protect final current state first |
| Application/off-host export | n8n/MariaDB/Postgres/application files/config/secrets state under a labeled cutoff | Operator backed own meaningful data/key and actual read/decrypt/workflow/restart on restored app proves usable—not merely artifact upload |
| VX1 block/local/mixed | Current product-specific storage type, local treated expendable and no Auto Backups | Cap/snapshot eligibility/storage+boot totals/transfer explicitly unverified; select block persistent/current supported path with independent final backup if qualifying |
| Bare Metal/other services | Specific hardware/service/installed filesystem and billed features you actually selected | Do not infer normal VM snapshot or transfer; get correct product supplier support/final backup outside service |
Providers' automatic backup, snapshots, restore backup and deleted-backup restore links define product/supported mechanism, not issue app-backup guarantee. Snapshots and backups in same Vultr credential/account/control panel don't constitute independent account/provider-credential failure recovery. Ransomware/provider-lock/current provider-restore unavailable scenario is part of threat model when choosing destination.
Customer-specific recovery branches before generalizing
Choose by exact order, not similarity of physical disk numbers:
- Eligible Ordinary Cloud Compute: make Auto backup selection explicitly useful for full-primary-state rollback with DB frozen RPO, plus an off-provider exact application export to separate trusted recovery account. Current provider auto-backup alone may not accept desired RPO/Block Storage.
- VX1 local-NVMe: do not choose local only for recoverable valuable data because general website “backup” display occurs. Treat NVMe loss as data loss unless durable external app copy/canonical re-download plus exact restored state proves the actual supported recovery needed; no environment had that test assumed here.
- VX1 block/mixed: identify each volume actual bill/snapshot eligibility and its attach ID before any snapshots/test recreation; ordinary automatic backup is unsupported per VX1 guide even if another included choice causes confusion. Confirm current product basis or stay out with only independently verified application state.
- Cloud GPU/Cloud GPU (for this site primarily ComfyUI/custom n8n): backup checkpoint manifest, configs/user/output or durable separate Object Storage you selected and verified. Driver, hardware, performance and price differences are separate restoration-target gates; ordinary host-node SLA coverage does not certify application recovery.
- Bare Metal: inventory selected product snapshot eligibility/lower-level reimage route; current docs generic snapshot product doesn’t include normal Bare Metal coverage. Export actual outside source representation, no promised “just snapshot” recovery.
- N99panel / OpenClaw / WordPress Marketplace: find vendor tools/config/admin/DB/control-plane resources actually installed; export using their precise path/tool. Panel license cancellation is not Cloud data deletion, vendor backup isn't independent unless separate owner/account/survival tested.
Application-consistent export must fail closed: choose and quiesce the writer
Operator selects protected staging and independent encrypted repository outside the same trust domain, tests connection/secret correctly before opening destructive window, and ensures enough space for application DB/files, current manifest/version list and protected key/config. Scope to actual discovered runtime. Do not copy whole root, /etc, catalog search, external user change logs as a universal archive.
- n8n custom reference
/opt/aixvps/n8nif and only if actual selected deployment: active webhooks/executor/scheduler writers frozen before finalpg_dump -Fc;.n8nis copied while writer stopped; manifests include correct n8n config, key, same protected Postgres DB password, proxy TLS config, mounted execution/custom node/binary-data locations and exact image snapshots/digests. No copying live Postgres raw data supposed application-consistent. n8n docs also support CLI workflow/credential exports as separate protected extras; keep encryption key with protected recovery escrow. - WordPress: discover actual supported current docroot/files/uploads/themes/plugins vs config, PHP/current core/webserver/database, same consistent DB snapshot plus domain/mail/other integrations. Don't blindly assume
/var/www/html, MySQL/MariaDB root password or 8.1 in “Latest” listing. Actual file paths and current supported WordPress backup process determine operations; plugin export alone is not all site recovery. - OpenClaw / ComfyUI / AI / custom apps: necessary actual agent/user config/data/logs/session location, selected model/library/manifest/license/digest/path, custom workflow/nodes, GPU imagery, other persistent mount outputs or verifiable re-download source and secret revoke/reissue plan. Model aliases don't guarantee weights restorable; prove re-download/authority/size if excluded. Restrict copy to authorized data rather than all unrelated plaintext secrets.
Finalize hidden config, companion mounted data and backups by explicit inclusion manifest; choose no sensitive single-file exposure outside encrypted blob. Content view shouldn't need auth credential dump in log. A redacted manifest outside encrypted artifact may record host/product/region/source/path/snapshot/image app/OS versions/DB/schema/table object counts expected, actual service/proxy ports/cert address owner, response/read-only canonical roles and correct encrypted key/output locations. Values remain protected.
Source final freeze: stop/freeze application writer first, or document every interval sync delta through the final intended write cutoff, copy all delta, and application-restore-test exactly that final included state. Source stays quiescent/read-only until that acceptance. Writer resumes after final export or while proving restore → restore proof is obsolete for destroy, preserve those writes/new delta and repeat both steps. A stale rehearsal snapshot is different from final proof. No modifier “we'll sync after restore” is accepted as last backup.
For ordinary Postgres copy fail and empty/truncated handling commands, the complete reference recovery-export.sh in n8n operations is reproduced at end for audit. Typical path-specific preconditions included:
# These are inspection/setup only. No real PROJECT/SECRET is named by the article.
# Actual n8n compose path and stable key/config must be complete before a final dump.
sudo find /opt/aixvps/n8n -maxdepth 1 -type f -printf '%f\n'
df -P /opt/aixvps/n8n
# No env dump, no latest Postgres data-directory copy, no piping secret to public tool.
Use independent encryption rather than conflating “off server” with recovery
One option is AiXVPS custom Restic SFTP, neither official Vultr backup nor a partner subscription. Local tooling validated current restic 0.19.1 pinned from official GitHub release, digest recorded in test evidence attached for review; verify current release official and architecture when adopting. Restic installation, SFTP backend and repository check current docs govern relevant version behavior.
Select separate administrative trust/account/provider and destination under current authorization: SFTP server with known expected host key/disabled password if practical, restrict scope allowed destination, unique repository and strong independent password. Other choices supported actual current encrypted cloud Object Storage/offline copy can be appropriate after account independence, region/fees/traffic/retention sorted; same Vultr Object Storage may be off-host but is not automatically separate control-plane/trust domain.
Before final cutoff save include list paths, no secret values—dump/api-config-sensitive-stage/key escrow selected destination file mapping—plus chosen retention/RPO. Never run repository prune last during a migration; off-provider key escrow enabled offline from surviving primary system. The below is operator template uses synthetic placeholder path and tool, not live backup:
# Run only with YOUR explicit repository and matching secrets in root-only local files.
# No command on this page contacts an SFTP endpoint by itself.
sudo install -d -m 700 /root/aixvps-recovery
# Set in a protected session after populating password source (never echo it to public):
# export RESTIC_PASSWORD_FILE=/root/aixvps-recovery/repository-password
# export RESTIC_REPOSITORY='sftp:backup-user@YOUR_HOST:YOUR_REPOSITORY_PATH'
# export STAGE='/var/backups/aixvps-n8n/.export.YOUR_EXACT_FINAL'
[[ ${RESTIC_PASSWORD_FILE:-} && ${RESTIC_REPOSITORY:-} && ${STAGE:-} ]] || exit 1
[[ $STAGE == /var/backups/aixvps-n8n/.export.* ]] || { printf '%s\n' 'Unrecognized export path';exit 1; }
[[ -s "$STAGE/SHA256SUMS" && -s "$STAGE/postgres.dump.gz" && -s "$STAGE/app/n8n_encryption_key" ]] || {
printf '%s\n' 'Incomplete sensitive export: cannot restaur invoices.' >&2; exit 1;
}
# Both checks initialize only at operator selection, not example arbitrary-repo creation.
# restic init (once only at operator-selected independent destination, successful auth/host trust)
restic backup "$STAGE" --tag aixvps-vultr --tag "${CUTOFF_LABEL:?set a SHORT tag, e.g. final-2026-11-05T220000Z}"
restic snapshots --compact
# `restic check` and optional `--read-data-subset` are repository integrity, not app restore.
If init permission/host/authentication fails, correct known host key/reusable tied owner route; don't store plaintext password in history. A transient snapshots listing is not credential-proof. The final backup includes entire sensitive stage thanks filename restriction; ensure /root/aixvps-recovery/repository-password is separately escrowed and not sole copy within repository; repository must be encrypted but immutable critical key survives administrator loss. Command code 0 isn't ready yet.
Rehearse actual application restore in an isolated safe target
A provider restore backup overwrites primary disk and later changes; this is why a disposable or proven empty detached target is essential. Should choose supported current Cloud/appropriate product “rehearsal” new instance or isolated blank application root never /, no production DNS/external workers by default. Independent provider service endpoint differs select not by lowest displayed pricing.
Before launching restore:
- CONTROL WRITES / DEFINE CUTOFF: exact final included transaction/file marker + stable current key location decided. Source read-only/maintained quiescent for final workflow through restore. External callbacks, mail/workflow/prompt agents, downloaded arbitrary scripts all prevented on replica. If initial rehearsal uses an old copy, name its
phase=NONFINAL, not final restore proof. - Establish target: isolated known safe root matching test tool, let test input dummy workflow/hostnames. Preserve original DB/read-only or only real canonical changed use; not copy over production disk.
- Secure content:
restic snapshots, selected snapshot ID→restic restore ... --target YOUR_ISOLATED_ROOT, verify chosen snapshot/sensitive files hash/key presence supported image UID perms and schema/app compatible full-set. Only application restoration includes DB restore into matching supported Postgres/new DB and schema permissions under exact matching script/proxy/DB pinned version. No continuously recording-old writer without synchronized gap documentation. - n8n application proof: actual stable secret used, DB supported as of version;
docker compose config --quiet, correct n8n mount inbound, query meaningful expected tables/object/final-marker; read config owner, login, decrypt stored noncritical harmless credential, read/test workflow (no real side effect), restart and repeat. Basic 200 page or Postgrespg_isreadyalone not restorable operation; invalid/missing wrong key = fail entire gate. - WordPress proof: new isolated DB restored, exact docroot/content ignoring tool/world lobby, current supported PHP/Nginx/MariaDB no migrated fake env; override canonical/test URL via supported actual process with external mail/plugins/webhooks disabled. Sign in/read content/db query/restart and seed final chosen post ID/version—these checks under operator ownership only.
- AI proof: if exact reference data present, run private isolated non-sensitive Ollama endpoint tag/manifest smoke limited, meaningful custom model/config/connected identity and output presence expected; OpenClaw stays external sessions revoked/disabled throughout, tool-arbitrary prompt never automatically trusted. If GPU exact re-download requires expensive selected GPU, that's additional authorized branch but its lack untested = incomplete marker not claim.
- Capture restore receipt cutoff: zone-label timestamp of source export, last included transaction/post/file/model ID, number of meaningful DB/object/test workflow; source key presence, same app/image/DB support compatibility, targetID/scope cloud safe, credential decrypt/input outcome after restart, resource left, unresolved paths (e.g. license/api credentials not actual validation) explicitly. Source remains read-only so no delta.
Wrong root block: require known explicit artifact-named /srv/aixvps-restore-validation/YOUR_SAFE_SUBDIR or new disposable VM; never guessed mount path or sanitized schedule file to ROOT= arbitrary. Testable specifically rejects /, project source, existing nonempty housing in reference. Cloud-account selection belongs only human-approved operator/vultr official interface. Not this draft.
Reader adaptable guarded local restore check (custom artifact sanity, not whole application)
#!/usr/bin/env bash
set -Eeuo pipefail
RESTIC=${RESTIC:-restic}
command -v "$RESTIC" >/dev/null || { printf '%s\n' 'Install reviewed restic binary on operator path first.' >&2;exit 1; }
# ONLY basic local file restore check. It cannot prove application/DB/credentials/restart.
ROOT=${RESTORE_ROOT:?choose dedicated empty isolated root}
PW=${RESTIC_PASSWORD_FILE:?protected separate repository password file}
REPO=${RESTIC_REPOSITORY:?current selected independent repository}
[[ -n $ROOT && -r $PW && -n $REPO ]] || { printf '%s\n' 'Missing/unsafe restore inputs' >&2;exit 1; }
[[ $ROOT == /srv/aixvps-restore-validation/* ]] || { printf '%s\n' 'Refuse root/default/source/new random base.' >&2;exit 1; }
[[ $ROOT != /srv/aixvps-restore-validation/ && $ROOT != *'..'* && $ROOT != *[[:space:]]* ]] || exit 1
[[ -d $ROOT && -z $(find "$ROOT" -mindepth 1 -print -quit) ]] || { printf '%s\n' 'Target must be pre-created and empty; do not wipe it.' >&2;exit 1; }
[[ -n ${CUTOFF_LABEL:-} && -n ${SNAPSHOT_ID:-} ]] || { printf '%s\n' 'Set the exact final-cutoff tag and its selected immutable snapshot ID (not latest).' >&2;exit 1; }
META=$(mktemp)
trap 'rm -f -- "$META"' EXIT
rc=("$RESTIC" --repo "$REPO" --password-file "$PW")
"${rc[@]}" cat snapshot "$SNAPSHOT_ID" >/dev/null
# Require the exact expected cutoff tag in the selected snapshot's metadata.
"${rc[@]}" snapshots --json >"$META"
python3 - "$META" "$SNAPSHOT_ID" "$CUTOFF_LABEL" <<'PY'
import json, sys
index, wanted, label = sys.argv[1:]
for item in json.load(open(index)):
if item.get('id') == wanted:
tags = item.get('tags') or []
if label not in tags: raise SystemExit('Selected snapshot lacks exact final-cutoff tag')
break
else: raise SystemExit('Selected snapshot not found')
PY
"${rc[@]}" restore "$SNAPSHOT_ID" --target "$ROOT" --verify
find "$ROOT" -type f -name CUTOFF-EVIDENCE -print
# Match expected cutoff and protected files inside actual extracted filesystem;
# application DB/key/workflow/restart acceptance separate gate above.
Use the selected tool’s documented restore --verify and an immutable snapshot ID from the matching tag’s snapshot list; never rely on generic latest. Compare the expected final marker and protected file hashes inside the restored files, then perform the application checks above. A failed check blocks deletion and does not prove that the repository or provider has failed; diagnose the actual cause.
Migrate or resize while retaining the old recovery point
Compare the candidate exact SKU, region, storage lineage, delivered facts, cost and stock. VX1 requires its explicit storage, boot, cap, snapshot and transfer checks; a GPU image requires supported drivers. A slower or cheaper headline is not equivalent capacity. Consult the current Cloud Compute documentation for the selected product and storage operation. Neither a CPU selector nor attaching a disk guarantees data-preserving cross-product cloning or zero downtime.
Nonfinal rehearsal before the final cutoff: on a disposable host or isolated empty target with external side effects disabled, restore an earlier full export to discover version, access and capacity problems. Label the receipt phase=REHEARSAL_NONFINAL; keep the old recovery intact. It cannot certify a subsequent final export.
Final migration or destructive resize: CONTROL WRITES / DEFINE CUTOFF across all writers, or prove every synchronized delta through that cutoff. Export manifests, database, files, config, keys and all deltas; protect an independent copy and check its hashes. Restore that exact cutoff to an isolated application target, then verify owner access, read/query, credential decryption, the last data marker and restart. Only after those pass: confirm ownership, credentials and scope; redirect DNS, API, load balancer, scheduler and workflow inputs; enable the new writer with its own backup. Accept the new canonical operation before retiring the old read-only source. Preserve the verified source export until new writes also have recovery proof.
If a source write occurs after the candidate restore, repeat the final export and restore to include it. DNS completion plus a later delta is not permission to destroy. A replica may catch up only when every delta is captured and the resulting synchronized cutoff is application-restore-tested. A new host, credential or domain can change behavior; preserve compatible config and keys, and prevent restored jobs or webhooks from causing side effects. Secret cleanup is not a recovery plan.
Take a fresh resource, cost, owner and network inventory on the destination; do not inherit old product or cap assumptions. Product labels, prices and endpoints can change.
Ordered destroy and remaining-charge audit
- CONTROL WRITES / DEFINE CUTOFF: Freeze/quiesce all source writers through final capture and exact application restore. Record which workflow transaction/post/custom file/model is last included. If synchronized bounded deltas are used, include every named delta. Otherwise, no new old-system writes until final acceptance; resumed write makes destroy ineligible.
- OPTIONAL NONFINAL REHEARSE: On a disposable target, restore a prior export to discover image, driver, schema and capacity needs, plus owner access, queries and harmless operations with external effects disabled. Label it nonfinal; it never counts as final-cutoff proof.
- FINAL EXPORT: Freeze/capture exact cutoff with DB/files/config/manifest/current selected images/digests and protected keys, hash/smoke validation/compressed PG full readable/dump validation, complete final delta verification. Send independent encrypted copy within separate trust domain. Empty/truncated dump, unmatched hash, missing key/filtered paths/connection are all no-go.
- VERIFY FINAL-CUTOFF RESTORE: Restore that exact selected export and every delta onto isolated current-supported app DB, known empty target. Owner login/read/decrypt/query/harmless test/restart/latest final marker succeeds, not just files uploaded. Keep it and read-only old source as recoverable rollback. If old writer resumed restart CONTROL WRITES, preserving any delta.
- ESTABLISH NEW HOME AND ROLLBACK IF MIGRATING: After exact-cutoff restore passes, deliberately redirect DNS, API, workers, schedulers and integration inputs; enable new writers only when ownership and scope are clear. Smoke-test and back up that new cutoff before accepting it. Retain the old source read-only until no missing delta remains. Without a migration target, preserve the tested independent export as the recovery point.
- INVENTORY: Every relevant region/instance/ID; VX1/OS boot/local/Block Storage volumes/mount lineage; Auto Backups/manual or converted Snapshots; Reserved/connected/ordinary IP addresses; File/Object Storage; NAT/Gateway/LB/DDoS/firewall groups; managed DB; panel/Marketplace license/API/mail/remote-worker/connected identities, control-panel DNS and actual billing/pending snapshots. Inventory every region. The marketing page lists 34 locations including Chennai; the API returned 33 without Chennai at capture. Neither proves that a selected plan is in stock.
- PRESERVE DELIBERATELY: Record any backups or snapshots intentionally retained only after current product-eligibility, restore and monthly-storage checks. Keep the independent final-cutoff export regardless. VX1 has no AutoBackups; its snapshot eligibility and remaining storage costs require product-specific confirmation. Local NVMe is not a backup.
- DESTROY TARGET ONLY: Recheck the instance ID, region, hostname/IP, authorized operator label, captured final-cutoff restore, absence of resumed writes and retained independent copy. Only the operator may use the current official UI or authorized API on that explicitly selected target—not Stop, OS uninstall or deleting files. Abort if the identity or data cutoff is unclear, any volume is unaccounted for, or the recovery budget is unresolved; escalate to the resource owner. A “latest duplicate” is not proof of identity. No destructive command is shown.
- AUDIT: Review every region and service—storage, networking, IP addresses and managed resources—against the current invoice and resource inventory. Record deletion/cancellation dates and private confirmation receipts, expect posting lag, and reconcile the next bill. Ending instance accrual does not prove that every add-on, vendor or license charge has ended.
- CANCEL THIRD PARTIES SEPARATELY: Revise or cancel the N99panel license, mail, model APIs, agents and identities only through their owners’ supported routes; revoke or transfer access deliberately. Keeping domain, download and monitoring services may still be necessary. Destroying the app or instance does not cancel those contracts, and this article sends no ticket or email.
- CLOSE ACCOUNT LAST IF INTENDED: If and only if account closure is an explicit operator decision, finish all billed-service, refund-support and data-retention decisions, then follow the current official close-account guidance. Vendor-described irreversible account closure is distinct from stopping one instance; this article does not request that action.
Refunds, SLA and incident evidence
The official refund policy captured no refunds for services or credits and payments as final. The TOS separately describes cancellation at the end of the selected period and no prorated cash credits; neither is equivalent to stopping or destroying one hourly server. Cloud GPU custom best effort/on request refund is not universal entitlement. A capture not a formal term or a credit control/tool guarantee; eligibility solely vendor.
The official SLA 100% uptime concern is network/host-node per eligible service item, not n8n token/API/model/WordPress plugin, application data loss, scheduler/latency/response, Vultr website/DNS/API/control plane, OS/software/improper configuration, attacks against instance/suspension/paused/halt or many maintenance/notice exclusions. Standard Cloud GPU is beyond this normal SLA; use its separate, unclear refund-on-request wording only as the vendor’s current wording, not an entitlement.
| Captured per-downtime credit tier | Hours of service credit quoted by SLA |
|---|---|
| Less than 9 minutes | 12 |
| 10–59 minutes | 24 |
| 60–119 minutes | 48 |
| 120–239 minutes | 120 |
| 240–419 minutes | 240 |
| 420 minutes or more | 672 / one month wording |
The 9–10 minute gap is in vendor wording, not silently normalized. Claim requires support ticket expressly requesting credit, eligibility assessed under current SLA. Current TOS capture requires notification procedure within three days of the incident, credits one-year expiration and no cash redemption. A credit would not reconstruct preservation of your final workflow or unique model checkpoint. Incident first protect data in recovery gate, monitor/timestamp service logs without hallucinated measurement, then record UTC instants at incident start/end separately from your local ticket date and include instance ID / affected region / selected resource / logs only safe support requested. No invented failure durations or ticket created by article; reader/operator contacts support themselves if desired.
Failed backup, recovery or unexpected-charge checklist
| Evidence | Safe next operator action; data stays protected |
|---|---|
| Dump command fails, zero file, incomplete gzip or pg readable header weird | Writer remains frozen/read-only; retain failed partial for operator diagnose, storage/perms/DB parity logs without secret exposure; re-run final export and actual full cutoff restore |
| DB or object marker older than labeled cutoff | All source states/deltas enumerated; preserve them; no destructive overwrite, re-export/check latest selected includes entire finite change |
| Missing or wrong stable n8n key | Never regenerate and “try credentials”; restore protected original from escrow, verify config/mount/UID, repeat instance harmless decrypt/restart |
| Model/weights/uploads/custom-node missing | Compare manifest authorized source/downloadLicense/actual volume hidden directory vs copied content; recover/mongo query actual dependent path before deleting prior state |
| No disk / unreadable tar / checksum fails | Stop backup/restore; preserve source, grow safe stage through approved resource, re-export deltas then exact app restore. Small hash file does not prove meaningful DB |
| App restored but TLS callback/query/decrypt/new write fails | Replica keeps external actions disabled; isolate domain/key/DB version/registry cause; proof fails, source retained read-only until full pass |
| Ollama/model or admin port publicly visible | Actual both IPv4/IPv6 listener + effective rules; immediately restrict scope/owner auth, environment test associations. No expose-and-security-replace while traffic ongoing |
| Unexpected transfer or next invoice | Preserve labelled invoice/account timestamps/usage/identity/resource/owner evidence; explicit line relation unknown stops assertions; if needed human support contact, no blind purge/instance destruction |
| Instance gone but Panel/external subscription remains | Separate vendor current contract/panel cancel receipt and next renewal verify; Vultr stop/cancel/account mechanisms do not cancel third-party |
| VX1 storage/cap/snapshot/transfer uncertain | Current support actual selected product storage/control panel/order receipts and independent exact final restores; cannot open ordinary Cloud procedure as unsupported fallback |
| Wrong target or unknown source identities | No select/delete/restore; source safe if chosen write-frozen remains read-only; confirm authorized correlative all ledger owners |
Exit acceptance: you can independently restore named exact final source and say latest meaningful data/hash/key with actual app restart, calculate product/region/storage/IP/API totals, identify all retained/destroyed named items and recurring vendor obligations explicitly, then verify posted current/next charge. Failure keeps source retained, not panic Delete old/secondary or open SQL. Scope of validation for command/YAML/examples here is static and synthetic state only, never fake early “tested on live Vultr” promises; actual provider/app invoice/writer/restore ends on your chosen environment's current supported facts.
Tested custom n8n exporter for its matching custom deployment — audit before use
This is only for the exact current selected AiXVPS n8n Compose above, not any generic n8n/DB/panel. MODE=final stops n8n and intentionally keeps it stopped for exact restored cutoff application proof; MODE=rehearsal reopens n8n afterward. Tool does not stop Postgres, preserve validated latest marker comparison automatically, download external backup or restore any application. Review required is actual final marker inside all writers in transaction ready; merely running it isn't final accepted gate. CUTOFF_FILE must be private signoff of scheduler/quiesced webhooks/latest meaningful app object marker. Secrets copied are therefore sent only independent encryption.
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
# AiXVPS custom bounded reference, not Vultr or n8n official.
# Final leaves writer frozen; rehearsal attempts restore after export/failure.
MODE=${MODE:?choose rehearsal or final}
PROJECT=${N8N_PROJECT:-/opt/aixvps/n8n}
DEST=${EXPORT_ROOT:-/var/backups/aixvps-n8n}
CUTOFF_FILE=${CUTOFF_FILE:?last-known-writer-cutoff-and-recovery-evidence}
DOCKER=${DOCKER:-docker}
[[ $MODE == rehearsal || $MODE == final ]] || { printf '%s\n' 'MODE must be final or rehearsal' >&2;exit 1; }
[[ $PROJECT == /opt/aixvps/n8n && $DEST == /var/backups/aixvps-n8n ]] || { printf '%s\n' 'Unexpected project/export destination' >&2;exit 1; }
[[ -d /opt/aixvps && -s /opt/aixvps/README && $(stat -c %U:%G /opt/aixvps) == root:root && -e /opt/aixvps/n8n ]] || { printf '%s\n' 'Refuse unknown parent or uninitialized project' >&2;exit 1; }
[[ ${AIXVPS_MANIFEST_REVIEWED:-no} == yes-reviewed-all-required-files ]] || { printf '%s\n' 'Preflight exact hidden paths/custom binaries and key ownership required' >&2;exit 1; }
[[ -s $CUTOFF_FILE ]] || { printf '%s\n' 'Missing last-included-change cutoff record' >&2;exit 1; }
[[ $DEST != / && $PROJECT != / && $PROJECT != *'..'* && $DEST != *'..'* && $CUTOFF_FILE != "$PROJECT/.env" ]] || { printf '%s\n' 'Unsafe path or nonsense cutoff' >&2;exit 1; }
for f in compose.yml Caddyfile .env secrets/postgres_password secrets/n8n_encryption_key; do
[[ -s $PROJECT/$f && ! -L $PROJECT/$f ]] || { printf '%s\n' 'Missing/unsafe required project file' >&2;exit 1; }
done
for cmd in gzip stat cp find sort sha256sum xargs mktemp df grep dd python3 cut; do command -v "$cmd" >/dev/null;done
command -v "$DOCKER" >/dev/null
# operator declares extra validated paths, no auto-scan or whole host root copying.
if [[ -n ${EXTRA_PATHS_FILE:-} ]];then
[[ -r $EXTRA_PATHS_FILE && ! -L $EXTRA_PATHS_FILE ]] || exit 1
EXTRA_PATHS=()
while IFS= read -r expected || [[ -n $expected ]]; do
[[ -z $expected ]] && continue
[[ $expected == /* && $expected != / && -f $expected && ! -L $expected && -r $expected ]] || { printf '%s\n' 'Required extra missing, non-regular or symlinked' >&2;exit 1; }
EXTRA_PATHS+=("$expected")
done <"$EXTRA_PATHS_FILE"
else EXTRA_PATHS=(); fi
declare -A EXTRA_KEYS=()
for expected in "${EXTRA_PATHS[@]}";do
key=$(printf '%s\n' "$expected" | sha256sum | cut -d' ' -f1)
[[ -z ${EXTRA_KEYS[$key]:-} ]] || { printf '%s\n' 'Duplicate required path' >&2;exit 1; }
EXTRA_KEYS[$key]=$expected
done
dc() { "$DOCKER" compose --project-directory "$PROJECT" --env-file "$PROJECT/.env" -f "$PROJECT/compose.yml" "$@"; }
dc config --quiet
df -P "$PROJECT"; mkdir -p "$DEST"; df -P "$DEST"
dc ps --status running --services | grep -qx n8n || { printf '%s\n' 'Refuse export when expected writer not initially running' >&2;exit 1; }
STAGE=$(mktemp -d "$DEST/.export.XXXXXXXX"); printf '%s\n' "$STAGE" > "$DEST/.last-export-stage"
finish() {
original_code=$?; code=$original_code
: >"$STAGE/state-check-before-reopen"
state_known=yes
dc ps --status running --services > "$STAGE/writer-restoration-check" || state_known=no
if (( original_code == 0 )) && [[ $MODE == final ]]; then
if [[ $state_known == yes ]] && ! grep -qx n8n "$STAGE/writer-restoration-check"; then
printf '%s\n' 'FINAL_EXPORT_WRITER_FROZEN -- next independent encryption + exact-cutoff application restore'
return 0
fi
printf '%s\n' 'CRITICAL: final writer state missing or still running; cutoff cannot be certified' >&2
return 88
fi
[[ $state_known == yes ]] || printf '%s\n' 'Writer state unavailable; requesting service restoration without assuming stopped' >&2
printf '%s\n' 'Attempting writer restoration due rehearsal or unfinished cutoff' >&2
if ! dc start n8n; then printf '%s\n' 'CRITICAL: writer restoration failed; operator attention required' >&2; return 90; fi
# Record a separate post-reopen observable state.
if dc ps --status running --services > "$STAGE/writer-post-reopen-check"; then
grep -qx n8n "$STAGE/writer-post-reopen-check" || { printf '%s\n' 'CRITICAL: writer missing after restoration request' >&2; return 90; }
else printf '%s\n' 'WARNING: post-reopen state unavailable; inspect manually' >&2; fi
return "$code"
}
trap finish EXIT
printf '%s\n' 'CONTROL WRITES / DEFINE CUTOFF: operator has frozen scheduler/webhooks/workers and verified marker before calling this export.'
dc stop n8n
! dc ps --status running --services | grep -qx n8n || { printf '%s\n' 'Writer reported still running; export refused' >&2;exit 1; }
printf '\x00' > "$STAGE/dump.zero.direct"
dc exec -T postgres pg_dump -Fc | gzip -c > "$STAGE/postgres.dump.gz.partial"
[[ -s $STAGE/postgres.dump.gz.partial ]] || { printf '%s\n' 'Empty compressed dump' >&2;exit 1; }
gzip -t "$STAGE/postgres.dump.gz.partial"
[[ $(gzip -dc "$STAGE/postgres.dump.gz.partial" | dd bs=1 count=5 status=none) == PGDMP ]] || { printf '%s\n' 'Truncated/wrong format dump' >&2;exit 1; }
mv -- "$STAGE/postgres.dump.gz.partial" "$STAGE/postgres.dump.gz"
dc cp n8n:/home/node/.n8n "$STAGE/n8n-state"
[[ -d $STAGE/n8n-state ]] || { printf '%s\n' 'Actual declared n8n persistent state missing' >&2;exit 1;}
# Scope is explicit regular files only, never directories/symlinks/whole root.
declare -A EXTRA_KEYS=()
for expected in "${EXTRA_PATHS[@]}";do
[[ $expected == /* && -f $expected && ! -L $expected && $expected != / && -r $expected ]] || { printf '%s\n' 'Required extra missing, non-regular or symlinked' >&2;exit 1; }
key=$(printf '%s\n' "$expected" | sha256sum | cut -d' ' -f1)
[[ -z ${EXTRA_KEYS[$key]:-} ]] || { printf '%s\n' 'Duplicate required path' >&2;exit 1; }
EXTRA_KEYS[$key]=$expected
printf '%s\t%s\n' 'IMAGE_MISSING_UNSUPPORTED' x >/dev/null # no image provenance assumptions
((${#key}==64)) || exit 1
# Protected deterministic internal name prevents basename/path traversal collisions.
cp --no-preserve=mode,ownership -- "$expected" "$STAGE/extra-file-${key}" || exit 1
[[ -r $STAGE/extra-file-${key} ]] || exit 1
printf '%s\t%s\n' "$key" "$expected" >>"$STAGE/EXTRA-MANIFEST"
done
mkdir -p "$STAGE/app"; cp -- "$PROJECT/compose.yml" "$PROJECT/Caddyfile" "$PROJECT/.env" "$STAGE/app/"
cp -- "$PROJECT/secrets/postgres_password" "$PROJECT/secrets/n8n_encryption_key" "$STAGE/app/"
cp -- "$CUTOFF_FILE" "$STAGE/CUTOFF-EVIDENCE"
printf '%s\n' 'Freeze complete; backups are only file-level and MUST still pass app restore' > "$STAGE/state.txt"
printf '%s\n' 'source app pin / postgres pin / actual DB final transaction validated in CUTOFF-EVIDENCE privately; do not invent after export' >> "$STAGE/manifest-notes.txt"
(cd "$STAGE" && find . -type f ! -name SHA256SUMS ! -name '*.partial' -print0 | sort -z | xargs -0 sha256sum >"$DEST/.hashes.tmp")
mv -- "$DEST/.hashes.tmp" "$STAGE/SHA256SUMS"
(cd "$STAGE" && sha256sum -c SHA256SUMS) >"$STAGE/../.verify.tmp" && cp -- "$STAGE/../.verify.tmp" "$STAGE/CONTENT-VERIFICATION" && rm -- "$STAGE/../.verify.tmp"
printf 'FINAL_EXPORT=%s\n' "$STAGE"
printf '%s\n' 'NOT_YET_AUTHORIZED_FOR_DESTROY: exact app restored marker + owners required'
After exporter followed required separate encryption/run Restic, then use actual application-restore instruction above—not the local sanity snippet. Final writer stopped, SHA256SUMS inspect successful and capture phase=FINAL_EXPORT_WRITER_FROZEN are continuations not authorization to early destroy. All failure narratives include mock-tested branches distinct from provider behavior; it does not claim complete Postgres application verification here.
Sources reviewed 2026-11-05 capture: server billing dates stop/destroy, pricing, VX1 product guide, bandwidth pool, automatic backup, snapshot docs, TOS and AUP. Current control panel/SKU source wins where versions still unresolved; do not treat read-only draft as cloud action.