Video failed to load

PicImpact Uploads Failing with Cloudflare R2? Here’s How to Troubleshoot It

772 words
4 minutes
PicImpact Uploads Failing with Cloudflare R2? Here’s How to Troubleshoot It
PicImpact Uploads Failing with Cloudflare R2? Here’s How to Troubleshoot It

Translation Notice

This article was originally written in Chinese and translated into English with the assistance of AI. The translation has been reviewed and edited for clarity, accuracy, and readability. Please refer to the original source where necessary, especially for technical terms, commands, configuration details, and proper nouns.

PicImpact is a self-hostable photography portfolio platform built with Next.js + Hono.js. It looks great and is practical—perfect for people like me who enjoy tinkering but are too lazy to build a frontend from scratch 🙋‍♂️

  • 🌐 GitHub:
besscroft
/
PicImpact
自部署的摄影作品网站,支持多种功能特性。PicImpact,分享你和世界!
—
—
MIT
TypeScript

🪄 Why PicImpact?#

I was looking for an attractive and convenient image-hosting template for my photography site Moments. After comparing several options, I found PicImpact: a great interface, simple deployment, and Docker support—everything in one shot!

🚫 Why not deploy it locally?
Don’t ask. I simply did not want to run Node.js—it feels too heavy… 💀

🐳 One-Command Docker Deployment#

Deployment is genuinely smooth. Install PostgreSQL beforehand—locally or in the cloud—and then all that remains is a docker run. 🌟 It is incredibly fast:

Terminal window
docker run -d --name picimpact \
-p 3000:3000 \
-e DATABASE_URL="postgresql://[username]:[password]@[host:port]/[database]" \
-e BETTER_AUTH_SECRET="npx auth secret or a random string" \
besscroft/picimpact:latest

🧨 But Then Came the Problem…#

I initially used Alist as the storage backend, but my home connection’s limited upload speed made access painfully slow. So I turned to Cloudflare’s free R2 object storage service.

After configuring everything, image uploads went haywire:

  • The lower-right popup reports ☑️ success, but Upload.failed appears below the image.

  • A collection of bizarre Console errors:

    1. ERR_NAME_NOT_RESOLVED
    2. ERR_SSL_VERSION_OR_CIPHER_MISMATCH
    3. ERR_FAILED
    4. has been blocked by CORS policy: … No ‘Access-Control-Allow-Origin’ header

Was the upload successful? The R2 console was empty… Was it a failure? The frontend insisted that it had succeeded. It felt as if I had encountered every PicImpact error 🤦‍♂️. Eventually, I identified the cause: the CORS configuration was wrong.

Upload error
Upload error

🛠️ Create Cloudflare R2 Object Storage#

Cloudflare R2 provides 10 GB of storage per month with free bandwidth. However, its Cloudflare nodes are overseas, so performance may be slow. If speed is important, consider Tencent COS or Alibaba OSS instead.

  1. Open the R2 Object Storage page.

    R2 Object Storage
    R2 Object Storage

  2. Create a bucket.

    Create Bucket
    Create Bucket

  3. Configure the bucket parameters.

You may choose a Location or leave it blank; performance is similar. However, the storage class must be Standard, otherwise the free R2 allowance will not apply 😯.

Bucket configuration
Bucket configuration

  1. Configure the object-storage domain.

The domain must use DNS nameservers pointing to Cloudflare. Domains managed by other providers will not work; if you use Cloudflare’s service, the domain must be under Cloudflare’s control.

Custom Domain
Custom Domain

  1. Important: Configure the CORS policy

This is the key step. Without a CORS policy, you may spend hours troubleshooting as I did.

CORS configuration
CORS configuration

Example CORS configuration. AllowedHeaders is required; the default CORS policy generated by R2 does not include it.

Terminal window
[
{
"AllowedOrigins": [
"http://localhost:3000"
],
"AllowedMethods": [
"GET",
"HEAD",
"PUT",
"POST",
"DELETE"
],
"AllowedHeaders": [
"*"
]
}
]
  1. Create an API.
    Create API
    Create API

Note: As a security professional, I recommend applying least privilege to APIs. Some pages may encourage you to create an Account API token, which is not recommended. A User API Token is sufficient.

Create User token
Create User token

API permissions should also be minimized. Each API should control only its corresponding bucket. 🙅 Do not grant excessive permissions; least privilege is more complex, but safer.

API configuration
API configuration

  1. Cloudflare provides the API key information.

These details are shown only once, so store them safely. For the PicImpact integration, you only need the S3 API details: Access Key ID, Secret Access Key, and Default (the Account ID).

API information
API information

🔗 Connect PicImpact to CF-R2 Object Storage#

  1. Open the admin panel and go to Storage Settings -> Cloudflare R2 -> Edit.

    Cloudfalre R2
    Cloudfalre R2

  2. Enter the information.

  • r2_accesskey_id

    Use the Access Key ID from Cloudflare’s API key information.

  • r2_accesskey_secret

    Use the Secret Access Key from Cloudflare’s API key information.

  • r2_account_id

    Take the first segment of Default. For example, if it is https://123456.r2.cloudflarestorage.com, your r2_account_id is 123456.

  • r2_bucket

    Use the name of the bucket you created.

  • r2_storage_folder

    Storage path: leave it blank for the root directory; otherwise enter the path name. Do not add a leading /.

  • r2_public_domian

    Use the object-storage domain configured in Step 4. Include https://; if your domain is abc.com, enter https://abc.com.

  • r2_direct_download

    The default false value is fine.

R2 object-storage information
R2 object-storage information

  1. Once complete, start showcasing your photography.

Moments
Moments

✅ Final Thoughts#

PicImpact is an excellent project with an elegant UI and simple deployment. Its documentation does not provide step-by-step guidance for object storage, but that is understandable—open-source projects are all about experimentation.

Incorrect CORS configuration is especially misleading: an upload may appear successful while actually failing. The Console had already shown the error; I simply missed it, so the mistake was ultimately mine.

If you are also experimenting with PicImpact + CF-R2, remember:

  • Check Console errors first.
  • Compare them with the CORS settings.
  • Finally, confirm that the upload actually reached the storage bucket.

I hope this article saves you from a lot of hair-pulling 🤯.

Support & Share

If this article helped you, please share or support!

Sponsor
PicImpact Uploads Failing with Cloudflare R2? Here’s How to Troubleshoot It
https://blog.bytesycn.cn/posts/02139ee4-d1ee-496a-94a2-e1f68c1a2982/
Author
Ryan Zhang
Published at
2025-07-02

Comments

Profile Image of the Author
Ryan Zhang
Keep building, keep thinking, keep creating.
Announcement
Welcome to my blog!
Categories
Tags
Latest Moments
Site Statistics
Posts
30
Categories
7
Tags
42
Total Words
117,260
Running Days
0 days
Last Activity
0 days ago
Table of Contents