{"id":306382,"date":"2026-09-25T16:03:48","date_gmt":"2026-09-25T16:03:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/dilux-cloud-storage\/"},"modified":"2026-10-08T19:27:30","modified_gmt":"2026-10-08T19:27:30","slug":"diluxone-offload","status":"publish","type":"plugin","link":"https:\/\/bal.wordpress.org\/plugins\/diluxone-offload\/","author":13017021,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"2.1.0","stable_tag":"2.1.0","tested":"7.1.3","requires":"5.1","requires_php":"7.4","requires_plugins":null,"header_name":"DiluxOne Offload \u2013 Media Storage","header_author":"Pablo Ariel Di Loreto","header_description":"Move your WordPress media to cloud object storage and serve it from there. Replaces \/uploads\/ transparently via a PHP stream wrapper.","assets_banners_color":"fbfbfb","last_updated":"2026-10-08 19:27:30","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/DiluxOne\/diluxone-offload-wordpress","header_author_uri":"https:\/\/diluxone.com\/plugins-wordpress","rating":0,"author_block_rating":0,"active_installs":0,"downloads":185,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"pablodiloreto","date":"2026-09-25 16:03:18","revision":3713296},"2.0.0":{"tag":"2.0.0","author":"pablodiloreto","date":"2026-09-28 00:01:31","revision":3716156},"2.1.0":{"tag":"2.1.0","author":"pablodiloreto","date":"2026-10-08 19:27:30","revision":3735407}},"upgrade_notice":{"1.0.0":"<p>First public release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3713296,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3713296,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3713296,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3713296,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","2.0.0","2.1.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3735407,"resolution":"1","location":"assets","locale":"","width":1600,"height":900},"screenshot-10.png":{"filename":"screenshot-10.png","revision":3735407,"resolution":"10","location":"assets","locale":"","width":1600,"height":900},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3735407,"resolution":"2","location":"assets","locale":"","width":1600,"height":900},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3735407,"resolution":"3","location":"assets","locale":"","width":1600,"height":900},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3735407,"resolution":"4","location":"assets","locale":"","width":1600,"height":900},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3735407,"resolution":"5","location":"assets","locale":"","width":1600,"height":900},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3735407,"resolution":"6","location":"assets","locale":"","width":1600,"height":900},"screenshot-7.png":{"filename":"screenshot-7.png","revision":3735407,"resolution":"7","location":"assets","locale":"","width":1600,"height":900},"screenshot-8.png":{"filename":"screenshot-8.png","revision":3735407,"resolution":"8","location":"assets","locale":"","width":1600,"height":900},"screenshot-9.png":{"filename":"screenshot-9.png","revision":3735407,"resolution":"9","location":"assets","locale":"","width":1600,"height":900}},"screenshots":{"1":"Overview: provider configured, media synced, offloading active.","2":"Cloud Provider \u203a Connection: choosing Azure Blob Storage.","3":"Cloud Provider \u203a Connection: entering the storage account, key and container, and testing the connection.","4":"Provider saved and ready to sync.","5":"Sync &amp; Offloading \u203a Sync: the first sync, file by file, in the browser.","6":"Sync complete: enable offloading now or later.","7":"Sync &amp; Offloading \u203a Offloading: offloading active, with the local copies to delete.","8":"Settings \u203a Transfers: file-size limit and transfer timeout.","9":"Status \u203a Health: plugin state and connection health at a glance.","10":"Cloud Provider \u203a Connection: S3-compatible storage, with the service filling in the endpoint and the public URL."}},"plugin_section":[],"plugin_tags":[13289,10725,46891,217,85],"plugin_category":[50],"plugin_contributors":[181787],"plugin_business_model":[],"class_list":["post-306382","plugin","type-plugin","status-publish","hentry","plugin_tags-azure","plugin_tags-cloud-storage","plugin_tags-offload","plugin_tags-s3","plugin_tags-uploads","plugin_category-media","plugin_contributors-pablodiloreto","plugin_committers-pablodiloreto"],"banners":{"banner":"https:\/\/ps.w.org\/diluxone-offload\/assets\/banner-772x250.png?rev=3713296","banner_2x":"https:\/\/ps.w.org\/diluxone-offload\/assets\/banner-1544x500.png?rev=3713296","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/diluxone-offload\/assets\/icon-128x128.png?rev=3713296","icon_2x":"https:\/\/ps.w.org\/diluxone-offload\/assets\/icon-256x256.png?rev=3713296","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-1.png?rev=3735407","caption":"Overview: provider configured, media synced, offloading active."},{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-2.png?rev=3735407","caption":"Cloud Provider \u203a Connection: choosing Azure Blob Storage."},{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-3.png?rev=3735407","caption":"Cloud Provider \u203a Connection: entering the storage account, key and container, and testing the connection."},{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-4.png?rev=3735407","caption":"Provider saved and ready to sync."},{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-5.png?rev=3735407","caption":"Sync &amp; Offloading \u203a Sync: the first sync, file by file, in the browser."},{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-6.png?rev=3735407","caption":"Sync complete: enable offloading now or later."},{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-7.png?rev=3735407","caption":"Sync &amp; Offloading \u203a Offloading: offloading active, with the local copies to delete."},{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-8.png?rev=3735407","caption":"Settings \u203a Transfers: file-size limit and transfer timeout."},{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-9.png?rev=3735407","caption":"Status \u203a Health: plugin state and connection health at a glance."},{"src":"https:\/\/ps.w.org\/diluxone-offload\/assets\/screenshot-10.png?rev=3735407","caption":"Cloud Provider \u203a Connection: S3-compatible storage, with the service filling in the endpoint and the public URL."}],"raw_content":"<!--section=description-->\n<p>DiluxOne Offload moves your WordPress media library to Azure Blob Storage or to any S3-compatible service (Amazon S3, Cloudflare R2, Backblaze B2, DigitalOcean Spaces, Wasabi, Google Cloud Storage, Hetzner, Akamai (Linode), Vultr, Scaleway, OVHcloud, IDrive e2, MinIO) and serves files directly from the cloud \u2014 without breaking the Media Library UI, plugins, or existing content.<\/p>\n\n<p>The plugin uses a custom PHP stream wrapper to intercept every read and write to <code>\/wp-content\/uploads\/<\/code>, so WordPress, WooCommerce, page builders, image editors, and any plugin that calls standard filesystem functions (<code>fopen<\/code>, <code>file_get_contents<\/code>, <code>unlink<\/code>, etc.) keep working unchanged.<\/p>\n\n<h4>Key features<\/h4>\n\n<ul>\n<li><strong>Azure Blob Storage or S3-compatible storage<\/strong> \u2014 bring your own storage account or bucket; nothing is shared with anyone else. For S3-compatible services, pick the service and the plugin fills in the endpoint and the public URL; a CDN or a custom domain goes in the Public URL field.<\/li>\n<li><strong>Transparent stream wrapper<\/strong> \u2014 no URL rewriting, no regex on post content, no database migration required for URLs.<\/li>\n<li><strong>Sync with resumable state machine<\/strong> \u2014 start, cancel, resume after an interruption, retry failed files, resync from scratch.<\/li>\n<li><strong>Offloading mode<\/strong> \u2014 after a successful sync you can delete the local copies to free disk space; the stream wrapper keeps everything working.<\/li>\n<li><strong>Connection health monitoring<\/strong> \u2014 when the cloud is unreachable, new uploads are refused with a clear error instead of landing somewhere else, and a banner on the plugin's admin pages says why until it recovers.<\/li>\n<li><strong>No plugin data on disk<\/strong> \u2014 no cache, log or data files anywhere on the server. The one time the plugin writes to the uploads directory is when you disconnect, to copy your own media back to where WordPress expects it.<\/li>\n<li><strong>Large files don't need large memory<\/strong> \u2014 a download goes straight to disk, and an upload is sent in blocks (4 MiB on Azure, 5 MiB parts on S3-compatible services, larger only for a file too big for the service's limit on parts, past about 5 GB on Scaleway or 48 GB elsewhere), so PHP never holds more than one block of a file at a time and a video does not trip <code>memory_limit<\/code>.<\/li>\n<li><strong>Multisite aware<\/strong> \u2014 network activation supported; each site keeps its own configuration and file tracking, and its objects live under their own prefix in the container or bucket (<code>uploads\/<\/code> for the main site, <code>uploads\/sites\/&lt;id&gt;\/<\/code> for the others, the same layout WordPress uses on disk), so several sites can share one container or bucket without ever sharing a key.<\/li>\n<li><strong>Quiet by default<\/strong> \u2014 with <code>WP_DEBUG<\/code> off and the Settings toggle off the plugin writes nothing to the PHP error log, at any level. <code>WP_DEBUG<\/code> turns on errors and warnings; the toggle adds the informational lines.<\/li>\n<\/ul>\n\n<h4>Why a stream wrapper instead of URL rewriting<\/h4>\n\n<p>Most offload plugins rewrite media URLs in post content, which breaks when you switch providers, move domains, or restore from a backup. DiluxOne Offload leaves URLs alone and rewrites reads\/writes at the filesystem layer, so your content stays portable.<\/p>\n\n<h4>Known limitations<\/h4>\n\n<ul>\n<li>The media must be publicly readable where it is stored: on Azure, a container whose public access level is <em>Blob<\/em>; on S3-compatible services, a bucket that lets anyone read its objects. <strong>Test Connection<\/strong> checks it and refuses a private one.<\/li>\n<li>The initial sync runs in your browser tab and stops if you close it; it resumes where it left off. Nothing runs in the background or via cron.<\/li>\n<li>Files above the <strong>Maximum File Size<\/strong> setting (20 MB by default, up to 500 MB) are skipped by the initial sync.<\/li>\n<li>While the cloud is unreachable, new uploads fail. There is deliberately no local fallback.<\/li>\n<li>On Azure, media is served from the storage account's URL; on S3-compatible services the Public URL field is where a CDN or custom domain goes.<\/li>\n<li><strong>Disconnect from Cloud<\/strong> needs a writable uploads directory and enough disk for your media.<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>This plugin connects to one cloud storage service, the one you choose: Azure Blob Storage, or an S3-compatible service (Amazon S3, Cloudflare R2, Backblaze B2, DigitalOcean Spaces, Wasabi, Google Cloud Storage, Hetzner Object Storage, Akamai (Linode) Object Storage, Vultr Object Storage, Scaleway Object Storage, OVHcloud Object Storage, IDrive e2, or a server whose address you type). It uses it to store and serve your media files. <strong>Nothing is sent anywhere until you configure it yourself<\/strong> in the <em>Cloud Provider<\/em> tab, with an account and credentials you supply. The plugin contacts no other service: it sends no telemetry, no usage data and no licence check to the author or to anyone else.<\/p>\n\n<h4>Azure Blob Storage<\/h4>\n\n<p>What it is used for: storing your WordPress media files outside your server and serving them from the cloud.<\/p>\n\n<p>Where requests go: the Azure Blob REST API at blob.core.windows.net \u2014 specifically your own account's host, <code>https:\/\/ACCOUNT.blob.core.windows.net<\/code>, where ACCOUNT is the storage account name you enter in the settings.<\/p>\n\n<p>What data is sent: your media files themselves, together with their relative path, size and MIME type. The storage account key you entered never leaves your server \u2014 it is used locally to compute the signature that authenticates each request. No personal data about your visitors or your site's users is sent, and nothing at all about your site reaches the plugin's author.<\/p>\n\n<p>When requests happen:<\/p>\n\n<ul>\n<li>During the initial sync \u2014 uploading existing files from <code>\/wp-content\/uploads\/<\/code> to your container.<\/li>\n<li>On every new media upload \u2014 writing the file to the cloud through the stream wrapper.<\/li>\n<li>On read or delete \u2014 when WordPress, or any plugin using filesystem APIs against <code>\/uploads\/<\/code>, reads or deletes a file. This is also the only front-end traffic: a form or a review that uploads a file goes through the same stream wrapper.<\/li>\n<li>When the plugin lists your container \u2014 for the Overview statistics (cached for five minutes) and for the scan that precedes <strong>Disconnect from Cloud<\/strong>.<\/li>\n<li>A connection-health check \u2014 a small GET for your container's properties \u2014 when you open one of the plugin's admin pages, at most once every 5 minutes, and again from a write that follows three consecutive failures, so uploads resume on their own when the cloud is back. Nothing runs via cron.<\/li>\n<li>During <strong>Disconnect from Cloud<\/strong> \u2014 downloading your files back to the server.<\/li>\n<\/ul>\n\n<p>This is <strong>your own Azure account<\/strong>, under your own agreement with Microsoft. Neither DiluxOne nor the plugin's author is a party to it and neither has any access to your data. Your use of the service is subject to Microsoft's terms:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/azure.microsoft.com\/services\/storage\/blobs\/\">Azure Blob Storage<\/a> (https:\/\/azure.microsoft.com\/services\/storage\/blobs\/)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/azure.microsoft.com\/support\/legal\/\">Microsoft Azure Legal Information<\/a> (https:\/\/azure.microsoft.com\/support\/legal\/), which links the Microsoft Products and Services Agreement and the Online Services Terms<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.microsoft.com\/privacy\/privacystatement\">Microsoft Privacy Statement<\/a> (https:\/\/www.microsoft.com\/privacy\/privacystatement)<\/li>\n<\/ul>\n\n<h4>S3-compatible storage<\/h4>\n\n<p>What it is used for: the same as above, on the S3-compatible service you choose.<\/p>\n\n<p>Where requests go: the endpoint of the service you chose, which the form fills in for each service and you can change: Amazon S3 at <code>https:\/\/s3.REGION.amazonaws.com<\/code> (requests address <code>https:\/\/BUCKET.s3.REGION.amazonaws.com<\/code>), Cloudflare R2 at <code>https:\/\/ACCOUNT_ID.r2.cloudflarestorage.com<\/code>, Backblaze B2 at <code>https:\/\/s3.REGION.backblazeb2.com<\/code>, DigitalOcean Spaces at <code>https:\/\/REGION.digitaloceanspaces.com<\/code>, Wasabi at <code>https:\/\/s3.REGION.wasabisys.com<\/code>, Google Cloud Storage at <code>https:\/\/storage.googleapis.com<\/code>, Hetzner Object Storage at <code>https:\/\/REGION.your-objectstorage.com<\/code>, Akamai (Linode) Object Storage at <code>https:\/\/REGION.linodeobjects.com<\/code>, Vultr Object Storage at <code>https:\/\/REGION.vultrobjects.com<\/code>, Scaleway Object Storage at <code>https:\/\/s3.REGION.scw.cloud<\/code>, OVHcloud Object Storage at <code>https:\/\/s3.REGION.io.cloud.ovh.net<\/code>, IDrive e2 at <code>https:\/\/s3.REGION.idrivee2.com<\/code> (or the endpoint of your own its dashboard shows), or the address you type under Custom. Browsers load your media from the Public URL you set, which can be the service's own address, a CDN or a custom domain.<\/p>\n\n<p>What data is sent: your media files themselves, together with their relative path (the object key), size and MIME type, and a signature of each request computed from your secret access key. The secret itself never leaves your server. No personal data about your visitors or your site's users is sent, and nothing at all about your site reaches the plugin's author.<\/p>\n\n<p>When requests happen: the same moments as for Azure above. The connection check is different: when you press <strong>Test Connection<\/strong>, and at most every five minutes while you browse the plugin's admin pages, the plugin writes a 32-byte probe object under your site's prefix, reads it back from the Public URL without credentials (to prove browsers can load your media) and deletes it.<\/p>\n\n<p>This is <strong>your own account<\/strong> with that service, under your own agreement with its provider. Neither DiluxOne nor the plugin's author is a party to it and neither has any access to your data. Your use of the service is subject to its provider's terms:<\/p>\n\n<p>Amazon S3:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/aws.amazon.com\/s3\/\">Amazon S3<\/a> (https:\/\/aws.amazon.com\/s3\/)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/aws.amazon.com\/service-terms\/\">AWS Service Terms<\/a> (https:\/\/aws.amazon.com\/service-terms\/)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/aws.amazon.com\/privacy\/\">AWS Privacy Notice<\/a> (https:\/\/aws.amazon.com\/privacy\/)<\/li>\n<\/ul>\n\n<p>Cloudflare R2:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/www.cloudflare.com\/products\/r2\/\">Cloudflare R2<\/a> (https:\/\/www.cloudflare.com\/products\/r2\/)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/www.cloudflare.com\/terms\/\">Cloudflare Terms<\/a> (https:\/\/www.cloudflare.com\/terms\/)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.cloudflare.com\/privacypolicy\/\">Cloudflare Privacy Policy<\/a> (https:\/\/www.cloudflare.com\/privacypolicy\/)<\/li>\n<\/ul>\n\n<p>Backblaze B2:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/www.backblaze.com\/cloud-storage\">Backblaze B2<\/a> (https:\/\/www.backblaze.com\/cloud-storage)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/www.backblaze.com\/company\/policy\/terms-of-service\">Backblaze Terms of Service<\/a> (https:\/\/www.backblaze.com\/company\/policy\/terms-of-service)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.backblaze.com\/company\/policy\/privacy\">Backblaze Privacy Notice<\/a> (https:\/\/www.backblaze.com\/company\/policy\/privacy)<\/li>\n<\/ul>\n\n<p>DigitalOcean Spaces:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/www.digitalocean.com\/products\/spaces\">DigitalOcean Spaces<\/a> (https:\/\/www.digitalocean.com\/products\/spaces)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/www.digitalocean.com\/legal\/terms-of-service-agreement\">DigitalOcean Terms of Service<\/a> (https:\/\/www.digitalocean.com\/legal\/terms-of-service-agreement)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.digitalocean.com\/legal\/privacy-policy\">DigitalOcean Privacy Policy<\/a> (https:\/\/www.digitalocean.com\/legal\/privacy-policy)<\/li>\n<\/ul>\n\n<p>Wasabi:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/wasabi.com\/cloud-object-storage\">Wasabi<\/a> (https:\/\/wasabi.com\/cloud-object-storage)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/wasabi.com\/legal\/terms-of-use\">Wasabi Terms of Use<\/a> (https:\/\/wasabi.com\/legal\/terms-of-use)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/wasabi.com\/legal\/privacy-policy\">Wasabi Privacy Policy<\/a> (https:\/\/wasabi.com\/legal\/privacy-policy)<\/li>\n<\/ul>\n\n<p>Google Cloud Storage:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/cloud.google.com\/storage\">Google Cloud Storage<\/a> (https:\/\/cloud.google.com\/storage)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/cloud.google.com\/terms\">Google Cloud Terms of Service<\/a> (https:\/\/cloud.google.com\/terms)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/policies.google.com\/privacy\">Google Privacy Policy<\/a> (https:\/\/policies.google.com\/privacy)<\/li>\n<\/ul>\n\n<p>Hetzner Object Storage:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/www.hetzner.com\/storage\/object-storage\/\">Hetzner Object Storage<\/a> (https:\/\/www.hetzner.com\/storage\/object-storage\/)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/www.hetzner.com\/legal\/terms-and-conditions\/\">Hetzner Terms and Conditions<\/a> (https:\/\/www.hetzner.com\/legal\/terms-and-conditions\/)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.hetzner.com\/legal\/privacy-policy\/\">Hetzner Privacy Policy<\/a> (https:\/\/www.hetzner.com\/legal\/privacy-policy\/)<\/li>\n<\/ul>\n\n<p>Akamai (Linode) Object Storage:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/www.linode.com\/products\/object-storage\/\">Akamai Object Storage<\/a> (https:\/\/www.linode.com\/products\/object-storage\/)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/www.linode.com\/legal\/msa\/\">Akamai Cloud Master Service Agreement<\/a> (https:\/\/www.linode.com\/legal\/msa\/)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.akamai.com\/legal\/privacy-statement\">Akamai Privacy Statement<\/a> (https:\/\/www.akamai.com\/legal\/privacy-statement)<\/li>\n<\/ul>\n\n<p>Vultr Object Storage:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/www.vultr.com\/products\/object-storage\/\">Vultr Object Storage<\/a> (https:\/\/www.vultr.com\/products\/object-storage\/)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/www.vultr.com\/legal\/tos\/\">Vultr Terms of Service<\/a> (https:\/\/www.vultr.com\/legal\/tos\/)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.vultr.com\/legal\/privacy\/\">Vultr Privacy Policy<\/a> (https:\/\/www.vultr.com\/legal\/privacy\/)<\/li>\n<\/ul>\n\n<p>Scaleway Object Storage:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/www.scaleway.com\/en\/object-storage\/\">Scaleway Object Storage<\/a> (https:\/\/www.scaleway.com\/en\/object-storage\/)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/www.scaleway.com\/en\/contracts\/\">Scaleway Contracts<\/a> (https:\/\/www.scaleway.com\/en\/contracts\/)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.scaleway.com\/en\/privacy-policy\/\">Scaleway Privacy Policy<\/a> (https:\/\/www.scaleway.com\/en\/privacy-policy\/)<\/li>\n<\/ul>\n\n<p>OVHcloud Object Storage:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/www.ovhcloud.com\/en\/public-cloud\/object-storage\/\">OVHcloud Object Storage<\/a> (https:\/\/www.ovhcloud.com\/en\/public-cloud\/object-storage\/)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/www.ovhcloud.com\/en\/terms-and-conditions\/contracts\/\">OVHcloud Contracts<\/a> (https:\/\/www.ovhcloud.com\/en\/terms-and-conditions\/contracts\/)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.ovhcloud.com\/en\/terms-and-conditions\/privacy-policy\/\">OVHcloud Privacy Policy<\/a> (https:\/\/www.ovhcloud.com\/en\/terms-and-conditions\/privacy-policy\/)<\/li>\n<\/ul>\n\n<p>IDrive e2:<\/p>\n\n<ul>\n<li>Service: <a href=\"https:\/\/www.idrive.com\/s3-storage-e2\/\">IDrive e2<\/a> (https:\/\/www.idrive.com\/s3-storage-e2\/)<\/li>\n<li>Terms of Service: <a href=\"https:\/\/www.idrive.com\/s3-storage-e2\/terms\">IDrive e2 Terms<\/a> (https:\/\/www.idrive.com\/s3-storage-e2\/terms)<\/li>\n<li>Privacy Policy: <a href=\"https:\/\/www.idrive.com\/privacy\">IDrive Privacy Policy<\/a> (https:\/\/www.idrive.com\/privacy)<\/li>\n<\/ul>\n\n<p>Custom endpoint: the plugin talks only to the server whose address you typed (MinIO, Ceph or any other that speaks the S3 API). No third party is involved unless that server belongs to one you chose.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>diluxone-offload<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install via the WordPress Plugins screen.<\/li>\n<li>Activate the plugin through the <strong>Plugins<\/strong> screen in WordPress.<\/li>\n<li>Open the new <strong>DiluxOne Offload<\/strong> menu in the admin sidebar.<\/li>\n<li>Go to <strong>Cloud Provider<\/strong>, select Microsoft Azure Blob Storage (enter the storage account, container and access key) or S3-compatible storage (pick the service, then enter the region, bucket, keys and, if it is not filled in, the public URL), and click <strong>Test Connection<\/strong>.<\/li>\n<li>Save the configuration.<\/li>\n<li>Go to <strong>Sync &amp; Offloading<\/strong>, run the initial sync, and enable offloading when sync is complete.<\/li>\n<\/ol>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>WordPress 5.1 or higher.<\/li>\n<li>PHP 7.4 or higher.<\/li>\n<li><code>ext-curl<\/code> and <code>ext-openssl<\/code> enabled.<\/li>\n<li>A writable uploads directory only for <strong>Disconnect from Cloud<\/strong>, when your media is copied back. Transfers use the PHP temporary directory for their scratch files, never <code>uploads\/<\/code>.<\/li>\n<li>An Azure Blob Storage account, a container whose public access level is <strong>Blob<\/strong> (anonymous read access for blobs, so browsers can load your media straight from it), and the account's access key; or a bucket on an S3-compatible service that lets anyone read its objects, and an access key pair allowed to put, get, delete and list objects in it. <strong>Test Connection<\/strong> refuses a private container or bucket and says so.<\/li>\n<\/ul>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20modify%20my%20existing%20media%20urls%20in%20the%20database%3F\"><h3>Does this plugin modify my existing media URLs in the database?<\/h3><\/dt>\n<dd><p>No. The stream wrapper intercepts filesystem calls transparently \u2014 your post content, the <code>wp_posts<\/code> table, and the <code>wp_postmeta<\/code> table are never rewritten.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20the%20cloud%20is%20temporarily%20unreachable%3F\"><h3>What happens if the cloud is temporarily unreachable?<\/h3><\/dt>\n<dd><p>The plugin monitors connection health. While the cloud is unreachable, a new upload fails with WordPress's own \"could not be moved\" error and nothing is saved anywhere, so you never end up with a file that looks uploaded but isn't. A banner on the plugin's admin pages explains the failure. Files already in the cloud keep being served from the storage account URL. The plugin re-checks the connection at most every five minutes and uploads resume on their own once it is back.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20write%20any%20files%20to%20my%20server%3F\"><h3>Does the plugin write any files to my server?<\/h3><\/dt>\n<dd><p>Not for itself: it has no cache, log or data files on disk; everything it needs lives in the WordPress options table and its own database table. Your media is written by WordPress core through the plugin's stream wrapper to the cloud, passing through a temporary file in the PHP temp directory that is deleted right after the upload.<\/p>\n\n<p>The one operation that writes to the server is <strong>Sync &amp; Offloading \u2192 Disconnect from Cloud<\/strong>. It copies your media back from the container to the exact uploads-directory paths WordPress has on record (resolved at runtime with <code>wp_upload_dir()<\/code>), so the Media Library works again without the plugin. It restores only what sits under the <code>uploads\/<\/code> prefix of your own container, never a script or executable file name (PHP, JavaScript, HTML, shell or Windows executables) whatever put it there, and it runs only when you click it.<\/p><\/dd>\n<dt id=\"what%20if%20the%20container%20or%20bucket%20already%20holds%20files%3F\"><h3>What if the container or bucket already holds files?<\/h3><\/dt>\n<dd><p>Before the first sync, Sync &amp; Offloading \u203a Sync looks under this site's folder in it (<code>uploads\/<\/code>, or <code>uploads\/sites\/&lt;id&gt;\/<\/code> for a site of a network). If something is there, from an earlier install or a staging copy, it says how many files and how much, and lets you continue with them, empty that folder (you type the container's or bucket's name to confirm) or connect another one. Emptying deletes only this site's folder, never anything else in the container or bucket, and only before the first sync.<\/p><\/dd>\n<dt id=\"can%20i%20move%20to%20another%20storage%20account%20or%20bucket%20later%3F\"><h3>Can I move to another storage account or bucket later?<\/h3><\/dt>\n<dd><p>Yes, including from Azure to an S3-compatible service or back. Remove the current provider configuration from the admin, enter the new account, container or bucket, run a full resync, and the plugin starts serving from the new location. No URL rewriting required.<\/p><\/dd>\n<dt id=\"will%20this%20work%20with%20woocommerce%20%2F%20elementor%20%2F%20image%20editors%3F\"><h3>Will this work with WooCommerce \/ Elementor \/ image editors?<\/h3><\/dt>\n<dd><p>Yes. Because the stream wrapper operates at the filesystem layer, any plugin that reads or writes files under <code>\/uploads\/<\/code> using standard PHP functions works unchanged.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20delete%20my%20local%20files%20automatically%3F\"><h3>Does the plugin delete my local files automatically?<\/h3><\/dt>\n<dd><p>Only if you explicitly opt in. After a successful sync you can click <strong>Delete Local Files<\/strong> in Sync &amp; Offloading \u203a Offloading. Until you do that, files are kept in both locations. A file that is empty (0 bytes) when the sync scans it is skipped: it is neither uploaded nor tracked, so <strong>Delete Local Files<\/strong> leaves it alone.<\/p><\/dd>\n<dt id=\"if%20i%20delete%20a%20file%20from%20the%20media%20library%2C%20is%20it%20deleted%20from%20the%20cloud%20too%3F\"><h3>If I delete a file from the Media Library, is it deleted from the cloud too?<\/h3><\/dt>\n<dd><p>Yes, while offloading is active: the stream wrapper turns the deletion into a delete on your container, thumbnails included. If you have synced but not yet enabled offloading, WordPress deletes only the local copy; the copy already in your container is not removed automatically.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20i%20uninstall%20the%20plugin%3F\"><h3>What happens when I uninstall the plugin?<\/h3><\/dt>\n<dd><p>Deleting the plugin from the Plugins screen removes everything it created in your database: its options (all prefixed <code>diluxone_offload_<\/code>), its transients and its file-tracking table (<code>diluxone_offload_files<\/code>, with your table prefix) \u2014 on every site of a network. Deactivating alone keeps all of that, so you can deactivate and reactivate without losing your configuration.<\/p>\n\n<p>Your media files are never touched by uninstalling: whatever is in <code>\/wp-content\/uploads\/<\/code> stays there, and whatever is in your container stays in your container. The only thing uninstalling cancels in the storage is an S3 multipart upload the sync left unfinished, which could no longer be completed and would keep being billed. If offloading was active and local copies had been deleted, download them first with <strong>Sync &amp; Offloading \u2192 Disconnect from Cloud<\/strong>, otherwise WordPress will be pointing at files that are no longer on the server.<\/p><\/dd>\n<dt id=\"how%20do%20i%20enable%20verbose%20debug%20logging%3F\"><h3>How do I enable verbose debug logging?<\/h3><\/dt>\n<dd><p>Go to <strong>DiluxOne Offload \u2192 Settings \u2192 Enable detailed debug logging<\/strong>. Logs are written to the standard PHP <code>error_log<\/code> destination. Disable it in production unless you are actively troubleshooting \u2014 it may impact performance.<\/p>\n\n<p>With that setting off and <code>WP_DEBUG<\/code> off, the plugin writes nothing to the PHP error log at all, at any level. With <code>WP_DEBUG<\/code> on it writes errors and warnings; the setting adds the rest.<\/p><\/dd>\n<dt id=\"is%20the%20plugin%20multisite%20compatible%3F\"><h3>Is the plugin multisite compatible?<\/h3><\/dt>\n<dd><p>Yes. It can be network-activated; each site then has its own Cloud Provider configuration and its own file-tracking table, so different sites can use different providers, containers or buckets \u2014 or share one: a site's objects are stored under <code>uploads\/sites\/&lt;id&gt;\/<\/code> (the main site under <code>uploads\/<\/code>), and each site only ever lists, syncs and restores its own prefix.<\/p><\/dd>\n<dt id=\"how%20are%20my%20credentials%20stored%3F\"><h3>How are my credentials stored?<\/h3><\/dt>\n<dd><p>The Azure access key and the S3 secret access key are encrypted with AES-256-GCM before they are written to the WordPress options table (the S3 access key ID, like a user name, is not a secret and is stored as it is). The encryption key is derived from your site's WordPress salts (<code>AUTH_KEY<\/code> \/ <code>SECURE_AUTH_KEY<\/code> and the corresponding salts in <code>wp-config.php<\/code>), so as long as those salts are defined in <code>wp-config.php<\/code> (as WordPress recommends) a database dump on its own is not enough to recover the credentials \u2014 the attacker also needs filesystem access to <code>wp-config.php<\/code>.<\/p>\n\n<p>If you ever rotate the WordPress salts, the existing encrypted credentials become unreadable; the plugin will surface the provider as \"not configured\" and you simply re-enter the credentials in the <em>Cloud Provider<\/em> tab. There is intentionally no plaintext fallback.<\/p>\n\n<p>Requirements: PHP <code>ext-openssl<\/code> (enabled by default on virtually every host).<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>2.1.0<\/h4>\n\n<ul>\n<li>Enable Offloading looks for files added since the last sync first: it says how many there are and uploads them before offloading is turned on. A file added between the end of the sync and enabling offloading used to stay off the cloud, a broken image once offloading was on. A synced library also offers Scan and Complete Sync on Sync &amp; Offloading \u203a Sync.<\/li>\n<li>Opening Sync &amp; Offloading \u203a Sync more than 90 seconds after a sync finished no longer resets the plugin to \"configured\", which turned offloading off without a word.<\/li>\n<li>Complete Sync uploads the files added to uploads\/ since the last sync; it used to report success and leave them out.<\/li>\n<li>Deleting an attachment while offloading is on removes its copies left on this server too, not only the objects in the cloud.<\/li>\n<li>Deactivating the plugin before the first sync keeps its state; it used to come back as \"synced\".<\/li>\n<li>A site whose server path has a folder named cache, temp or tmp above <code>uploads\/<\/code> syncs its files; every file used to be skipped. Those folders inside <code>uploads\/<\/code> are still left out.<\/li>\n<li>Cloud Provider \u203a Credentials shows the answer of Test Connection; it was written but stayed hidden.<\/li>\n<li>Clear List empties the failed files list on Sync &amp; Offloading \u203a Sync; it used to say so and leave the list as it was.<\/li>\n<li>A browser tab that lost the sync to another tab stops when the sync finishes, instead of asking the server again and again.<\/li>\n<li>The size of a file that is only in the cloud is its real size (the Media Library shows it for files without a stored size); it used to be 0.<\/li>\n<li>The DiluxOne Offload menu sits at the end of the admin menu, after Settings, where WordPress places a plugin's menu by default.<\/li>\n<li>A sync or download request keeps to its time limit when the server's clock is corrected while it runs. Before, a clock set back made the limit look untouched, and the request kept starting uploads past it.<\/li>\n<li>A delete or an upload the storage service asks to slow down (a 429; Google allows one change a second to the same file) is tried again after a second. Before, deleting an image right after editing it could leave its files stored, and billed, in the cloud.<\/li>\n<li>Uninstalling cancels the S3 multipart uploads a sync left unfinished, so the bucket stops billing parts nobody can complete any more.<\/li>\n<li>Before the first sync, Sync &amp; Offloading \u203a Sync checks this site's folder in the container or bucket. If something is already there (an earlier install, a staging copy) it says how many files and how much, and lets you continue with them, empty that folder (typing the container's or bucket's name) or connect another one. Emptying never touches anything outside this site's folder.<\/li>\n<li>A sync whose uploads go through ends a pause the connection health had recorded (a key that failed and was fixed since), instead of showing \"Paused\" for up to five more minutes.<\/li>\n<li>An upload, a delete or a check that meets a temporary error from the storage service (a 500 or 503, a dropped connection) is tried up to three times in all, instead of failing at once. Backblaze B2 answers that way to about one upload in a hundred, which could leave an image without one of its thumbnails.<\/li>\n<li>The initial sync uses every parallel upload from the start: a library that begins with large files used to send them one at a time, and now sends them alongside small ones, each upload starting as soon as another finishes.<\/li>\n<li>A large file's parts (above 10 MB) now go up in parallel, like the other files, instead of one after another while the rest of the sync waited. A part that meets a temporary error from the storage service is sent again instead of failing the file. A very large file no longer has to go up within one request of the sync: the next one takes it up where it was left, sending only the parts the storage service does not have yet.<\/li>\n<li>The sync and Disconnect from Cloud reuse their connections to the storage service from one group of files to the next, instead of opening a new one, with its secure handshake, for every file.<\/li>\n<li>Status \u203a Health names the storage service in use (Cloudflare R2, Amazon S3, \u2026) and no longer shows a card that repeated the plugin's state. Screens that speak of the storage say \"container or bucket\", and a hostname too long for its card (Cloudflare R2's public one) is shortened, with the whole name on hover.<\/li>\n<li>The Sync, Offloading and Disconnect screens and their windows are built on WordPress' own buttons, notices and cards, and take the accent of your admin colour scheme. Offloading's bar shows, in one full bar, the files only in the cloud and, striped, the ones that still have a copy on this server (the disk Delete Local Files can free). While a sync has files pending, the ones that already failed show as a red part of its bar. Messages these screens showed in English only are now translated.<\/li>\n<li>Six more services in the S3-compatible provider's Service list: Hetzner Object Storage, Akamai (Linode) Object Storage, Vultr Object Storage, Scaleway Object Storage, OVHcloud Object Storage and IDrive e2. Each fills in the endpoint and, where the service has one, the public URL, and says where its keys come from and how to make the bucket readable.<\/li>\n<li>A file too large for the storage service's limit on parts goes up in larger parts instead of failing: past about 5 GB on Scaleway (1,000 parts), past about 48 GB elsewhere.<\/li>\n<li>Settings \u203a Serving \u203a New uploads: browser caching, on by default, stores <code>Cache-Control: public, max-age=604800<\/code> (one week, editable, or off) with every new upload, so browsers and CDNs keep your media instead of asking the storage again. And a storage class for new uploads: Standard, or the cheaper infrequent-access class (Azure's Cool tier, STANDARD_IA on Amazon S3 and Cloudflare R2), which charges per read and bills a minimum of 30 days. Files already in the cloud keep what they were stored with.<\/li>\n<li>The notices after saving settings, the provider or new credentials are translated.<\/li>\n<li>Settings \u203a Transfers \u203a Folders the initial sync leaves out: one folder per line under <code>wp-content\/uploads\/<\/code> (backups, caches); the scan skips them and lists them on the Sync screen. Files uploaded through the site while offloading is on still go to the cloud.<\/li>\n<li>An e-mail to the site's administrator address when uploads pause (the storage failed three times in a row) and one more when they resume, never one per failure. On by default; Settings \u203a Logging turns it off.<\/li>\n<li>Tools \u203a Site Health has a test for the connection to your storage, critical with the reason when uploads are paused, and an Info section with the provider, the service, the state and the version (never a key).<\/li>\n<\/ul>\n\n<h4>2.0.0<\/h4>\n\n<ul>\n<li>S3-compatible storage: besides Azure Blob Storage, the media can live on Amazon S3, Cloudflare R2, Backblaze B2, DigitalOcean Spaces, Wasabi, Google Cloud Storage (HMAC keys) or any server that speaks the S3 API, such as MinIO. Pick the service and the plugin fills in the endpoint and the public URL; the Public URL field is also where a CDN or a custom domain goes. Test Connection proves the keys can write to the bucket and that browsers can read what is stored, and refuses a private bucket. Large files go up in 5 MiB parts; the secret access key is encrypted like the Azure key. \"Force HTTPS for cloud storage URLs\" leaves alone a Public URL that is plain http on purpose, such as a server on a private network.<\/li>\n<li>Only a configuration that passed Test Connection can be saved, now checked on the server too: a key other than the tested one is refused.<\/li>\n<li>The admin is one menu with a screen per submenu (Overview, Cloud Provider, Sync &amp; Offloading, Settings, Status) and tabs only where a screen needs a second level: Connection and Credentials; Sync, Offloading and Disconnect; Transfers, Serving and Logging; Health and System. Every screen is headed \"DiluxOne Offload | Screen\", shows the site's state at a glance in a column beside the content, and the open tab follows your admin colour scheme. Old links to the tabs keep working.<\/li>\n<li>Status \u203a Health shows the connection health the plugin already recorded (status, last check, last success, consecutive failures) and how many files the tracking table knows, with a \"Check now\" button that asks the provider right away; Status \u203a System shows the free disk.<\/li>\n<li>The screens say what is where: Sync shows how many files are synced, how many still have a local copy, how many live in the cloud only, the last upload made through the site and what the last scan left out (and why); Offloading shows where the media is served from, where the bytes are and since when; Disconnect shows what it would bring back and whether the disk has room; Cloud Provider shows since when it is connected.<\/li>\n<li>Files uploaded through the site while offloading is on are now counted like the ones the initial sync moved, and deleting the local copies no longer empties the plugin's tracking table, so those figures stay right on the sites that use offloading. A very long list of failed files shows its first 50 rows and says how many there are.<\/li>\n<li>The Overview shows three state cards (the fourth repeated them); Cloud Provider \u203a Connection offers \"Rotate the key\" and \"Delete Cloud Provider\" as buttons; every button with an icon has the icon and its label on one line, and the sync window's buttons read at their size.<\/li>\n<li>The \"Upload Timeout\" setting is now \"Transfer Timeout\" and governs every upload request: the single upload, each block and its commit, and the sync's parallel transfers. Before, block commits waited a fixed 300 seconds whatever the setting said. Downloads keep waiting at least the 300 seconds they always had; a higher setting raises that too.<\/li>\n<li>A transfer that runs past the timeout is reported as such: the connection-health banner says \"Cloud Transfer Timed Out\" and links to Settings, instead of showing a made-up error code.<\/li>\n<li>With debug logging on, every successful upload through the stream wrapper writes one line (path and size).<\/li>\n<li>The suites now prove what each setting does, not only that it is saved.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<p>First public release.<\/p>\n\n<ul>\n<li>Azure Blob Storage provider with your own account and key; media served from <code>https:\/\/&lt;account&gt;.blob.core.windows.net<\/code>.<\/li>\n<li>Transparent PHP stream wrapper on <code>\/wp-content\/uploads\/<\/code>: no URL rewriting, no database migration.<\/li>\n<li>Sync with cancel, resume and retry; optional deletion of the local copies once synced; <strong>Disconnect from Cloud<\/strong> brings everything back.<\/li>\n<li>Connection health: when the cloud is unreachable an upload fails with a clear error and nothing is written elsewhere.<\/li>\n<li>Streaming transfers: downloads go straight to disk and uploads go in 4 MiB blocks, so large files do not need large memory.<\/li>\n<li>\"Force HTTPS for cloud storage URLs\" option; multisite with per-site configuration; credentials encrypted at rest (AES-256-GCM, key derived from the site's salts); quiet unless <code>WP_DEBUG<\/code> or the debug toggle is on.<\/li>\n<li>Uninstalling removes the plugin's options, transients and table; media files are never touched.<\/li>\n<\/ul>","raw_excerpt":"Move your media to cloud object storage and serve it from there. Replaces \/uploads\/ transparently, with no URL rewriting.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/306382","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=306382"}],"author":[{"embeddable":true,"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/pablodiloreto"}],"wp:attachment":[{"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=306382"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=306382"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=306382"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=306382"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=306382"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/bal.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=306382"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}