Skip to content

Setup large file storage

Use external file storage when your Git repository should not act as file storage, or when you need larger uploads. For example, Cloudflare Workers only allows files up to 25 MB.

This guide explains how to configure Cloudflare R2 for Administration UI uploads in LightNet.

  1. Add an R2 subscription: Open your Cloudflare account and enable R2 Object Storage if it is not already active.
  2. Create a bucket: Create a new R2 bucket for your uploaded files.
  3. Configure bucket settings: In the bucket settings, add a custom domain such as files.your-site.org. Then add a CORS policy like this:
    [
    {
    "AllowedOrigins": [
    "http://localhost:4321",
    "https://your-site.org"
    ],
    "AllowedMethods": [
    "GET", "PUT", "HEAD"
    ],
    "ExposeHeaders": ["ETag"],
    "AllowedHeaders": ["*"],
    "MaxAgeSeconds": 3000
    }
    ]
    Replace the sample origins with your real local development URL and your production site URL.
  4. Create an API token: In Cloudflare, go to R2 Object Storage, click API tokens and then Manage, then create an account API token. Set Permissions to Object Read & Write, set Specify buckets to Apply to specific buckets only, and select your bucket. Save the generated Access Key ID and Secret Access Key somewhere secure.

Add the experimental R2 file storage configuration to lightnetSveltiaAdmin(...):

astro.config.mjs
import lightnet from "lightnet"
import lightnetSveltiaAdmin from "@lightnet/sveltia-admin"
import { defineConfig } from "astro/config"
export default defineConfig({
integrations: [
lightnet({
// ...
}),
lightnetSveltiaAdmin({
experimental: {
fileStorage: {
name: "cloudflare-r2",
accessKeyId: "<your-access-key-id>",
bucket: "<your-bucket>",
accountId: "<your-account-id>",
publicUrl: "https://files.your-site.org",
},
},
}),
],
})
  • name: Must be "cloudflare-r2".
  • accessKeyId: The R2 Access Key ID for uploads.
  • bucket: The bucket name used to store uploaded files.
  • accountId: Your Cloudflare account ID.
  • publicUrl: Public base URL used for previews and downloads.
  • prefix: Optional path prefix inside the bucket, for example uploads/.

Follow these steps when an existing site stores uploaded media files in public/files and you want future uploads to go to Cloudflare R2.

Before you start, finish the R2 setup above and choose the public file URL you want to use, for example https://files.your-site.org.

  1. Install rclone: Install rclone on your computer.
  2. Create an R2 remote: Run rclone config and follow Cloudflare’s rclone setup guide. The examples below use <remote-name> for the rclone remote and <bucket-name> for the R2 bucket.
  3. Upload the existing files: From your site repository, copy the current public/files contents (excluding OS-files) to the R2 bucket:
    Terminal window
    cd public/files
    rclone copy . <remote-name>:<bucket-name> \
    --progress \
    --exclude ".DS_Store" \
    --exclude "._*" \
    --exclude "Thumbs.db" \
    --exclude "desktop.ini"
    If you configured a prefix in experimental.fileStorage, include it in the destination:
    Terminal window
    rclone copy . <remote-name>:<bucket-name>/<prefix> \
    --progress \
    --exclude ".DS_Store" \
    --exclude "._*" \
    --exclude "Thumbs.db" \
    --exclude "desktop.ini"
  4. Check the uploaded files: Open a few uploaded file URLs in the browser using your public file domain. For example, public/files/videos/intro.mp4 should be available at https://files.your-site.org/videos/intro.mp4.
  5. Update media item URLs: In your site repository, replace file URLs in media content from the local /files/ path to the R2 public URL. For JSON content, this usually means replacing:
    "/files/
    with:
    "https://files.your-site.org/
    Keep the trailing slash so existing nested paths stay intact.
  6. Allow the file domain in LightNet: In astro.config.mjs, add the new file storage domain to internalDomains so LightNet treats the uploaded files as internal media:
    astro.config.mjs
    lightnet({
    internalDomains: ["files.your-site.org"],
    })
    If your config already has internalDomains, add the new domain to the existing list.
  7. Enable R2 uploads in the Administration UI: Add the experimental.fileStorage configuration to lightnetSveltiaAdmin(...) as shown above. Future Administration UI uploads will now go to R2 instead of the Git repository.
  8. Test the site locally: Build or run the site and confirm that existing media loads from the R2 domain:
    Terminal window
    pnpm build
  9. Archive the old repository history: If you need to preserve the old Git history, push the current repository to a separate archive repository before removing the file blobs from the active project. This is done to reduce the size of the active repository after moving uploads to R2, which helps future clone, fetch, and CI performance. Deleting the files from the working tree alone would not be enough, because Git would still keep the old file blobs in the commit history.
  10. Create a fresh Git history: When the R2 migration is verified and the archive is complete, merge or close any important open pull requests first, and ask contributors to stop opening new ones. Then remove the old .git directory and initialize a new repository:
    Terminal window
    rm -rf .git
    git init
    git add .
    git commit -m "Migrate media files to external storage"
    git remote add origin git@github.com:Your-Org/Your-Repo.git
    git push -u origin main --force
  11. Verify the site now uses R2: After the force push, run the site again and confirm media still loads from the R2 domain rather than from repository files. Upload a new file in the Administration UI and check that it appears in R2 and is served from your public file URL.