Part 1 of Hetzner Cloud Module Installation for WHMCS
Continuing from part 2 of Hetzner Cloud Module Installation for WHMCS
Usage and metric billing
WHMCS's daily cron records bandwidth used, the plan's included allowance, and the disk limit.
For metric billing, open the product's Other tab → Usage Billing and set your per-unit prices.
Only things Hetzner actually charges for are reported, so you never bill a customer for something that costs you nothing:
| Metric | What Hetzner charges |
|---|---|
| Block Storage | Per GB per month |
| Snapshot Storage | Per GB per month |
| Backups | A flat percentage of the server price |
| Floating IPs | A flat monthly rate per IP |
| Primary IPs | A flat monthly rate per IP |
| Billable Bandwidth | Per TB above the plan's included allowance |
CPU, memory and disk are not reported as metrics: they are part of the plan you already charge for, and billing them again would double-charge.
The live provider rates for all of these are on the addon's Products page, so you can price your markup against them.
Billable bandwidth counts only what exceeds the included allowance. A plan with 20 TB included reports zero until 20 TB is passed, then reports the excess — the included traffic is already in the recurring price.
Moving from the older HetznerCloud module
If you already sell Hetzner servers through the previous HetznerCloud module, its products can be moved across without touching a single server.
Nothing is created, deleted, restarted or renamed at Hetzner. Migration only re-points WHMCS at the servers your customers already have.
- Finish Steps 1 to 4 first — the addon must be active and at least one Hetzner Cloud account added, because migration needs to know which Project each product provisions into.
- Open Addons → Hetzner Cloud Manager → Migration. Every product still running on the old module is listed, with its old Project, Server Type and Location, and how many live services it has.
- For each product choose the Account, then pick the Location and Server Type from the dropdowns — they list what Hetzner actually offers, pre-selected to the legacy value where it still matches. Set a Price Markup and press Migrate.
- Read the confirmation. It reports how many services were relinked out of the total, for example 12 of 12 service(s) were relinked.
Check it worked: open one of the migrated services. The dashboard should load and show the live state of the customer's existing server.
What migration does
| Step | Detail |
|---|---|
| Switches the product | Its module becomes Hetzner Cloud Manager, and Account, Location, Server Type and Price Markup are written. |
| Creates the custom fields | Including Server ID, which is how this module knows which server belongs to a service. |
| Relinks every service | The old module stored the server id inside an instanceId field as serverid_projectid; the server id is taken from it and written to the new Server ID field. Where that field is empty, the WHMCS server record's access hash is used instead. |
| Carries the SSH key id | So terminating a migrated service still removes its key from the Project. |
| Builds the options | Configurable options, product addons and their pricing, exactly as for a new product. |
Fewer services relinked than the total Three services had no usable server id on record. They are not broken — open the addon's Servers page, find each server, and use Assign to link it to its service by hand.
Cancelled and fraud services are skipped on purpose. They are not relinked and no server of theirs is touched.
Check the Location and Server Type before migrating. They are pre-selected from the old product where the name still matches, but the older module used its own naming and some values will not. A wrong Server Type here does not affect existing servers — it only decides what new orders create.
Migrating is safe to repeat. Running it again on the same product simply rewrites the same values.
After migrating
- Both modules can stay installed. Once every product has moved, the old one can be removed at your convenience.
- Re-save each migrated product once so its paid add-on switches and pricing are written the way you want them.
- Existing invoices, billing cycles and service dates are untouched.
Upgrading to a newer version
Upgrading is an overwrite. There is no migration script to run and no maintenance window.
- Back up first — your WHMCS database, and the two module folders. Every upgrade should be reversible.
- Upload the new
modules/servers/hetzner_cloud_vps/andmodules/addons/hetzner_cloud_vps/folders over the old ones. Overwrite when asked. - Open System Settings → Addon Modules. WHMCS notices the new version and runs the upgrade for you as the page loads. You do not click anything.
- Open Addons → Hetzner Cloud Manager and check the version in the footer at the bottom of the page.
Check it worked: the footer shows the version you just uploaded, and your accounts, products and services are all still there.
To confirm it ran, look in Utilities → Logs → Module Log for an entry named
EncryptStoredTokens. It records how many tokens were converted. If you do not
see one, either there was nothing to convert or the accounts had already been
converted by an earlier page load — both are fine.
Do not delete the module folders before uploading the new ones. Deleting and re-uploading is the same as overwriting, but if the upload fails halfway you are left with a half-installed module and a client area that errors. Overwrite in place.
Your settings are safe. Product settings are stored by position, and the module never reuses a retired position. An upgrade cannot silently move "Console" onto the switch that used to mean something else.
After upgrading, hard-refresh the dashboard once (Ctrl+F5, or Cmd+Shift+R on a Mac). Browsers cache the stylesheet and script; the version number in their URL changes on upgrade, but a proxy in between may still hold the old copy briefly.
Languages
Language files ship for every WHMCS default language. Buttons, tabs, labels and statuses are translated. Longer warnings remain in English on purpose: WHMCS falls back per phrase, so nothing breaks, and an inaccurate warning about erasing data would be worse than an English one.
To finish a language, edit its file in either module's lang/ folder and
replace the remaining English text.
If something goes wrong
Every message the module shows is meant to name the cause and the fix. If one does not, that is a documentation bug worth reporting.
| "That product is not on the legacy Hetzner Cloud module." | The product was already migrated, or never used the old module. | Nothing to do. | | "Select the Hetzner Cloud account this product provisions into." | No account was chosen on the migration form. | Pick one. If the list is empty, add an account in Step 4 first. |
Where to look first: Utilities → Logs → Module Log records every exchange with Hetzner. API tokens and private keys are masked there, so the log is safe to read and safe to quote.
Messages a customer or an administrator may see
| What you see | What it means | What to do |
|---|---|---|
| "This feature is not enabled for this product." | The tab's switch is off in Module Settings. | Turn on the matching switch under Client Area Features, or leave it off if that was intended. |
| "This action is not available." | An administrator-only action was attempted from a customer session. | Nothing. This is the module refusing correctly. |
| "No Hetzner Cloud server is assigned to this service yet." | The Server ID custom field is empty, so the module does not know which server this service owns. | If the server exists, assign it from the addon's Servers page. If it was never created, check the Module Log for why the order failed. |
| "Your session expired. Reload the page and try again." | The security token with the request did not match the session — usually a page left open for a long time, or a browser that dropped the session cookie. | Reload the page and repeat the action. If it repeats immediately every time, your WHMCS session cookie is not persisting; check the session settings on the server. |
| "The server must be powered off before its plan can be changed" | Hetzner requires the server stopped for a resize. | Nothing. The module stops it, resizes, and restarts it if it was running. |
| "Action Protection is enabled" / "Rebuild protection is enabled at the provider" | A protection switch is on. The message names which one. | Turn off the named protection, then retry. They are separate: one is the module's, one is Hetzner's. |
| "That volume is not attached to this server." / "That snapshot does not belong to this server." / "That floating IP is not assigned to this server." | The resource named in the request is not owned by this service. | Nothing. This is the ownership check refusing to touch another customer's resource. |
| "That operating system is not available for this server." | The selected image is not in Hetzner's catalogue for this server, and is not a snapshot this service may use. | Pick from the list shown. If a published snapshot is missing, re-check it is still published on the addon's Resources page. |
| "A volume can only be made larger." | Hetzner cannot shrink a volume. | Enter a size above the current one. |
| "Please wait a few seconds and try again." | The rate limit on password resets, credential reveals, console requests and reinstalls. | Wait a few seconds. It is per service and per action, so it does not block anything else. |
| "This action could not be completed. Please contact support if it keeps happening." | The customer's version of an error. The detail is deliberately withheld from them. | Read the real reason in the Module Log, or repeat the action from the service's Module tab, where administrators see the provider's own message. |
| "This service includes" … | A purchased allowance is used up — snapshot storage, firewalls, or firewall rules. The message names the limit and what is currently used. | Free one up, or sell a larger allowance. Nothing was changed at Hetzner. |
| "Automatic backups are managed by the provider." | Someone tried to delete an automatic backup as if it were a snapshot. | Turn backups off to stop them accruing; individual ones cannot be deleted. |
| The dashboard shows only a suspension notice | Correct behaviour for a suspended service. | Unsuspend to restore it. |
| "This dashboard could not load." | The dashboard's first request failed outright. | Check the Module Log. Most often the account's token has been revoked in Hetzner, or the host cannot reach api.hetzner.cloud. |
Messages on the administration side
| What you see | What it means | What to do |
|---|---|---|
| "WHMCS could not encrypt the value." | WHMCS's encryption is unavailable, so the module refused to store an API token it could not protect. | Confirm your WHMCS installation is intact and its encryption key is present, then save the account again. The token is not stored until this succeeds — nothing was saved in the clear. |
| "The account configured on this product no longer exists." | The product points at an account row that has been deleted. | Reselect an account in the product's Module Settings. |
| "That image was not found on this account." | A snapshot was published, then deleted in Hetzner. | Withdraw the stale entry on the Resources page. |
| "Only snapshots can be published for rebuild." | The selected image is a system image or a backup, not a snapshot. | Take a snapshot of the prepared server first, then publish that. |
| "Unable to reach Hetzner Cloud API" | A network-level failure, not a rejected request. | Check outbound HTTPS from the WHMCS host. The module retries transient failures on its own before showing this. |
Nothing here matches
- Reproduce the problem once, so the newest Module Log entry is the relevant one.
- Open Utilities → Logs → Module Log and read the newest entry for
hetzner_cloud_vps. The request and the provider's reply are both there. - If the reply mentions a Hetzner error such as
resource_unavailableoruniqueness_error, that is Hetzner refusing, not the module. The message usually names the constraint.
Before contacting support, have: your WHMCS and PHP versions, the module version from the addon footer, and the relevant Module Log entry.
Never send your API token, a server root password, or a TLS private key — not to us, not to anyone. The masked Module Log entry contains everything needed to diagnose a problem. If you have already pasted a token somewhere, revoke it in Hetzner and generate a new one.