# Backups Fail Silently on CloudPanel / nginx / OpenLiteSpeed

> SiteVault Pro backups failing with 'cannot create backup directory' on CloudPanel, nginx or OpenLiteSpeed: fix wp-content/uploads/ permissions and the vhost.

- Canonical: <https://royalplugins.com/support/sitevault/backups-fail-on-cloudpanel-nginx/>
- HTML version: <https://royalplugins.com/support/sitevault/backups-fail-on-cloudpanel-nginx/>

---

If SiteVault Pro backups fail without an actionable error on a managed-host stack — usually with a “cannot create backup directory” message on 1.7.31+ — the cause is almost always filesystem permissions on the `wp-content/uploads/` tree. Two layers to address: fix the permissions so PHP can create the directory, then add the web-server rule that keeps the backups themselves unreachable. Here’s both, per server.

### Most Common Hosting Stacks Affected

CloudPanel, RunCloud, GridPane, ServerPilot, and other managed-host stacks where `wp-content/uploads/` is owned by a different user than PHP-FPM runs as. The directory-creation failure happens at the filesystem layer regardless of the web server. The reason nginx / OpenLiteSpeed get called out is a secondary step: those servers ignore the `.htaccess` SiteVault auto-writes, so the protection layer needs a one-line vhost rule on top of the permission fix.

## Symptoms

You probably have this issue if one or more of the following are true:

#### On SiteVault Pro 1.7.31 and later

- Backup row shows status **Failed** with an error message like: *“Backup cannot start: cannot create backup directory at /wp-content/uploads/sitevault/backups. Check filesystem permissions on the parent directory and any server-level rules.”*
- The error names the exact directory that can’t be created
- SSH access shows `wp-content/uploads/sitevault/` either doesn’t exist OR exists but the PHP user can’t write to it

Why you see a named error on 1.7.31+

SiteVault 1.7.31 added a pre-flight check that surfaces the exact directory that can’t be created. Pre-1.7.31 the failure was silent and the row just said “Backup in progress or failed” with no detail — if you’re on an older version, update to 1.7.31+ first to get the proper error message before debugging.

#### On SiteVault Pro pre-1.7.31

- Backups row in the dashboard shows status **Failed** with the generic *“Backup in progress or failed”* message and no detail
- No `.zip` ever appears in the backups directory (because the directory itself was never created)
- Database-only backups *do* complete when written to a different directory, but full backups don’t
- The `wp-content/uploads/sitevault/` directory is missing entirely or empty

## How to Verify It’s This Specific Issue

Two quick checks confirm the diagnosis before you change any server config.

#### Check the parent directory’s writability as the PHP user

From an SSH terminal in your WordPress root. The check tests whether the PHP user can write to `wp-content/uploads/` — that’s the parent SiteVault needs to create `sitevault/` inside. Checking the missing sitevault/ directory directly would always fail (it’s missing — that’s the symptom we’re diagnosing).

```
ls -la wp-content/uploads/sitevault/ 2>/dev/null || echo "SITEVAULT DIRECTORY MISSING"

PHP_USER=$(stat -c '%U' wp-config.php)
sudo -u "$PHP_USER" touch wp-content/uploads/.write-test \
    && rm wp-content/uploads/.write-test \
    && echo "UPLOADS WRITABLE BY $PHP_USER" \
    || echo "UPLOADS NOT WRITABLE BY $PHP_USER"
```

If you see `UPLOADS NOT WRITABLE BY ...`, you’ve confirmed the cause — the PHP user can’t create subdirectories under `uploads/`. Go to Layer 1 below to fix ownership.

#### (Optional) Check the web-access protection state

From your local machine, curl the directory URL:

```
curl -I https://yoursite.com/wp-content/uploads/sitevault/
```

A `403 Forbidden` means the web-access protection (Layer 2 below) is already in place — good. A `200 OK` or `404` with a directory listing means you’ll need the server-block rule from Layer 2 once you have a working backup directory. This check is informational; it doesn’t tell you anything about why `wp_mkdir_p` failed (that’s the filesystem layer, separate from the HTTP layer).

#### (Optional) Check Tools → Site Health

In wp-admin go to **Tools → Site Health → Info → Filesystem Permissions**. The `The uploads directory` row should say *Writable*. If it says *Not writable*, your uploads directory itself is locked — fix that first, then re-test SiteVault.

## The Fix — Two Layers

