Shared topics
Cloud-init & provisioning
How Impulse modules bootstrap servers via cloud-init: the one-time bootstrap fetch, variable substitution, re-applying the bootstrap in place, custom templates, and provider-specific quirks.
This applies to the modules that create and manage their own servers — ImpulseObjects, ImpulseDB Postgres, ImpulseAuth, ImpulseValkey, ImpulseSecrets and ImpulseSearch. ImpulsePlesk and ImpulseCpanel work with Plesk and cPanel servers you register yourself, and ImpulseVPS creates your customers’ servers and manages them only through the provider’s API.
1. The provisioning flow, end-to-end
Section titled “1. The provisioning flow, end-to-end”- You add a server in the module’s admin area. The module renders its bootstrap script for that server (hostname, firewall allowlist, admin proxy secret, DNS credentials for the TLS certificate, and so on) and stores it, encrypted, on your WHMCS server.
- The module asks the provider’s API to create the server. The instance’s
user_datais only a small fetcher carrying a short-lived, one-time token — never the full script or its secrets. - The server boots and cloud-init runs the fetcher as root. It downloads the full bootstrap from your WHMCS System URL over HTTPS, checks its SHA-256 against the one the module recorded, and runs it.
- The script installs OS packages, the module’s runtime (RustFS, Nginx and the admin proxy for ImpulseObjects; PostgreSQL and its pooler for ImpulseDB Postgres; and so on), configures the firewall to let your WHMCS server reach the admin proxy, and issues a Let’s Encrypt certificate through a DNS-01 challenge with your DNS provider’s API token. The server’s DNS records are created through the same DNS provider.
- The module’s
provisiontask — registered with Core’s cron runner at a 2-minute cadence — checks the provider and the server’s admin proxy health endpoint on each tick, and marks the server online once the setup has finished. - The bootstrap writes a log on the host. You can read it from the module’s admin area — it is fetched through the server’s scoped admin proxy, not over SSH.
2. Template variables
Section titled “2. Template variables”ImpulseObjects’ templates use {{PLACEHOLDER}} variable substitution; other modules write the same kind of per-server values into variables at the top of the script they render. The exact set differs per module and engine, and several modules’ diagnostics check that the template they will use still contains the placeholders they need. ImpulseObjects’ common placeholders:
| Variable | Source |
|---|---|
{{FQDN}} |
Server hostname from the provision form |
{{WHMCS_IPV4}} / {{WHMCS_IPV6}} |
Your WHMCS server’s IP addresses from the module’s settings (used for the firewall rules that allow the admin proxy) |
{{LE_EMAIL}} |
Let’s Encrypt email from the module’s DNS & TLS settings |
{{DNS_PROVIDER}} |
Active DNS provider |
{{DNS_API_TOKEN}} / {{DNS_ZONE_ID}} |
DNS provider credentials (used for the DNS-01 challenge) |
{{ADMIN_PROXY_PORT}} / {{ADMIN_PROXY_SECRET}} |
Per-server admin proxy port + secret (auto-generated for each server) |
{{SSH_PUBLIC_KEY}} |
Your break-glass SSH public key — filled in only while the module’s HIGH-RISK break-glass SSH setting is on; empty otherwise |
On top of these, ImpulseObjects’ template carries the storage root credentials, the RustFS version pin, the block-storage size and monitoring settings, among others.
3. Re-applying the bootstrap in place
Section titled “3. Re-applying the bootstrap in place”Sometimes a provision fails partway, or a server’s configuration drifts from what the module would render today, and you want to re-run the bootstrap rather than destroy the server. Modules compare a hash of the bootstrap they would render now with the one the server last applied, so they can show when a server is out of date. Where a module offers it, its re-apply action — named Update server, Apply, Apply/Rebuild or Apply config depending on the module — does this through the server’s admin proxy:
- The module renders the current bootstrap and stores it for a one-time fetch, as for a new server.
- The admin proxy fetches it, checks it, and re-runs it in place.
- The run is marked as a re-apply, so the script takes its non-destructive path: it doesn’t reboot the server (ImpulseObjects also holds back kernel package upgrades), so a re-apply never reboots a live server out from under its customers.
- The module follows the run and reports when it has finished, or why it failed.
This is why re-applying on a healthy server doesn’t break it — the bootstrap is written to be re-run, and a re-apply skips the disruptive steps. Where a module still offers re-running over SSH, that is a HIGH-RISK break-glass path, off by default.
4. Custom templates
Section titled “4. Custom templates”Each module ships its default templates in modules/servers/<module>/cloud-init/, one per engine or server type (for example bootstrap-rustfs.sh). If you need extra packages (a monitoring agent, a custom nginx config, a corporate CA cert), most of these modules let you save a full-template override in their admin area — the module’s own guide says where. The override is used for every new provision and re-apply until you clear it.
5. Provider-specific quirks
Section titled “5. Provider-specific quirks”- Linode — user_data size cap. Linode caps
user_dataat 16 KiB. The bootstrap fetcher is far smaller than that. If a full script ever has to be delivered, Core’s Linode driver falls back to a private StackScript and the module deletes it once the server is online — which is why the Linode API token needs StackScripts read/write access. - New provider accounts — low limits. Fresh accounts at most providers start with low resource limits (instance counts, volume sizes) and may need identity or billing verification before larger orders. Raise limits with the provider before provisioning a large storage or database server, and test with a small server first.
- Cloudflare DNS — missing
Zone:Read. The most common provisioning failure across providers. The DNS-01 challenge needs bothZone:DNS:EditANDZone:Zone:Read. The Cloudflare token UI doesn’t enable Read by default for new tokens.
6. Diagnosing a stuck provision
Section titled “6. Diagnosing a stuck provision”If a server stays in provisioning or ends in provision_failed, open its bootstrap log from the module’s admin area — it is read through the server’s admin proxy once the proxy is up. Most failures land in:
- The server can’t reach your WHMCS — the fetcher can’t download the bootstrap (firewall, IP allowlist, DNS for your System URL), or its one-time token expired before it ran. The fetch failure is at the top of the log. Fix reachability and provision again.
- DNS API token missing
Zone:Read— cert issuance fails. Re-issue with the right scope. - Hostname doesn’t resolve yet — DNS for the new record hasn’t propagated. Wait, then re-apply.
- Block storage not available in region — some providers don’t offer block storage, or a storage type, in every region. Switch region or plan.
- Admin proxy never came up — the log isn’t reachable through the proxy, and the provider’s web console is the place to look. Core’s 15-minute health check records
admin_proxy.unreachablein the audit log.
Once the root cause is fixed, use the module’s re-apply action to re-run the bootstrap in place without destroying the server. A provision that failed before the admin proxy came up has to be provisioned again.