# Install and migrate 1.4.0-rc1 This candidate requires a reviewed cutover. Validate the licensed WHMCS version and actual theme in staging before replacing production. ## Requirements Use a supported, patched WHMCS/PHP combination, PHP cURL, and MySQL/MariaDB advisory locks with InnoDB. The source uses PHP 8.1-compatible syntax; PHP 8.1 is no longer a supported production runtime in September 2026. The PVE HTTPS hostname must match its certificate SAN. For a private CA, set `PROXMOX_CA_FILE` to its private filesystem path. Never disable verification. Use a dedicated privilege-separated provisioning token, separate from the console token. Its user and token need effective permissions for the configured templates, destination VMs, storage, VM firewall, network inventory and optional pool. The MAC allocator requires inherited `VM.Audit` on `/vms` and audits every relevant QEMU/LXC config; a filtered inventory is insufficient. Do not silently substitute a root token. Templates must exist on the configured target node, have `scsi0`, and have tested cloud-init/cloudbase-init, networking and DHCP reservations. The module does not build OS images or shrink disks. ## Options and units Positions 1–9 are preserved; new options are appended. | Position | Option | Meaning | |---|---|---| | 1 | TemplateID | Template VMID; paid OS selection may override | | 2 | Node | Administrator-selected PVE node | | 3 | CPUCores | Integer cores | | 4 | RAM | Module value MB; paid configurable value GB | | 5 | DiskSize | Final GB, at least actual template disk | | 6 | NetworkSpeed | Module value Mbps / 8; paid configurable value already MB/s | | 7 | EnableConsole | `on` permits authorized gateway launches | | 8 | HostnameSuffix | Administrator-controlled suffix | | 9 | IsolationGroupPrefix | Existing firewall group: prefix + bridge | | 10 | OSMinimumPolicy | JSON keyed by template ID; blank disables extra minima | | 11 | ConsolePool | Existing PVE pool; new clones join during clone | Example delivery policy for an OS template with the illustrative ID `100`: ```json {"100":{"cpu":2,"ramMB":3072,"diskGB":20}} ``` Replace `100` with the template ID from your installation and choose appropriate delivery thresholds. These are operator policies, not OS vendor recommendations. To offer a **3 GB** RAM selection, add `3|3 GB` to the product's configurable options, place it between 2 and 4 GB, and set your own pricing. Check for an existing option before adding one. Existing subminimum services keep their resources; their complete selected plan must pass the policy before reinstall/upgrade. OS minimum errors use WHMCS's resolved client locale via `Lang::trans('locale')`. Translations cover Spanish, English, Portuguese (Portugal/Brazil), French, German, Italian, Czech, Hungarian and Chinese (traditional/simplified); other locales and execution without WHMCS language services fall back to English. RAM is shown in GB when exactly divisible by 1024, otherwise MB. This does not change account language preferences or resource requirements. ### Standard Cart nameserver fields WHMCS requests NS1/NS2 prefixes for `Server/VPS` products, although this module does not use them. Apply `integrations/standard_cart-nameservers.patch` to `templates/orderforms/standard_cart/configureproduct.tpl` to hide those two inputs only for products using this module. The `ClientAreaPageCart` hook sets the flag; hidden `ns1`/`ns2` defaults satisfy WHMCS's native form validation without configuring DNS. Hostname, guest password and other products are unchanged. Reapply the small integration after an order-form template update, reviewing any concurrent template customizations. Assigned IP pool example (documentation addresses, not a deployable route): ```text 02:00:00:00:00:01=203.0.113.10;vmbr1,1500,PRIVATE_IPV4 ``` Replace `PRIVATE_IPV4` with the guest address from your own private network. MAC/public IP are required; bridge defaults to `vmbr1`; MTU/private IP are optional. The private IP must match DHCP/NAT design. Bridge and requested isolation group must exist. Verify effective cluster firewall/backend and packet isolation separately: API acceptance is not a packet-level test. ## Activation 1. Back up files and relevant DB tables **outside the web root**. Pause module provisioning/actions during cutover. Inventory active service/VMID/node mappings, custom fields, IP reservations and legacy ACLs. 2. Verify each legacy VMID against its service; resolve duplicate global/product fields. Apply `schema.sql`: it creates the ownership/reservation table and marks VMID/IP/reinstall-time fields administrator-only. No runtime DDL. Do not invent ownership markers for existing VMs. 3. Deploy the separate [gateway](console-gateway/README.md), public HTTPS origin and console pool. Grant a custom role containing only `VM.Console` to both the technical user and its privilege-separated token on `/pool/POOLNAME`. Add only verified existing VPSs to the pool. Option 11 makes future clones join automatically. The separate provisioning identity needs `Pool.Allocate` and `Pool.Audit` plus the required VM mutation rights on its intended pool; direct VM ACLs may disappear on deletion and cannot by themselves support reinstall. These pool rights do not belong on the console-only token. 4. Set `CONSOLE_PUBLIC_ORIGIN` and the same literal `CONSOLE_SHARED_SECRET` on WHMCS PHP-FPM and cron/CLI. Use at least 32 random bytes, outside the document root. FPM normally clears arbitrary environment variables: explicitly expose these variables in its private pool configuration. Gateway configuration/secrets remain independent private files. 5. Upload all runtime PHP files, root `clientarea.tpl` and `assets/` as one version. Do not move the template into `templates/`. Retire the old reverse-proxy password helper; included `console-login.html` is an inert replacement only. Re-save product module settings so WHMCS discovers module hooks. 6. Set Windows policy and console pool. Test checkout, configurable-option upgrade and product upgrade with the actual theme, including different option groups. Hooks validate the complete target plan, reject OS changes in upgrades and require valid target option IDs. Verify native admin CSRF and pre/post service-edit hooks on the licensed version. 7. Revoke legacy PVE access using [SECURITY.md](SECURITY.md). Only after that remove stale PVE passwords from custom fields/email instructions. Restrict direct customer/public access to PVE when the new console path is proven. 8. Test the whole lifecycle with a disposable service, including failed-create recovery, another account, delegated permissions, console replay/expiry/revocation and reinstall. Resume provisioning after validation. ## Timeouts and recovery Measure real clone times and configure FPM/reverse-proxy request deadlines accordingly. The module persists ownership before clone and uses bounded API waits; it does not store credentials in a background queue. A timeout does not prove clone failure. An owned unlocked clone can resume; unknown/missing ownership or an uncertain deletion requires operator review. The pool lock covers a complete allocation inventory and reservation. Large/offline clusters can exceed the 10-second lock wait; callers receive an error and can retry without allocating twice. This candidate does not parallelize inventory reads. `LIFECYCLE.md` explains states and retained reservations. Reinstall preserves the original description while deletion is pending, blocks manual start, and switches to the new marker only after confirmed deletion. ## Rollback Pause module actions and restore the reviewed v1.3.0 file set from a private backup. Retain the new table/evidence until every pending attempt is reconciled; never discard a reservation while a PVE task may still exist. File rollback cannot undo VM creation/deletion, ACL revocation or pool membership. Keep consoles disabled while repairing the gateway instead of restoring legacy password exposure. Test restoration before the cutover.