Skip to content

Image Hosting on R2

Product images are uploaded and stored on the rCommerce server (local disk under the [media] local_path, default ./uploads). For fast global delivery, sync them to a per-store Cloudflare R2 bucket and serve the bucket’s public URL.

The importer decides the URL it writes into product_images.src at import time, based on the IMAGE_BASE_URL environment variable (read by the WooCommerce importer when it downloads images to local storage):

Terminal window
# Always set it per store so image URLs point at the CDN, not the API host.
# There is no reliable default.
IMAGE_BASE_URL=https://images.shop.example.com

Set it in the store’s service environment before running any import or re-import. Images already imported keep their old URLs until re-imported with --overwrite (or updated directly).

Create one bucket per store (R2 → Manage R2 → Create bucket), e.g. store-b-uploads. Two ways to serve it publicly:

  1. Public development URL — enable “Public URL” on the bucket; you get https://pub-….r2.dev. Fine for testing.
  2. Custom domain (recommended) — attach images.<store>.com to the bucket. At your DNS provider, CNAME the hostname to public.r2.dev and keep the Cloudflare proxy enabled (orange cloud).

rclone speaks S3-compatible R2. Configure a remote per store:

~/.config/rclone/rclone.conf
[store-b-r2]
type = s3
provider = Cloudflare
access_key_id = <r2_access_key_id>
secret_access_key = <r2_secret_access_key>
endpoint = https://<account_id>.r2.cloudflarestorage.com
acl = private

Create API tokens scoped to the bucket (R2 → Manage R2 → Manage R2 API Tokens). Then sync the server’s uploads directory to the bucket:

Terminal window
rclone sync /var/db/store-b/uploads store-b-r2:store-b-uploads \
--transfers 8 --checkers 16 --fast-list --delete-after

(The exact local path depends on your layout, e.g. /usr/local/etc/<store> configs with /var/db/<store>/uploads.)

Keep the bucket fresh with a 5-minute cron job on the server:

*/5 * * * * /usr/local/bin/rclone sync /var/db/store-b/uploads store-b-r2:store-b-uploads --transfers 8 --checkers 16 --fast-list --delete-after >> /var/log/store-b/rclone-sync.log 2>&1

Do not remove the reverse proxy’s file_server for /uploads/* when you move to R2. Old image rows still point at https://api.<store>.com/uploads/…, so the Caddy block serving /uploads/* from the store’s upload directory keeps those working. New imports write R2 URLs via IMAGE_BASE_URL, and over time the fallback serves less and less traffic.