Use a Storage Server with WordPress: what works and what does not

Published on 6 min read

Not everything you read about WordPress and external storage actually works. This article separates the three cases: backups work right away, downloads with little effort, and the media library only under one condition.

The directory wp-content/uploads is the part of WordPress that grows without a brake. Images, PDF files, videos, plus several sizes of every image that WordPress generates automatically. After a few years there are dozens of gigabytes sitting there, and space on the web server is the most expensive space you can buy.

A Storage Server costs a fraction of that. The only question is what can really be moved off. There is a lot written about this online that does not work in practice. This article separates the three cases cleanly.

The three cases at a glance

WhatDoes it work?Effort
Backupsyes, right awaya quarter of an hour, free plugin
Large downloadsyesa small script or a download plugin
Media library, your own serveryesmount it once, then invisible
Media library, shared hostingnothe matching plugin does not exist

The last point is the one most people trip over. So the inconvenient truth first.

Why there is no plugin for the media library

The well-known offloading plugins for WordPress all speak the same language: S3. They connect to Amazon S3 or a compatible service, upload the file there, delete the local copy and replace the address in the post with a public address of that service.

Exactly that cannot be transferred to a Storage Server, for two reasons:

  • The storage speaks SMB, SFTP and WebDAV, but no S3.
  • There is no public address per file. Every access is authenticated, so there can be no link that the visitor's browser calls up directly.

There are individual plugins that work with FTP, but none with noteworthy adoption and current maintenance that moves the media library off completely over SFTP or WebDAV. If you find one, look at the date of its last update and the number of active installations before putting it to work.

The way that works: mount instead of offload

On your own server with root rights you turn the whole thing around. Instead of teaching WordPress to talk to foreign storage, you bring the storage to the place WordPress writes to anyway:

apt install -y cifs-utils
mkdir -p /mnt/storage
printf 'username=u123456-sub1\npassword=YOUR_PASSWORD\n' > /etc/samba/storage.cred
chmod 600 /etc/samba/storage.cred

Entry in /etc/fstab:

//u123456.storage.kernelhost.net/backup /mnt/storage cifs credentials=/etc/samba/storage.cred,uid=www-data,gid=www-data,file_mode=0660,dir_mode=0770,seal,_netdev,nofail 0 0

Then move the existing files over and replace the directory:

mount -a
mkdir -p /mnt/storage/uploads
rsync -a /var/www/example.com/wp-content/uploads/ /mnt/storage/uploads/
mv /var/www/example.com/wp-content/uploads /var/www/example.com/wp-content/uploads.alt
ln -s /mnt/storage/uploads /var/www/example.com/wp-content/uploads

WordPress notices nothing of this, for the application it is a perfectly normal path. The old directory stays behind as uploads.alt until you have checked that everything works. Only delete it then, not before.

The trap along the way: thumbnails

WordPress generates several sizes of every image and loads them on every page view. If those small files live on network storage, the network latency is added per file, and a gallery with forty images waits forty times.

Two solutions, both good:

  • Put a cache in front, for example a cache in the web server that keeps the delivered files locally.
  • Put only the originals on the storage and leave the generated sizes local. That is a bit more work, but it is the cleanest way for sites with many images.

Backups: the fastest benefit

If you only do one thing, do this one. A backup on the same server is not a backup: if the disk is wiped or the website is encrypted, the backup is gone with it. On separate storage it survives.

The free plugin WPvivid can back up to the storage over SFTP in its basic version, with a schedule and a retention rule. The complete guide for that is in WordPress backups to the Storage Server.

On your own server it gets even better, namely with rsync or BorgBackup straight out of a scheduled job. Then you transfer only the changes, and BorgBackup deduplicates on top of that.

Delivering large downloads

For files that visitors are meant to download, the storage is ideal: they are read rarely, they are large, and they do not have to be fast, they just have to arrive. Access runs through a small script that checks the permission first:

<?php
// in functions.php or as a plugin of its own
add_action('template_redirect', function () {
    if (!isset($_GET['kh_download'])) {
        return;
    }
    if (!is_user_logged_in()) {
        wp_die('Please sign in', '', ['response' => 403]);
    }

    $pfad = '/mnt/storage/downloads/' . basename($_GET['kh_download']);
    if (!is_readable($pfad)) {
        wp_die('File not found', '', ['response' => 404]);
    }

    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . basename($pfad) . '"');
    header('Content-Length: ' . filesize($pfad));
    readfile($pfad);
    exit;
});