There are two separate problems to solve, and it’s easy to conflate them. Do them in this order:

1. **Fix the directory-creation failure** — this is a *filesystem-layer* issue (Linux file permissions, PHP’s `open_basedir`, or in rare cases SELinux/AppArmor). The web server’s config doesn’t directly control whether PHP’s `mkdir()` syscall succeeds.
2. **Protect backups from being downloaded by URL guessing** — this is a *web-server-layer* issue. SiteVault auto-writes `.htaccess` + `web.config` + a stub `index.php` into the backup directory, which Apache and IIS honor. nginx and OpenLiteSpeed don’t read `.htaccess`, so on those servers you need an explicit vhost rule.

Why the plugin’s error message mentions nginx

The 1.7.31 error message reads *“Check filesystem permissions on the parent directory and any server-level rules (e.g. nginx `deny all` on /wp-content/uploads/sitevault/)”*. The nginx hint is included because some managed-host stacks mirror their nginx deny rules at the filesystem layer via custom security wrappers — in those edge cases, relaxing the nginx rule does fix the creation. But the most common cause by far is straightforward filesystem permissions, which the Layer 1 steps below address.

### Layer 1: Fix Directory Creation (the actual cause)

#### SSH in and identify the PHP user

The PHP user is whoever owns `wp-config.php`:

```
cd /path/to/your/wordpress
stat -c '%U:%G' wp-config.php
```

Typical values: `www-data:www-data` (vanilla nginx/Apache), `cloudpanel:cloudpanel` (CloudPanel), a per-site user like `site-myname:site-myname` (managed hosts).

#### Confirm the parent directory is owned by that user and is writable

```
ls -la wp-content/uploads/
```

The `uploads` entry should show the same owner you got in the previous step, with mode `755` or `775`. If the owner is different (e.g. `root` or some deploy user), that’s your cause — PHP can’t create subdirectories under a directory it doesn’t own.

#### Fix ownership if needed

From SSH. Uses `%U:%G` to pull both the user AND the primary group from `wp-config.php` — safer than assuming the group has the same name as the user (which is the default on most distros but not universal).

```
sudo chown -R $(stat -c '%U:%G' wp-config.php) wp-content/uploads/
sudo chmod 755 wp-content/uploads/
```

#### Manually create the SiteVault directory tree (skips the WP layer)

If WordPress is still struggling, just create the directories yourself with the right ownership — SiteVault will use them on the next backup:

```
PHP_USER=$(stat -c '%U' wp-config.php)
sudo -u "$PHP_USER" mkdir -p \
    wp-content/uploads/sitevault/backups \
    wp-content/uploads/sitevault/temp \
    wp-content/uploads/sitevault/logs
```

Trigger a fresh backup from **SiteVault Pro → Backups → Backup Now**. The 1.7.31 pre-flight check should now pass.

#### If still failing — check `open_basedir` and disk space

Two remaining filesystem-layer culprits:

- **open\_basedir restriction:** some hosts limit PHP to a whitelist of paths. From the WP admin **Tools → Site Health → Info → Server** tab, find “PHP open basedir”. If it’s set, the WordPress installation path must be inside the listed paths. Contact your host if it isn’t.
- **Disk space / quota:** `df -h` and (on hosts with per-user quotas) `quota -s`. Out-of-disk produces the same “cannot create” symptom.

### Layer 2: Protect Backups from Web Access (security)

After Layer 1 makes backups work, the backup files themselves need to be unreachable by URL guessing — they contain your full database dump and `wp-config.php`. On Apache and IIS the protection is automatic (SiteVault writes `.htaccess` and `web.config`). On nginx and OpenLiteSpeed you have to add a vhost rule because those servers don’t read `.htaccess`.

SiteVault will warn you proactively

If the backup directory ends up web-accessible, SiteVault Pro 1.7.26+ probes it via a short-lived canary file and shows a red admin notice on every page load until you fix it. So you’ll know to come back here even if you skip this layer initially.

#### CloudPanel + plain nginx

Open your site’s vhost config (CloudPanel: `/etc/nginx/sites-enabled/<site>.conf`; Debian/Ubuntu: `/etc/nginx/sites-available/yourdomain.conf`; CentOS/RHEL: `/etc/nginx/conf.d/yourdomain.conf`). Inside the `server { ... }` block, add:

```
location ~* /wp-content/uploads/sitevault/ {
    deny all;
    return 403;
}
```

Then reload nginx:

