# Part III - Storage Pools

Store files, back up to S3, check diffs, and schedule deployments across all members.

# Introduction

## Storage Pools

Storage Pools are the central distribution platform for ServersCTL. Publish backups, configuration files and deployment packages from browsers, agents or external software, then compare, version, schedule and deploy them safely across your infrastructure.

**Storage Pools** hold things you care about in production:

- OpenLiteSpeed site and vhost backups.
- cPanel account backups.
- MariaDB / MySQL dumps.
- HAProxy, nginx, PHP, SSL, cron, firewall, and other configuration files.
- Browser uploads and deployment packages.

Each pool is a **named, regional destination** with its own quota, S3 credentials, and object browser. Storage is **account-scoped**: one login can have **multiple pools** (for example *London Recovery* and *Toronto DR*). Pools are **not** tied to a single server pool—you can send or restore from a Storage Pool to **any enrolled member** in your account when compatibility rules allow.

The product thinks in **objects** (for example *example.com vhost*, *all-databases dump*, *nginx site config*), not raw folder paths. Repeated backups of the same site become **new versions** under the same object.

<div class="qMYqUG_convSearchResultHighlightRoot" id="bkmrk-storage-quotas-stora"><div class="" data-is-intersecting="true" data-turn-id-container="d86299f2-5e8f-4713-8be7-cc36ac39db34"><section class="text-token-text-primary w-full focus:outline-none has-data-writing-block:pointer-events-none [&:has([data-writing-block])>*]:pointer-events-auto R6Vx5W_threadScrollVars scroll-mb-[calc(var(--scroll-root-safe-area-inset-bottom,0px)+var(--thread-response-height))] scroll-mt-[calc(var(--header-height)+min(200px,max(70px,20svh)))]" data-testid="conversation-turn-622" data-turn="assistant" data-turn-id="d86299f2-5e8f-4713-8be7-cc36ac39db34" data-turn-id-container="d86299f2-5e8f-4713-8be7-cc36ac39db34" dir="auto">### Where to find Storage Pools

<table><colgroup><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Location

</th><th colspan="1" rowspan="1">What you get

</th></tr><tr><td colspan="1" rowspan="1">**Left sidebar → Storage Pools**

</td><td colspan="1" rowspan="1">Account overview and list of all pools

</td></tr><tr><td colspan="1" rowspan="1">**`/app/storage-pools`**

</td><td colspan="1" rowspan="1">Storage Pools overview (usage, recent objects, live activity)

</td></tr><tr><td colspan="1" rowspan="1">**`/app/storage-pools/new`**

</td><td colspan="1" rowspan="1">Create a new pool (region + capacity + name)

</td></tr><tr><td colspan="1" rowspan="1">**`/app/storage-pools/{pool}`**

</td><td colspan="1" rowspan="1">**Objects** — browse, upload, discover, deploy, restore

</td></tr><tr><td colspan="1" rowspan="1">**`/app/storage-pools/{pool}/activity`**

</td><td colspan="1" rowspan="1">Live incoming/outgoing jobs

</td></tr><tr><td colspan="1" rowspan="1">**`/app/storage-pools/{pool}/credentials`**

</td><td colspan="1" rowspan="1">S3 endpoint and keys for WHM/cPanel/scripts

</td></tr><tr><td colspan="1" rowspan="1">**`/app/storage-pools/{pool}/settings`**

</td><td colspan="1" rowspan="1">Slug, region, quota breakdown

</td></tr></tbody></table>

The sidebar footer also shows **aggregate storage used / quota** across all pools.

</section></div></div>

# Plans, costs, and quota

Storage capacity is billed at the **account** level. Each Storage Pool has its own **assigned quota** slice of that account capacity.

### Included with Pro

<table id="bkmrk-plan-base-storage-co"><colgroup><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Plan

</th><th colspan="1" rowspan="1">Base storage

</th></tr><tr><td colspan="1" rowspan="1">**Community**

</td><td colspan="1" rowspan="1">**0 bytes** — you must purchase add-on capacity before backups can upload