The example assumes mounted storage. Without mounting, you replace readfile() with an SFTP or WebDAV request as described in Use a Storage Server for your website.

The side effect is a pleasant one: because the file never has a public address, nobody can pass the link around. The permission check cannot be bypassed.

What is left on shared hosting

GoalShared hostingYour own server
Backup through a pluginyesyes
Delivering downloads through PHPyes, over WebDAV or SFTPyes
Moving the media library offnoyes, by mounting
rsync or BorgBackupmostly noyes

On shared hosting, WebDAV over HTTPS is the most reliable route, because port 443 is practically never blocked. SFTP works as well, but runs on port 23 with us, and not every provider allows outgoing connections on ports like that. It is worth a quick check before you order.

One sub-account per purpose

Every Storage Server allows up to 100 sub-accounts, each with its own home directory, its own password and its own protocol permissions. For WordPress that means at least two:

  • One account for the website, which only sees /uploads.
  • One account for the backups, which only sees /backup.

If the website is ever taken over, the attacker finds the credentials of the first account in wp-config.php. The backups stay untouched, because that account does not even know about them. With a single main account, everything would be gone at that point.

When several users need space of their own

A Storage Server has no quota per sub-account. An account stays inside its directory, but can fill the entire plan from there. If you want to give customers, photographers or editors a limited allowance each, put an application in front that takes care of it. Nextcloud is the obvious choice, because it comes with users, quotas and share links: Connect Nextcloud to the Storage Server.

Which plan fits

PlanSpaceSub-accountsPrice
Storage-11 TB1009.99 EUR
Storage-25 TB10029.99 EUR
Storage-310 TB10039.99 EUR
Storage-420 TB10069.99 EUR

For a single WordPress site with backups, Storage-1 is usually enough for a long time. If you move the media libraries of several sites off or work with video, you quickly end up at Storage-2 or Storage-3. All plans are located in Germany, come without a setup fee, are billed PrePaid and have no minimum term. Switching to the next larger plan is possible at any time, without touching the data.

Frequently asked questions

Can I move the WordPress media library to a Storage Server with a plugin?
No, at least not reliably. The well-known offloading plugins speak S3 and compatible services only. For SFTP or WebDAV there is no maintained plugin that moves the media library off completely. If you read this and still find a plugin, check its last update date and its number of installations.
So how does it work after all?
On your own server with root rights. There you mount the storage into the file system and put the directory wp-content/uploads on it. WordPress notices nothing of this, for the application it is a perfectly normal path. On shared hosting without root rights this does not work.
What is the easiest benefit?
Backups. A plugin like WPvivid can back up to the storage over SFTP in its free version, which is set up in a quarter of an hour and gives you immediate safety, because the backup no longer sits on the same machine as the website.
Will my images load more slowly because of this?
If you build it wrong, yes. Thumbnails are needed on every page view, and every access over the network costs time. The solution is to keep the originals on the storage and leave the sizes generated by WordPress local, or to cache them.
Can I link downloads directly from the storage?
No, every access to the storage is authenticated. You deliver the file through a small PHP script or a download plugin that checks the permission and passes the file through. That is even an advantage, because nobody can pass the link around.
Which protocol do I use on shared hosting?
WebDAV over HTTPS, because port 443 is practically never blocked. SFTP works as well, but runs on port 23 with us, and some shared hosting providers do not allow outgoing connections on ports like that. It is best to check that beforehand.
Do I need a separate sub-account for every purpose?
It is highly recommended. Every Storage Server allows up to 100 sub-accounts, each with its own directory and its own password. If the website is ever taken over, the attacker does not get to the backups, because the website's account does not even see them.
What about several users who each need their own space?
The storage on its own is not made for that, because there is no quota per sub-account. In that case put Nextcloud in front of it: it comes with users, quotas and shares, and it stores the files on the storage.
Is it worth it for a small website?
For backups yes, always. For the media library only once space on the web server gets tight or expensive. As a rule of thumb: as soon as you start thinking about additional web space, a Storage Server is the cheaper answer.
What does it cost?
Storage-1 with 1 TB costs 9.99 EUR per month, Storage-2 with 5 TB 29.99, Storage-3 with 10 TB 39.99 and Storage-4 with 20 TB 69.99. Located in Germany, no setup fee, PrePaid and with no minimum term.

WordPress Storage Server Mediathek Backup Downloads SFTP WebDAV