Some months ago, a friend came to me asking for advice.
He runs a pretty huge WordPress website. Not just in traffic — but in assets. We’re talking images, PDFs, PSD files, and more, totaling around 240GB.
Originally, everything was hosted on a managed WordPress hosting provider. And as you can imagine, with that much storage and traffic, he had to scale up regularly. Every upgrade meant the monthly bill kept climbing higher and higher.
It was becoming painful.
So I suggested something simple:
Why not offload all static assets to object storage?
Instead of paying premium hosting prices for file storage, we could use something built specifically for it — Amazon S3 or any S3-compatible storage.
We ended up choosing DigitalOcean Spaces.
For just $5/month, you get 250GB of storage. That alone was already a massive win compared to scaling up his managed hosting plan.
Now let’s get into the technical part.
The Tool: S3 Uploads by Human Made
To offload all the assets properly, I used the excellent:
👉 https://github.com/humanmade/S3-Uploads
It’s lightweight, solid, and works beautifully with WP-CLI.
One important requirement:
You must have WP-CLI running on your server.
The setup instructions on the GitHub repo are already very clear, so I’ll just walk through the important parts here.
Step 1: Configure wp-config.php
First, we need to define the Spaces credentials and bucket configuration inside wp-config.php.
define( 'S3_UPLOADS_BUCKET', 'awesomewebsite' );
define( 'S3_UPLOADS_REGION', 'nyc3' );
define( 'S3_UPLOADS_BUCKET_URL', 'https://awesomewebsite.nyc3.digitaloceanspaces.com' );
define( 'S3_UPLOADS_ENDPOINT', 'https://nyc3.digitaloceanspaces.com' );
define( 'S3_UPLOADS_KEY', 'XXX' );
define( 'S3_UPLOADS_SECRET', 'XXX' );
In my case, all assets were placed in the root directory of the Space.
If you prefer to store them inside a subdirectory (for example /foo), you’ll need to adjust the bucket constants like this:
define( 'S3_UPLOADS_BUCKET', 'awesomewebsite/foo' );
define( 'S3_UPLOADS_BUCKET_URL', 'https://awesomewebsite.nyc3.digitaloceanspaces.com/foo' );
Simple enough.
The DigitalOcean Caveat
By default, S3 Uploads is configured for Amazon S3.
DigitalOcean Spaces is S3-compatible, but there’s a small tweak required.
We need to create a must-use plugin (mu-plugin).
Create this file:
wp-content/mu-plugins/s3-offload.php
And paste the following code:
<?php
/**
* Plugin Name: S3 Uploads DigitalOcean Helper
* Plugin URI: https://www.pixeldevs.io
* Description: Helper file to get DigitalOcean Spaces working with S3 Uploads
* Version: 1.0
* Author: PixelDevs
* Author URI: https://www.pixeldevs.io
**/
add_filter( 's3_uploads_s3_client_params', function ( $params ) {
if ( defined( 'S3_UPLOADS_ENDPOINT' ) ) {
$params['endpoint'] = S3_UPLOADS_ENDPOINT;
$params['use_path_style_endpoint'] = true;
$params['debug'] = false;
}
return $params;
}, 5, 1 );
That’s it. This ensures the S3 client talks properly to DigitalOcean Spaces.
Step 2: Activate the Plugin
From your server, run:
wp plugin activate s3-uploads
Now the site is ready to start offloading.
Step 3: Upload Existing Assets
In our case, everything was inside wp-content/uploads
So I ran:
wp s3-uploads upload-directory wp-content/uploads/ uploads
And then… we waited.
Moving hundreds of gigabytes is not instant. It took quite some time to finish. But once it was done, all uploads were living safely inside DigitalOcean Spaces instead of bloating the web server.
And the hosting bill?
Much lower.
Bonus: Cleaning Up the URLs
After everything worked properly, I also rewrote the asset URLs.
Instead of this:
https://awesomewebsite.nyc3.digitaloceanspaces.com/uploads/2025/09/image.jpg
We now serve files via:
https://assets.awesomewebsite.com/2025/09/image.jpg
Much cleaner. More professional. And ready for CDN in front.
But that’s a story for another day 😉
Leave a Reply