</td></tr><tr><td colspan="1" rowspan="1">**Pro** (active subscription)

</td><td colspan="1" rowspan="1">**5 GiB included**

</td></tr><tr><td colspan="1" rowspan="1">**14-day trial**

</td><td colspan="1" rowspan="1">Same as Pro while trial is active

</td></tr></tbody></table>

When you create a Storage Pool, you can apply the **Included 5 GiB (Pro)** capacity option **once** per account (until that entitlement is fully claimed). The create wizard shows how much included storage is still available.

### Storage Pool add-ons (monthly)

If you need more space, purchase a **Storage** add-on. Prices are **per month**; checkout uses the **region** of the pool or vault you are protecting.

<table id="bkmrk-capacity-monthly-pri"><colgroup><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Capacity

</th><th colspan="1" rowspan="1">Monthly price

</th></tr><tr><td colspan="1" rowspan="1">10 GiB

</td><td colspan="1" rowspan="1">$4

</td></tr><tr><td colspan="1" rowspan="1">50 GiB

</td><td colspan="1" rowspan="1">$12

</td></tr><tr><td colspan="1" rowspan="1">100 GiB

</td><td colspan="1" rowspan="1">$20

</td></tr><tr><td colspan="1" rowspan="1">250 GiB

</td><td colspan="1" rowspan="1">$40

</td></tr><tr><td colspan="1" rowspan="1">500 GiB

</td><td colspan="1" rowspan="1">$65

</td></tr></tbody></table>

**How add-ons combine with Pro:** add-on bytes **add to** your account quota. A Pro account with a 10 GiB add-on has **15 GiB total** (5 GiB included + 10 GiB add-on), not 10 GiB replacing the included amount.

**Where to buy add-ons:** the **Storage Pool** tier picker appears when:

- A backup or upload is blocked for insufficient quota
- You use the replication wizard **Cloud Backup Storage** step
- Legacy pool **Storage** flows that still surface the tier cards

Purchases go through **Stripe Checkout** (`Account` billing). Upgrading an existing storage subscription changes the current Stripe item with proration instead of creating a duplicate subscription.

### What counts toward quota

- Final stored objects and backup archives
- Temporary upload staging while a large backup is still assembling (hidden from the object browser but counted until complete)
- Active upload **reservations** while an agent backup is in progress

When the quota is full, new uploads fail with a clear **insufficient storage** message until you delete objects or buy more capacity.

### Feature access by plan

<table id="bkmrk-action-community-pro"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Action

</th><th colspan="1" rowspan="1">Community

</th><th colspan="1" rowspan="1">Pro / active trial

</th></tr><tr><td colspan="1" rowspan="1">Browse &amp; download objects

</td><td colspan="1" rowspan="1">Yes

</td><td colspan="1" rowspan="1">Yes

</td></tr><tr><td colspan="1" rowspan="1">Run backups into storage

</td><td colspan="1" rowspan="1">Only with purchased quota

</td><td colspan="1" rowspan="1">Yes (with quota)

</td></tr><tr><td colspan="1" rowspan="1">Browser upload

</td><td colspan="1" rowspan="1">Locked

</td><td colspan="1" rowspan="1">Yes (max **5 GiB per file**)

</td></tr><tr><td colspan="1" rowspan="1">Delete objects

</td><td colspan="1" rowspan="1">Locked

</td><td colspan="1" rowspan="1">Yes

</td></tr><tr><td colspan="1" rowspan="1">Restore to server

</td><td colspan="1" rowspan="1">Locked

</td><td colspan="1" rowspan="1">Yes (compatible targets)

</td></tr><tr><td colspan="1" rowspan="1">Deploy config to server

</td><td colspan="1" rowspan="1">Locked

</td><td colspan="1" rowspan="1">Yes

</td></tr><tr><td colspan="1" rowspan="1">Configuration Discovery

</td><td colspan="1" rowspan="1">Locked

</td><td colspan="1" rowspan="1">Yes

</td></tr><tr><td colspan="1" rowspan="1">Deployment Wizard

</td><td colspan="1" rowspan="1">Locked

