{"id":4382,"date":"2026-09-12T16:51:48","date_gmt":"2026-09-12T11:21:48","guid":{"rendered":"https:\/\/cpanelfree.com\/blog\/how-to-offload-wordpress-media-cloudflare-r2-s3\/"},"modified":"2026-09-12T16:52:36","modified_gmt":"2026-09-12T11:22:36","slug":"how-to-offload-wordpress-media-cloudflare-r2-s3","status":"publish","type":"post","link":"https:\/\/cpanelfree.com\/blog\/how-to-offload-wordpress-media-cloudflare-r2-s3\/","title":{"rendered":"How to Offload WordPress Media Library to Cloudflare R2 \/ AWS S3 (Zero Egress)"},"content":{"rendered":"<p>As a WordPress website expands, the single largest consumer of server disk space is never the MariaDB database or core PHP application code\u2014it is the <code>\/wp-content\/uploads\/<\/code> media directory. High-resolution product images, PDF catalogs, podcast audio, and banner graphics quickly accumulate into tens or hundreds of gigabytes of storage on your <a href=\"https:\/\/cpanelfree.com\/\">Linux VPS<\/a>.<\/p>\n<p>This storage bloat creates severe operational hazards: nightly server backups take hours to archive and transfer, disk capacity fills up unexpectedly, and migrating to larger virtual servers becomes an agonizing ordeal. Furthermore, serving heavy static media files directly from your application server consumes valuable web server worker processes that should be reserved for dynamic PHP execution.<\/p>\n<p>By offloading your media library to <strong>Cloudflare R2<\/strong> or <strong>AWS S3<\/strong>, you eliminate storage constraints entirely. Cloudflare R2 provides an S3-compatible object storage API with one game-changing advantage: <strong>zero egress bandwidth fees<\/strong>. In this guide, you will learn how to configure Cloudflare R2 buckets, link custom CDN domains, synchronize historical uploads, and serve media globally at edge speeds.<\/p>\n<h2>1. Why Cloudflare R2 Beats Traditional AWS S3 for WordPress<\/h2>\n<table style=\"width: 100%;border-collapse: collapse;margin: 24px 0\">\n<thead>\n<tr style=\"background: #1e293b;color: #f8fafc;border-bottom: 2px solid #334155\">\n<th style=\"padding: 12px;text-align: left\">Comparison Feature<\/th>\n<th style=\"padding: 12px;text-align: left\">Cloudflare R2<\/th>\n<th style=\"padding: 12px;text-align: left\">Standard AWS S3<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr style=\"border-bottom: 1px solid #334155\">\n<td style=\"padding: 12px;font-weight: bold\">Egress Bandwidth Cost<\/td>\n<td style=\"padding: 12px;color: #10b981;font-weight: bold\">$0.00 \/ GB (100% Free Egress)<\/td>\n<td style=\"padding: 12px;color: #f59e0b\">$0.09 \/ GB (Costly at scale)<\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #334155\">\n<td style=\"padding: 12px;font-weight: bold\">Storage Pricing<\/td>\n<td style=\"padding: 12px;color: #10b981\">$0.015 \/ GB per month<\/td>\n<td style=\"padding: 12px;color: #cbd5e1\">$0.023 \/ GB per month<\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #334155\">\n<td style=\"padding: 12px;font-weight: bold\">Free Monthly Tier<\/td>\n<td style=\"padding: 12px;color: #10b981\">10 GB storage free every month<\/td>\n<td style=\"padding: 12px;color: #cbd5e1\">5 GB free for first 12 months<\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #334155\">\n<td style=\"padding: 12px;font-weight: bold\">API Compatibility<\/td>\n<td style=\"padding: 12px;color: #10b981\">100% S3 API Compatible<\/td>\n<td style=\"padding: 12px;color: #10b981\">Native S3<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>2. Creating the Cloudflare R2 Bucket &amp; Generating API Credentials<\/h2>\n<ol>\n<li>Log in to your <strong>Cloudflare Dashboard<\/strong> and navigate to <strong>R2 &gt; Create bucket<\/strong>.<\/li>\n<li>Name your bucket (e.g., <code>my-site-media-prod<\/code>) and choose <strong>Automatic<\/strong> location hints.<\/li>\n<li>Under <strong>Settings &gt; Public Access<\/strong>, connect a custom domain (such as <code>https:\/\/media.yourdomain.com<\/code>). Cloudflare provisions a free SSL certificate automatically.<\/li>\n<li>In the R2 overview page, click <strong>Manage R2 API Tokens &gt; Create API Token<\/strong>.<\/li>\n<li>Select <strong>Object Read &amp; Write<\/strong> permissions and restrict the scope to your newly created media bucket.<\/li>\n<li>Record the <strong>Access Key ID<\/strong>, <strong>Secret Access Key<\/strong>, and the S3 Endpoint URL (e.g., <code>https:\/\/&lt;account_id&gt;.r2.cloudflarestorage.com<\/code>).<\/li>\n<\/ol>\n<h2>3. Configuring Media Offloading in WordPress<\/h2>\n<p>Install and activate the open-source <strong>Media Cloud<\/strong> or <strong>WP Offload Media Lite<\/strong> plugin via WP-CLI:<\/p>\n<pre><code>wp plugin install media-cloud --activate --allow-root<\/code><\/pre>\n<p>Navigate to <strong>Media Cloud &gt; Storage Settings<\/strong> in your WordPress admin:<\/p>\n<ul>\n<li><strong>Storage Provider:<\/strong> Select <strong>Amazon S3 Compatible<\/strong>.<\/li>\n<li><strong>Access Key:<\/strong> Your Cloudflare R2 Access Key ID.<\/li>\n<li><strong>Secret Key:<\/strong> Your Cloudflare R2 Secret Access Key.<\/li>\n<li><strong>Bucket Name:<\/strong> <code>my-site-media-prod<\/code><\/li>\n<li><strong>Custom Endpoint:<\/strong> <code>https:\/\/&lt;account_id&gt;.r2.cloudflarestorage.com<\/code><\/li>\n<li><strong>Path Style URLs:<\/strong> Enabled.<\/li>\n<li><strong>Custom Domain (CDN):<\/strong> <code>https:\/\/media.yourdomain.com<\/code><\/li>\n<\/ul>\n<h2>4. Synchronizing Historical Media Uploads<\/h2>\n<p>To offload existing historical media files without timing out your web browser, execute the batch migration command directly via the terminal using the AWS CLI tool:<\/p>\n<pre><code># Install AWS CLI\nsudo apt install -y awscli\n\n# Configure temporary R2 credentials\nexport AWS_ACCESS_KEY_ID=\"YOUR_R2_ACCESS_KEY\"\nexport AWS_SECRET_ACCESS_KEY=\"YOUR_R2_SECRET_KEY\"\nexport AWS_DEFAULT_REGION=\"auto\"\n\n# Sync local \/uploads folder to Cloudflare R2 bucket\naws s3 sync \/var\/www\/my-site\/wp-content\/uploads\/ s3:\/\/my-site-media-prod\/uploads\/   --endpoint-url https:\/\/&lt;account_id&gt;.r2.cloudflarestorage.com   --cache-control \"max-age=31536000,public\"<\/code><\/pre>\n<p>Once all historical assets have uploaded, run the database media replacement tool inside Media Cloud to update image references in <code>wp_posts<\/code> from local paths to your new <code>https:\/\/media.yourdomain.com<\/code> CDN URL.<\/p>\n<h2>5. Purging Local Uploads &amp; Slashing Backup Sizes<\/h2>\n<p>Once you verify that all media files load cleanly from your R2 CDN domain, enable the <strong>&#8220;Delete Local Media After Upload&#8221;<\/strong> setting in Media Cloud. Now, whenever an editor uploads an image, WordPress generates thumbnail sizes, pushes all files to R2, and deletes the local copies from your server.<\/p>\n<p>Your server&#8217;s daily backup archive shrinks from 50GB down to a lightweight 150MB database and code package that takes only 10 seconds to back up and transfer offsite!<\/p>\n<h2>Cloudflare R2 Media Offloading: Caching Rules &amp; SEO Image Optimization<\/h2>\n<p>Maximizing the benefits of offloading WordPress media to Cloudflare R2 requires configuring intelligent edge caching and image delivery rules:<\/p>\n<ul>\n<li><strong>Configuring Cloudflare Edge Cache Rules for Media:<\/strong> By default, Cloudflare caches media files according to origin response headers. To ensure maximum global cache hit ratios, create a Cache Rule in the Cloudflare Dashboard matching your custom media subdomain (<code>media.yourdomain.com\/*<\/code>):\n<ul>\n<li><strong>Edge TTL:<\/strong> Respect origin or set to 1 Year (31,536,000 seconds).<\/li>\n<li><strong>Browser TTL:<\/strong> Set to 1 Month.<\/li>\n<li><strong>Cache Everything:<\/strong> Ensures all images, PDFs, and assets are permanently cached at the nearest edge PoP.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Automating WebP and AVIF Image Delivery:<\/strong> Pair your Cloudflare R2 media subdomain with Cloudflare Polish or an automated image converter. This dynamically delivers next-generation AVIF and WebP image formats to supported browsers, shrinking image payloads by an additional 50\u201370% without altering origin files.<\/li>\n<li><strong>Securing S3 API Credentials in WordPress:<\/strong> Never store your Cloudflare R2 Access Key ID and Secret Access Key in the WordPress database where rogue administrators or malicious plugins could read them. Instead, define them as immutable constants in <code>wp-config.php<\/code>:\n<pre><code>define('CLOUDFLARE_R2_ACCESS_KEY', 'your_r2_access_key_here');\ndefine('CLOUDFLARE_R2_SECRET_KEY', 'your_r2_secret_key_here');<\/code><\/pre>\n<\/li>\n<\/ul>\n<div style=\"background: #0f172a;border-left: 4px solid #10b981;padding: 20px;border-radius: 8px;margin: 24px 0\">\n<h4 style=\"color: #10b981;margin-top: 0\">Disaster Recovery Advantage of Zero-Egress Storage<\/h4>\n<p style=\"color: #cbd5e1;margin-bottom: 0\">Because Cloudflare R2 charges zero bandwidth egress fees, you can download, sync, or migrate terabytes of media archives as frequently as needed without worrying about surprise cloud billing. Your storage costs remain predictable, transparent, and manageable.<\/p>\n<\/div>\n<div style=\"background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);border: 1px solid #334155;border-radius: 12px;padding: 28px;margin: 36px 0;text-align: center\">\n<h3 style=\"color: #38bdf8;margin-top: 0;font-size: 22px\">Run Lean, Lightning-Fast WordPress on CpanelFree<\/h3>\n<p style=\"color: #cbd5e1;font-size: 16px;line-height: 1.6;max-width: 680px;margin: 12px auto 24px auto\">Offload heavy media to the cloud while keeping your application execution blazingly fast on CpanelFree high-speed hosting infrastructure.<\/p>\n<p>    <a href=\"https:\/\/cpanelfree.com\/\" style=\"background: #38bdf8;color: #0f172a;font-weight: 700;padding: 12px 28px;border-radius: 6px;text-decoration: none;display: inline-block;font-size: 15px\">Discover CpanelFree Web Hosting Plans &rarr;<\/a>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>As a WordPress website expands, the single largest consumer of server disk space is never the MariaDB database or core PHP application code\u2014it is the \/wp-content\/uploads\/ media directory. High-resolution product images, PDF catalogs, podcast audio, and banner graphics quickly accumulate into tens or hundreds of gigabytes of storage on your Linux VPS. This storage bloat &#8230; <a title=\"How to Offload WordPress Media Library to Cloudflare R2 \/ AWS S3 (Zero Egress)\" class=\"read-more\" href=\"https:\/\/cpanelfree.com\/blog\/how-to-offload-wordpress-media-cloudflare-r2-s3\/\" aria-label=\"Read more about How to Offload WordPress Media Library to Cloudflare R2 \/ AWS S3 (Zero Egress)\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":4381,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4382","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-hosting-news"],"_links":{"self":[{"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/posts\/4382","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/comments?post=4382"}],"version-history":[{"count":1,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/posts\/4382\/revisions"}],"predecessor-version":[{"id":4391,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/posts\/4382\/revisions\/4391"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/media\/4381"}],"wp:attachment":[{"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/media?parent=4382"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/categories?post=4382"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/tags?post=4382"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}