```
sudo nginx -t && sudo systemctl reload nginx
```

#### OpenLiteSpeed

#### Open the OLS admin panel

Navigate to **Virtual Hosts → (your site) → Context** (usually at port 7080).

#### Add a new Static Context

Click **Add** → **Static**. Set **URI:** `/wp-content/uploads/sitevault/`, **Access Allowed:** No. Save.

#### Graceful restart OLS

**Actions → Graceful Restart** in the admin panel.

#### LiteSpeed Web Server (Enterprise) + Apache

Both honor the `.htaccess` SiteVault writes into the backup directory automatically — no extra config needed.

## Why Does This Happen?

Two separate things are going on, and the failure conflates them in a way that’s easy to mis-diagnose.

### The creation failure (Layer 1)

SiteVault Pro stores backups under `wp-content/uploads/sitevault/`. The first time it runs a backup, it needs to create that directory tree. `wp_mkdir_p()` — the WordPress wrapper around PHP’s `mkdir()` syscall — can fail silently for a handful of filesystem-layer reasons:

- **The PHP user doesn’t own `wp-content/uploads/`** — common on managed hosts where a deploy script created the WordPress install as one user, but PHP-FPM runs as a different user. PHP can read the directory but can’t create subdirectories under it.
- **`open_basedir` restriction** — some hosts restrict PHP to a whitelist of paths via `php.ini`. If the install path isn’t in the whitelist, every filesystem call fails.
- **SELinux / AppArmor / custom security wrappers** — rare but real on hardened stacks. Some managed-host setups mirror their nginx deny rules at the filesystem layer via these mechanisms, which is what the plugin error message is hinting at when it mentions “server-level rules”.
- **Disk space / per-user quotas** — produces the same “cannot create” symptom.

Before 1.7.31, `wp_mkdir_p()`’s return value was discarded by the plugin, so the failure was invisible and the backup just crashed mid-run with a generic error. 1.7.31 checks the return value and surfaces the exact path that failed, which is what lets you actually fix it.

### The web-access protection (Layer 2)

The backups themselves contain your full database dump plus `wp-config.php` — anyone with a URL guess could download them. SiteVault writes a `deny all` rule into `.htaccess` AND `web.config` AND a stub `index.php` guard the moment the directory is created.

Apache honors `.htaccess`. IIS honors `web.config`. **nginx ignores both**, and so do OpenLiteSpeed and some LiteSpeed configurations — their web-server config has to be edited at the vhost level. That’s why the Layer 2 step is required on those servers but not on Apache.

SiteVault Pro 1.7.26+ self-validates the protection: it probes the backup directory with a short-lived canary file via loopback HTTP, and shows a red admin notice if the canary is fetchable. So you’ll know if Layer 2 needs work even if you initially skipped it.

SiteVault 1.7.31 surfaces Layer 1 errors proactively

SiteVault Pro 1.7.31 added an explicit pre-flight check that names the exact directory that can’t be created, so you can ask your host the right question instead of getting a generic “backup failed”. If you’re on an older version, upgrading to 1.7.31+ is the first move — the error message gets you to this fix doc much faster.

## Still Failing After the Server Config Change? Email Priority Support

If you’ve added the location block, reloaded the web server, and SiteVault still fails to create the backup directory, email **[support@royalplugins.com](mailto:support@royalplugins.com)** with the diagnostic info below. Priority email support is included with your SiteVault Pro license — typical response time is within 24 hours.

#### Information We’ll Need

- **SiteVault Pro version** (Plugins → Installed Plugins)
- **The exact error message** shown on the failed backup row (1.7.31+ will name the directory)
- **Hosting provider name** + control panel (CloudPanel, RunCloud, GridPane, ServerPilot, custom, etc.)
- **Web server**: nginx, OpenLiteSpeed, LiteSpeed Enterprise, Apache
- **SSH output** of `ls -la wp-content/uploads/` AND `ls -la wp-content/uploads/sitevault/ 2>/dev/null || echo MISSING`
- **Last 50 lines** of `wp-content/uploads/sitevault/logs/sitevault-YYYY-MM-DD.log` if the directory exists
- **The location block** you added (or a confirmation of which fix you tried)

[Back to SiteVault Support](https://royalplugins.com/support/sitevault/)
[Diagnosing Stuck or Stalled Backups](https://royalplugins.com/support/sitevault/diagnosing-stuck-or-stalled-backups/)