</td><td colspan="1" rowspan="1">Yes

</td></tr></tbody></table>

### Regions and endpoints

When you **create** a Storage Pool, you choose a **region** (physical vault cluster). Pick the region closest to your servers and restore targets for lower latency.

### Billing regions (Stripe)

Add-on checkout is priced per vault region:

<table id="bkmrk-region-key-label-sho"><colgroup><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Region key

</th><th colspan="1" rowspan="1">Label shown in billing

</th></tr><tr><td colspan="1" rowspan="1">`eu-west`

</td><td colspan="1" rowspan="1">**EU West**

</td></tr><tr><td colspan="1" rowspan="1">`ca-east`

</td><td colspan="1" rowspan="1">**CA East**

</td></tr><tr><td colspan="1" rowspan="1">`sgp-central`

</td><td colspan="1" rowspan="1">**SG Central**

</td></tr></tbody></table>

Additional regions may appear in the create wizard, marked **Coming soon**.

### Your pool’s hostname

Each pool gets a dedicated endpoint on **serversctl.com** storage infrastructure:

```text
{pool-slug}.{region}.storage.serversctl.com
```

Example: slug `london-recovery` in EU West → `london-recovery.eu-west.storage.serversctl.com`

Use this hostname for:

- **WHM / cPanel → Additional Destinations → S3 Compatible**
- S3 backup tools and scripts
- Agent off-site backup authentication

**Credentials** for the pool are under **Storage Pools → {pool} → Credentials**.

# Create your first Storage Pool

1. Open **Storage Pools** in the left sidebar.
2. Click **Create Storage Pool** (or go to `/app/storage-pools/new`).
3. **Step 1 — Region:** select an available region (healthy clusters show **S3 endpoint**).
4. **Step 2 — Capacity:**
    
    
    - **Included 5 GiB (Pro)** — free, uses your Pro entitlement (shown only while remaining).
    - **Paid tiers** — 10 GiB through 500 GiB monthly options (when checkout is enabled for your account).
5. **Step 3 — Name:** give the pool a clear name (for example *Frankfurt Recovery*). The wizard suggests a name from the region.
6. Click **Create Storage Pool**.

You land on the pool **Objects** page. Activation provisions vault space, DNS, TLS, and S3 credentials for that pool.

**Tip:** use separate pools for separate purposes (production backups vs config baselines vs a second geography). Always secure your account with Two-Factor authentication.

# Navigation overview

## Account overview (`/app/storage-pools`)

- Total usage across pools
- Per-pool cards (region, used %, recent activity)
- Links into each pool’s Objects and Activity

### Per-pool tabs

<table id="bkmrk-tab-purpose-objects-"><colgroup><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Tab

</th><th colspan="1" rowspan="1">Purpose

</th></tr><tr><td colspan="1" rowspan="1">**Objects**

</td><td colspan="1" rowspan="1">Main work surface — browse, upload, discover, deploy, restore, delete

</td></tr><tr><td colspan="1" rowspan="1">**Activity**

</td><td colspan="1" rowspan="1">**Live** jobs only (running backups, uploads, Send To, deploy, restore)

</td></tr><tr><td colspan="1" rowspan="1">**Credentials**

</td><td colspan="1" rowspan="1">S3 URL, bucket/slug, access key, secret — for WHM and automation

</td></tr><tr><td colspan="1" rowspan="1">**Settings**

</td><td colspan="1" rowspan="1">Read-only pool metadata (slug, region, quota, default flag)

</td></tr></tbody></table>

## Objects and versions

### Object browser layout

Objects are grouped **by source server** first (member folders), not dumped in a flat list.

1. **Top level:** folders per source member (hostname / site name).
2. **Inside a member:** service folders such as **Backups**, **OpenLiteSpeed**, **MariaDB**, **NGINX**, **WordPress**, **SSL**, **Cron**, **Firewall**, **PHP**, **cPanel**, **Services**.
3. **Inside a service folder:** individual objects.

**Backups** from a server stay under that server’s folder, then **Backups** — so an old site backup does not create a second root folder for the domain name.

