Product design v2 · 6 of 6

Deletion

A cancellation is reversible until the instance is terminated. After that the job expires every licence, releases the AWS resources (the IP after a 3-day hold), bills the last usage and queues the member account for closure within AWS's limits. Every site on the pool goes with it; the JetBackup copy in Wasabi and the 1Password item stay.

CancellationTermination jobThe 10 stepsWhat is keptClosing the accountStatesIn the app

Cancellation

End of billing period (default)Immediate
RequestDELETE /v1/hosting/{id}?action=delete_all&type=… → Dedicated::deleteHosting(); a cancel change row; status cancellation_pending
WHMCS sidetblcancelrequests written now for the pool and every site on it, the unpaid renewal trimmed (existing CancellationRequests trait); WHMCS terminates on the due date through the module guard, which queues the jobno cancel request yet; the change stores execute_after = now + 24 h; dedicated:terminate-due (hourly) writes the request and dispatches the job when the window has passed
Abort windowuntil the due date24 hours (dedicated.abort_window_hours)
How to abort{command: cancel_termination} or the "Cancel termination" button: deletes the cancel requests, status back to active, a cancel_termination change row. Refused once step 6 below has started.
Sites on the pooldestroyed with the server. The cancel page lists every site on the pool and asks for explicit confirmation; the JetBackup copy in Wasabi is the only way back. Sites can be moved to Rochen One shared or another pool beforehand with the existing migration flow.
Mailsconfirmation with the termination date, the abort deadline and the list of sites that will be removed

Termination job

Class
App\Jobs\TerminateDedicatedInstanceJob, same runner, lock and WAIT rules as deployment
Modes
terminate (normal: 3-day IP hold, final invoice) · abort (tearing down a failed deployment: IP released at once, no invoice; run automatically on final deployment failure)
Plan
stored in dedicated_instances.plan, replacing the deployment plan; resumable with dedicated:resume
Point of no return
step 6, terminate_instance. Everything before it can be undone by starting the instance again

The 10 steps

#StepDoesAlready done when…Reversible
1guardstatus → terminating, lock taken, in-flight changes refused—yes
2stop_instancestop and WAIT stoppedstate stoppedyes
3final_backuptriggers a last JetBackup run to the Wasabi bucket and WAITs for it (skipped in abort mode). No EBS snapshots are taken: the Wasabi copy is the retained databackup job reported completeyes
4licences_cancelManage2 expire, CLN delete keys (CloudLinux, Imunify360, KernelCare), JetLicense cancel, Softaculous licence cancelled (NOC API to confirm), MailChannels sub-account removed at cleanup; LiteSpeed → ticketprovider reports no active licence for the IPre-issuable only
5zabbix_removedelete host, then the Zabbix IAM key, user and policynot foundno
6terminate_instanceTerminateInstances and WAIT terminated. Point of no returnstate terminatedno
7hold_eipdisassociate only; eip_release_after = now + 3 d. dedicated:release-ips releases it later; a redeploy inside the hold reuses it so DNS stays valid. Abort mode releases at onceaddress unassociatedyes, within the hold
8delete_volumesdelete root and home volumes (the Wasabi backup is the retained copy)not foundno
9cleanupkey pair, SSM parameters under /rochen/dedicated/{hosting}/, security groups, MailChannels sub-account, Cloudflare DNS records, the pool's tblservers row. Kept: the 1Password item and the Wasabi bucket (the system has no delete permission there); a Maintenance ticket "Wasabi bucket to review" and a devops mail are raisednot foundno
10close_billingone transaction: terminate change applied (end of the timeline), last data-transfer pull, final usage invoice, pool and every Dedicated Site service on it Terminated, status closing_account, terminated_at, close_account_after = terminated_at + 3 d (after the IP hold; nothing else remains in the account)status—

A failure after step 6 cannot be undone by a retry, so it opens a Maintenance ticket listing the steps left; the job stays resumable and support finishes it with dedicated:resume once the cause is fixed.

What is kept

Wasabi backups

The server's JetBackup bucket stays after deletion. The system has no Wasabi delete permission (Chris); deletion is a manual decision from the ticket and the devops mail the termination raises.

1Password item

The credentials item stays in the vault after deletion, for audit and for a restore.

Elastic IP for 3 days

Held unassociated so a client who changes their mind can be back online without a DNS change: dedicated:resume on a pool in the hold redeploys with the same IP and restores sites from the Wasabi backup.

Nothing in EC2

No EBS snapshots (MCS has none either). Volumes go with the instance; the member account closes once the IP hold has passed.

Closing the account

AWS allows closing at most 10 % of member accounts in any 30-day window, and a closed account stays suspended for 90 days before it disappears. Closure is therefore never a job step.

  1. Queueevery row in closing_account ordered by close_account_after.
  2. Daily rundedicated:close-accounts at 03:00: skip rows whose date has not come, confirm the IP was released, call CloseAccount.
  3. Quota hiton CLOSE_ACCOUNT_QUOTA_EXCEEDED stop for the day, log a notice, increment close_account_attempts; alert devops after 30 attempts.
  4. Successaccount_closed_at set, status closed, a close_account change row. The 90-day AWS grace period needs nothing from us.

States

stateDiagram-v2
  active --> cancellation_pending: cancel (end of period or immediate)
  cancellation_pending --> active: cancel_termination
  cancellation_pending --> terminating: due date reached / 24 h window passed
  terminating --> terminating: steps 1–5 (reversible by support)
  terminating --> closing_account: step 6–10 done, final invoice
  closing_account --> closed: CloseAccount (quota-aware, daily)
  failed --> terminating: abort command (mode abort)

In the app

Cancel page

subscriptions/[id]/cancel gains the Dedicated case (it is empty for AWS today): type choice, reason, the list of sites that will be destroyed with a typed confirmation, and a plain statement of when the server will be destroyed and until when it can be stopped.

While pending

The server and subscription pages show a banner with the termination date and a "Cancel termination" button while cancellation_pending.

While terminating

The provisioning card shows the termination steps; controls are disabled.

After

The pool and its sites disappear from lists (Terminated); the final invoice appears under Billing.

Rochen One Dedicated · deletion v2 · September 2026