This document provides step-by-step configuration for Google Cloud Storage using Fine-grained Access Control. This mode supports legacy object ACLs and resolves the common "Cannot insert legacy ACL" upload error. This guide also covers BBCode usage to embed and link files on your website.Part 1: Administrative Configuration (Backend Setup)
Two core components need configuration: Service Account (backend authentication) + Bucket with Fine-grained ACL enabled.
Critical Note: Uniform access control mode DOES NOT support object-level ACLs and will cause upload failures for most forum remote storage plugins.
1. Create Service Account (Backend Authentication Key)
Your website uses this service account to authenticate with Google Cloud for upload, delete, list and read files.
- Navigate to Google Cloud Console → IAM & Admin → Service Accounts
- Click + CREATE SERVICE ACCOUNT
- Service account details: Input recognizable name (e.g. gcs-backend-user), click Create and Continue
- Grant access permissions: Role → Cloud Storage → Storage Object Admin
This role allows creating, deleting, listing and overwriting objects inside bucket. - Click Done to finish account creation
- Locate the new service account in list, click ⋮ (three dots) → Manage keys
- ADD KEY → Create new key → JSON
- The JSON credential file will download automatically.
2. Create Bucket with Fine-grained Access Control (Most Important Step)
- Go to Cloud Storage → Browser → Click CREATE
- Bucket name: Use a globally unique name (cannot duplicate across all Google Cloud users)
- Location type: Select Region, choose region closest to your visitors (us-central1 / asia-east1 etc.)
- Storage class: Select Standard
- Access control configuration:
- Uncheck Enforce public access prevention on this bucket (required if you host public images for forums)
- Select Fine-grained
- Only Fine-grained mode supports legacy object ACLs and eliminates "Cannot insert legacy ACL" error. Existing buckets cannot switch access mode; you must create a new bucket.
- Complete bucket creation
3. Configure Bucket CORS Policy (Fix Cross-Origin Image & Upload Errors)
GCS console does NOT provide visual CORS editor; you must apply rules via Cloud Shell / gsutil.
- Open Cloud Shell icon at top-right of Google Cloud Console
- Execute this command to generate cors-config.json
Bash:
echo '[{"origin": ["*"], "method": ["GET", "PUT", "POST", "DELETE", "HEAD"], "responseHeader": ["Content-Type"], "maxAgeSeconds": 3600}]' > cors-config.json
- Run the following command to apply policy to your bucket, replace YOUR_BUCKET_NAME:
Bash:
gsutil cors set cors-config.json gs://YOUR_BUCKET_NAME
4. Enable Global Public Read Access (Mandatory for BBCode Image Embedding)
To let all website visitors load images via direct URL, you must add allUsers with Storage Object Viewer role.
- Open target bucket → Switch to Permissions tab
- Click GRANT ACCESS
- New principals: allUsers
- Assign role: Cloud Storage → Storage Object Viewer
- Click Save
- When warning about public access appears, confirm the change
allUsers means every user on the internet can read/download all objects inside this bucket. Do not store private, sensitive or confidential files.
If you skip this step, browsers will return 403 Forbidden when loading images inside forum posts.
Part 2: User Guide (How to use BBCode)
After backend integration passes testing, users can embed GCS files into posts via standard BBCode tags.
1. Standard GCS Public URL Format
Native public access link:
Example:
Custom domain link (with Cloud CDN, optional):
2. Common BBCode Usage Exampleslutish.com/
A. Embed display image (Direct image rendering)
Syntax:
Code:
[img]YOUR_GCS_FILE_URL[/img]
Code:
[img]https://storage.googleapis.com/my-website-storage-001/nature.png[/img]
B. Create text download link (PDF, ZIP, archives, documents)
Syntax:
Code:
[url=YOUR_GCS_FILE_URL]Custom Link Text[/url]
Code:
[url=https://storage.googleapis.com/my-website-storage-001/manual.pdf]Download User Manual[/url]
C. Clickable thumbnail image (Image button linking to target page)
Syntax:
Code:
[url=TARGET_WEBSITE_URL][img]GCS_IMAGE_URL[/img][/url]
Code:
[url=https://example.com][img]https://storage.googleapis.com/my-website-storage-001/button.jpg[/img]
Part 3: Troubleshooting Table
| Issue Symptom | Root Cause | Solution |
|---|---|---|
| Cannot insert legacy ACL / 400 upload error Bucket set to Uniform access control mode (ACL disabled) Recreate bucket and select Fine-grained access control. Existing buckets cannot switch mode directly. | ||
| 403 Forbidden when opening images in forum 1. "Enforce public access prevention" still enabled 2. Missing allUsers principal OR wrong role assigned 3. Permission propagation delay (2–5 minutes) Uncheck public access prevention; add principal allUsers with role Storage Object Viewer; wait for policy to take effect. | ||
| Backend unable to upload/delete files 1. Invalid / corrupted Service Account JSON key 2. Insufficient IAM role permissions 3. Wrong bucket name filled in website settings Re-download valid JSON key; confirm role is Storage Object Admin; double-check bucket spelling. | ||
| Broken image icon inside forum posts 1. Incorrect or missing CORS policy 2. File deleted or path mismatch 3. Non-HTTPS URL used Re-apply bucket CORS config; use full HTTPS links; verify file exists in bucket. | ||
| Direct URL opens file normally, images fail to embed in forum Browser cross-origin restriction Re-run gsutil cors command; clear browser cache; confirm GET & HEAD methods are allowed. | ||
| 404 Not Found error GCS filenames are case-sensitive Match filename uppercase/lowercase exactly in the public URL. |
Part 4: Administrator Final Checklist
Google Cloud Storage API enabled in project
Service Account created with Storage Object Admin role, JSON key safely backed up
Bucket newly created with Fine-grained access control
"Enforce public access prevention" unchecked
CORS policy applied to bucket via gsutil
Principal allUsers added with Storage Object Viewer role
Forum remote storage backend configured with bucket name and Service Account JSON key
Upload test file; confirm no legacy ACL error occurs
Test BBCode to verify images display correctly
Share BBCode instructions with forum users
- Uniform access control bucket cannot be converted to Fine-grained mode; you need to create a brand new bucket.
- Do not leak Service Account JSON key. Attackers can fully manage all bucket files with valid credentials.
- allUsers + Storage Object Viewer grants global public read access. Never store sensitive data.
- Restrict CORS AllowedOrigins to your own domain for production environments.
- Consider Cloud CDN to accelerate global loading speed for public static files.
- For private content: Remove allUsers access and use signed URLs for temporary authorized access.