**Search** flattens the tree and shows matching objects across the pool.

### Object row actions

<table id="bkmrk-button-when-it-appea"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Button

</th><th colspan="1" rowspan="1">When it appears

</th><th colspan="1" rowspan="1">What it does

</th></tr><tr><td colspan="1" rowspan="1">**Open**

</td><td colspan="1" rowspan="1">Always

</td><td colspan="1" rowspan="1">Version history, metadata, compare, download

</td></tr><tr><td colspan="1" rowspan="1">**Deploy**

</td><td colspan="1" rowspan="1">Object is deployable (for example OLS vhost config, discovered `.conf`)

</td><td colspan="1" rowspan="1">Push config to compatible members

</td></tr><tr><td colspan="1" rowspan="1">**Restore**

</td><td colspan="1" rowspan="1">Object is a restorable backup snapshot

</td><td colspan="1" rowspan="1">Guarded restore on compatible members

</td></tr></tbody></table>

Row menu adds **Send latest to inbox**, **Deploy latest**, **Restore latest**, **Download**, **Delete** (Pro).

### Versions

Each object has one or more **versions** (v1, v2, …). Version states include **active**, **archived**, and **deprecated**. Deploy and restore the default to the **latest active** version unless you pick another in the UI.

**Open** an object to:

- See all versions with size, date, and source channel (agent backup, WHM S3, browser upload, discovery, and so on)
- **View file** — inline text preview for configs (binary/archives prompt download instead)
- **Compare** — diff against the previous version (text) or metadata/size for archives
- **Download** a specific version
- **Send**, **Deploy**, or **Restore** a specific version

# Getting data into a Storage Pool

## Managing Data

### Member backups

From any enrolled server’s member tabs:

<table id="bkmrk-source-typical-path-"><colgroup><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Source

</th><th colspan="1" rowspan="1">Typical path

</th></tr><tr><td colspan="1" rowspan="1">**OpenLiteSpeed → Backups**

</td><td colspan="1" rowspan="1">Full / site / web backup jobs

</td></tr><tr><td colspan="1" rowspan="1">**MariaDB → Backup**

</td><td colspan="1" rowspan="1">Database dump

</td></tr><tr><td colspan="1" rowspan="1">**cPanel → account backup**

</td><td colspan="1" rowspan="1">WHM `pkgacct` style packages

</td></tr><tr><td colspan="1" rowspan="1">**Backups tab**

</td><td colspan="1" rowspan="1">Snapshot backups

</td></tr></tbody></table>

When the job supports it, you **choose the destination Storage Pool** before the job runs. Progress appears under **Activity** (incoming lane).

Agent backups flow: **check quota → collect → dump/package → upload → confirm stored**. Install a current agent (v204+ recommended) for step-by-step byte progress.

### WHM / cPanel S3 destination

1. Open **Storage Pools → {pool} → Credentials**.
2. Copy **S3 endpoint**, **bucket** (your pool slug), **access key**, and **secret**.
3. In WHM: **Backup → Additional Destinations → S3 Compatible**.
4. Set endpoint to your pool hostname, bucket to slug, path as documented on the Credentials page.
5. Run WHM backups — they land as objects in that pool.

Quota is enforced on the vault; over-quota uploads receive **507 Insufficient Storage**.

### Browser upload (Pro)

1. Open pool **Objects**.
2. Click **Upload**.
3. Select file(s) — large files upload in **16 MiB chunks** (max **5 GiB per file**).
4. After upload, **publish**: attach as a new version of an existing object, keep as a separate object, or cancel.

### Configuration Discovery (Pro)

Baseline server configs without running a full backup:

1. On **Objects**, click **Run Discovery**.
2. Pick **one member** to scan (account-wide member list).
3. Choose categories (HAProxy, nginx, OpenLiteSpeed, PHP, SSL, MariaDB, cPanel, cron, firewall, apps, and more) or select all.
4. Options: include SSL private keys (off by default), include system package units under `/lib/systemd/system` (off by default), **force fresh baseline** (ignore agent cache).
5. Confirm — a read-only scan runs on that member only. Discovered text files become objects; **unchanged files do not create new versions**.

Live progress shows on the Objects page until complete. Requires agent **v208+** for discovery (older agents may still be selectable; the job reports the real result).

**Privacy:** application configs (WordPress, Laravel, Docker Compose, and similar) store **redacted** copies — passwords and secrets are stripped. Redacted objects show **Secrets redacted** and cannot be deployed back to production.

### Track Changes (daily discovery)

On a **member folder** row menu → **Track Changes**:

- Enables a **daily** scheduled discovery for that member and pool.
- Folder shows **Tracked daily.**
- Only **changed** files create new versions (agent v219+ cache).

### Agent CLI upload (large files)

On the server (agent **v195+**):

```bash
sudo /usr/local/bin/balctl_heartbeat.py --send-to-storage /path/to/file-or-folder
```

The agent packages the path, checks quota, uploads as an **Agent upload** object. Useful when browser limits are awkward.

### Protection replication

**Protection** jobs (cPanel / OpenLiteSpeed standby) can replicate into vault storage tied to your account quota. If space is insufficient, the replication wizard prompts for **Cloud Backup Storage** add-ons.

# Send To, Deploy, and Restore

### Send To inbox

Delivers a copy to a member’s **storage inbox** (`/var/lib/balctl/storage-inbox/`) **without** changing production files. Use for inspection or manual steps.

1. Open object or version → **Send To** (or row menu).
2. Select one or more target members.
3. Confirm — progress appears in **Activity** (outgoing).

### Deploy

Writes configuration to **production paths** on selected members. The agent:

- Backs up the current file under `/tmp/balctl-storage-deploy/`
- Writes allowlisted paths only
- Validates and reloads services where supported
- **Rolls back** on failure

**OpenLiteSpeed vhost** deploy uses a guarded vhost path. **Discovered configs** deploy to the same member or another member with matching OS/service (agent v215+).

1. Click **Deploy** on a deployable object, or **Deployment Wizard** for multiple objects.
2. Pick **version** if prompted.
3. Select **compatible targets** (incompatible members are shown but blocked).
4. Review paths, optional **reload OpenLiteSpeed**, optional advanced path override.
5. **Deploy now** or **schedule** (wizard).

A live **deploy spotlight** shows progress per target member.

### Restore

For **backup objects** linked to a snapshot (OLS site/web/full, cPanel account, database dumps):

1. Click **Restore** on object or version.
2. Select **compatible** members (OLS backups → OLS members, cPanel → cPanel, and so on).
3. Confirm — guarded restore runs on each target; **Activity** tracks progress.

Restore **replaces** production data for that backup scope — use with care.

### Deployment Wizard

**Objects → Deployment Wizard** (Pro, when deployable/restorable objects exist):

1. **Source member** — same grouping as the object browser.
2. **Objects** — pick deploy and/or restore objects (one action type per run).
3. **Targets** — compatible members only.
4. **Paths** (deploy) or **Confirm** (restore).
5. **Schedule** (deploy only) — now or future time.

# Activity, S3, Settings & Deleting Objects

## Activity tab

Shows **live work only** — not historical logs.

<table id="bkmrk-lane-examples-incomi"><colgroup><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Lane

</th><th colspan="1" rowspan="1">Examples

</th></tr><tr><td colspan="1" rowspan="1">**Incoming**

</td><td colspan="1" rowspan="1">Running backups, browser/S3 uploads, discovery archiving

</td></tr><tr><td colspan="1" rowspan="1">**Outgoing**

</td><td colspan="1" rowspan="1">Send To, deploy jobs, restore jobs

</td></tr></tbody></table>

Refreshes every few seconds. Completed or failed jobs disappear from Activity; the finished object remains in **Objects**.

## Credentials and S3 setup

**Storage Pools → {pool} → Credentials**

<table id="bkmrk-field-use-endpoint-s"><colgroup><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Field

</th><th colspan="1" rowspan="1">Use

</th></tr><tr><td colspan="1" rowspan="1">**Endpoint**

</td><td colspan="1" rowspan="1">S3 URL for WHM, rclone, restic, etc.

</td></tr><tr><td colspan="1" rowspan="1">**Bucket**

</td><td colspan="1" rowspan="1">Pool slug

</td></tr><tr><td colspan="1" rowspan="1">**Access key / Secret**

</td><td colspan="1" rowspan="1">Authentication

</td></tr></tbody></table>

Regenerate keys from the panel if compromised. Keys are scoped to your account and pool.

**WHM tips:**

- Use the **regional** endpoint hostname shown for your pool.
- Do not point WHM at a shared global server name — each pool has its own hostname and vault assignment.
- Ensure server egress IP is allowed (same network rules as agent heartbeat where applicable).

## Settings

**Settings** shows:

- **Slug** — used in URLs and S3 bucket name
- **Region** — vault cluster
- **Quota / Included** — capacity assigned to this pool
- **Default pool** — whether this pool is the account default for new uploads

Rename and delete pool flows (if exposed in UI) respect active usage — check quota and objects before removing a pool.

## Deleting objects

**Pro:** select objects with checkboxes → **Delete selected**, or delete from row menu / object details.

**Deletion removes the logical object and version history from your storage. There is no way to recover a file after deletion.**

# Troubleshooting & Glossary

### “Insufficient storage” / backup won’t start

- Check sidebar **storage used / quota**.
- Delete old objects or purchase a **Cloud Backup Storage** add-on.
- Pro: confirm you have not exhausted the **included 5 GiB** without add-ons.
- Large jobs reserve space before upload — wait for stuck jobs to expire (up to 24h) or cancel the job.

### Upload button disabled

- **Community** plan — upgrade to Pro or buy storage quota.
- Trial ended — subscribe to Pro.

### Deploy / Restore target greyed out

- Target member lacks the right stack (for example cPanel backup → non-cPanel server).
- Object is redacted or not deployable/restorable.
- Refresh members by reopening the modal (panel refreshes account member list).

### Discovery stuck or slow

- Member must be online with agent check-in.
- Watch the progress panel — phases are agent-reported (v219+).
- **Force fresh baseline** re-uploads everything and takes longer.

### WHM S3 backup fails

- Verify endpoint, bucket, keys from **Credentials**.
- Confirm quota headroom.
- Check vault region matches what you purchased in Stripe.

### Objects missing after backup “succeeded”

- Large archives may still be **assembling** — watch **Activity** until **Confirm stored**.
- Look inside the correct **member → Backups** folder.
- Use **Search** by filename or domain.

## Glossary

<table id="bkmrk-term-meaning-object-"><colgroup><col></col><col></col></colgroup><tbody><tr><th colspan="1" rowspan="1">Term

</th><th colspan="1" rowspan="1">Meaning

</th></tr><tr><td colspan="1" rowspan="1">**Object**

</td><td colspan="1" rowspan="1">A named thing in a pool (site backup, config file, dump)

</td></tr><tr><td colspan="1" rowspan="1">**Version**

</td><td colspan="1" rowspan="1">A point-in-time revision of an object

</td></tr><tr><td colspan="1" rowspan="1">**Artefact**

</td><td colspan="1" rowspan="1">Internal platform type (OLS vhost, cPanel account, etc.) — you see the friendly object name

</td></tr><tr><td colspan="1" rowspan="1">**Publish**

</td><td colspan="1" rowspan="1">Finalize an upload into the object catalog

</td></tr><tr><td colspan="1" rowspan="1">**Send To**

</td><td colspan="1" rowspan="1">Copy to member inbox without production changes

</td></tr><tr><td colspan="1" rowspan="1">**Deploy**

</td><td colspan="1" rowspan="1">Write config to production with rollback

</td></tr><tr><td colspan="1" rowspan="1">**Restore**

</td><td colspan="1" rowspan="1">Replay a backup snapshot on a compatible server

</td></tr><tr><td colspan="1" rowspan="1">**Discovery**

</td><td colspan="1" rowspan="1">Read-only inventory of config files into the pool

</td></tr></tbody></table>