How to Configure AWS S3 or Cloudflare R2 with PicList: Complete Setup Guide

To configure AWS S3 or Cloudflare R2 with PicList, add an aws-s3 bucket in Settings → Manage → Bucket, supply your Access Key ID and Secret, set the endpoint (required for R2), enable s3ForcePathStyle for R2 compatibility, and define the ACL as public-read.

PicList supports both Amazon S3 and Cloudflare R2 through its unified aws-s3 plugin, which leverages R2’s S3-compatible API. The configuration values entered in the graphical interface map directly to the JSON structure consumed by the core upload logic, specifically within scripts/upload-to-s3.js.

Adding an S3 or R2 Bucket in PicList

  1. Open Settings → Manage → Bucket and click the "+" button to create a new bucket configuration.
  2. Select aws-s3 (or aws-s3-plist, which uses the identical implementation).
  3. Fill in the required fields detailed in the next section.

The UI field definitions, including placeholders and validation rules, are defined in src/renderer/manage/utils/constants.ts under the aws-s3 section.

Required Configuration Fields

Access Credentials

  • Access Key ID: For AWS, use the IAM user’s accessKeyId; for Cloudflare R2, use the R2_SECRET_ID from your R2 API tokens.
  • Access Key Secret: The corresponding secret key (accessKeySecret for AWS, R2_SECRET_KEY for R2).

Bucket Name and Endpoint

  • Bucket Name: The exact name of your existing bucket (e.g., my-bucket).
  • Endpoint: Leave this blank for AWS S3 to use the default regional endpoint. For Cloudflare R2, this is mandatory and must follow the format https://<ACCOUNT_ID>.r2.cloudflarestorage.com.

Path Style and Access Control

  • Force Path Style (s3ForcePathStyle): Set to true for Cloudflare R2, which requires path-style URLs (https://<endpoint>/<bucket>/<key>). For standard AWS S3, set this to false.
  • ACL: Typically set to public-read to ensure uploaded objects are publicly accessible.

How PicList Uploads Files to S3 and R2

When you initiate an upload, PicList constructs an S3Client instance using the AWS SDK for JavaScript v3. The client configuration is built from your bucket settings as implemented in scripts/upload-to-s3.js:

const client = new S3Client({
  region: 'auto',               // Region is ignored for R2
  credentials: {
    accessKeyId: bucketConfig.accessKeyId,
    secretAccessKey: bucketConfig.accessKeySecret,
  },
  endpoint: bucketConfig.endpoint, // Omitted for native AWS S3
  forcePathStyle: bucketConfig.s3ForcePathStyle ?? false,
});

The PutObjectCommand is then executed with your specified Bucket, Key, Body, and ACL values. The same upload script handles both AWS S3 and Cloudflare R2; when the endpoint is omitted, the AWS SDK automatically resolves the appropriate regional endpoint for S3.

Resolving R2 Connectivity Issues in Restricted Networks

Cloudflare R2 endpoints can encounter SNI blocking by the Great Firewall. If uploads fail, inspect piclist.log to identify the resolved IP address. Add this IP to PicList’s proxy exception list under Settings → Network → Proxy to bypass the blockage. This troubleshooting step is documented in FAQ.md.

Configuration File Examples

Bucket Configuration JSON

When saved, your settings produce a JSON object structured like this (example for Cloudflare R2):

{
  "type": "aws-s3",
  "name": "my-r2-bucket",
  "config": {
    "accessKeyId": "R2_SECRET_ID",
    "accessKeySecret": "R2_SECRET_KEY",
    "bucketName": "my-r2-bucket",
    "endpoint": "https://1234567890.r2.cloudflarestorage.com",
    "s3ForcePathStyle": true,
    "acl": "public-read"
  }
}

Upload Script Implementation

The core logic in scripts/upload-to-s3.js demonstrates how the configuration object is consumed:

const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const fs = require('fs');
const path = require('path');

async function upload(filePath, config) {
  const client = new S3Client({
    region: 'auto',
    credentials: {
      accessKeyId: config.accessKeyId,
      secretAccessKey: config.accessKeySecret,
    },
    endpoint: config.endpoint,
    forcePathStyle: config.s3ForcePathStyle,
  });

  const command = new PutObjectCommand({
    Bucket: config.bucketName,
    Key: path.basename(filePath),
    Body: fs.createReadStream(filePath),
    ACL: config.acl,
  });

  return client.send(command);
}

Summary

  • PicList uses the aws-s3 plugin for both Amazon S3 and Cloudflare R2 via S3-compatible APIs.
  • Cloudflare R2 requires a custom endpoint and s3ForcePathStyle: true, while AWS S3 uses regional endpoints and virtual-hosted styles by default.
  • Configuration fields are defined in src/renderer/manage/utils/constants.ts and processed by scripts/upload-to-s3.js.
  • For R2 users behind restrictive firewalls, adding the resolved IP to the proxy list resolves SNI blocking issues.

Frequently Asked Questions

Does PicList support Cloudflare R2 natively?

Yes. PicList supports Cloudflare R2 through the aws-s3 plugin, utilizing R2’s S3-compatible API. You configure it by selecting the aws-s3 bucket type and providing your R2-specific credentials and endpoint.

What is the correct endpoint format for Cloudflare R2?

The endpoint must be https://<ACCOUNT_ID>.r2.cloudflarestorage.com, replacing <ACCOUNT_ID> with your actual Cloudflare account ID. This value is mandatory for R2 but should be left blank for standard AWS S3 configurations.

Why does R2 require Force Path Style while AWS S3 does not?

Cloudflare R2 requires path-style URLs (https://endpoint/bucket/key) rather than virtual-hosted style (https://bucket.endpoint/key). Setting s3ForcePathStyle to true ensures the AWS SDK constructs URLs compatible with R2’s architecture.

How do I troubleshoot upload failures with R2 from China?

If you encounter timeouts or SSL errors, check piclist.log for the IP address resolved from the R2 endpoint. Add this specific IP address to the proxy list in Settings → Network → Proxy to circumvent SNI-based blocking, as noted in the project’s FAQ.md.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →