Image Hosting
Multiforum can use Google Cloud Storage (GCS) for uploaded images and files. Storage is optional: when it is unconfigured, upload controls remain disabled and the admin setup page explains what is missing.
Overview
The file upload system provides:
- Signed URLs - Time-limited upload access (15 minutes)
- File Type Validation - Server and channel-level restrictions
- Virus Scanning - Optional malware detection
- Image Moderation - Archive and removal workflows
Setting Up Google Cloud Storage
1. Create a Google Cloud Project
- Go to Google Cloud Console
- Create a new project or select an existing one
- Note your project ID
2. Enable the Cloud Storage API
- Go to APIs & Services → Library
- Search for "Cloud Storage"
- Click Enable on the Cloud Storage API
3. Create a Storage Bucket
- Go to Cloud Storage → Buckets
- Click Create Bucket
- Configure your bucket:
- Name: Choose a globally unique name (e.g.,
your-app-uploads) - Location: Choose a region near your users
- Storage class: Standard (recommended)
- Access control: Fine-grained
- Name: Choose a globally unique name (e.g.,
- Click Create
4. Configure CORS
For browser uploads to work, configure CORS on your bucket:
[
{
"origin": ["https://your-frontend-domain.com"],
"method": ["GET", "PUT", "POST", "DELETE"],
"responseHeader": ["Content-Type"],
"maxAgeSeconds": 3600
}
]
Apply using gsutil:
gsutil cors set cors.json gs://your-bucket-name
5. Create a Service Account
- Go to IAM & Admin → Service Accounts
- Click Create Service Account
- Name it (e.g.,
multiforum-storage) - Grant the Storage Admin role
- Create and download a JSON key
6. Encode the Credentials
Base64 encode your service account key:
base64 -i your-service-account-key.json
Save this encoded string for your environment variables.
Environment Variables
Backend
GCS_BUCKET_NAME=your-bucket-name
GOOGLE_CREDENTIALS_BASE64=your-base64-encoded-credentials
For private downloads, also configure:
GCS_PRIVATE_DOWNLOAD_BUCKET_NAME=your-private-download-bucket
The production Compose overlay supplies the public bucket to the frontend at
runtime. No VITE_* build variable is required.
File Type Configuration
Server-Level Allowed File Types
Configure default allowed file types in the ServerConfig:
MATCH (s:ServerConfig {serverName: "your-server"})
SET s.allowedFileTypes = [".stl", ".obj", ".zip", ".rar", ".blend", ".png", ".jpg", ".gif"]
Channel-Level Overrides
Individual channels can override server defaults:
- Go to Channel Settings → Downloads
- Edit the Allowed File Types list
- Save changes
Channels can be more restrictive than the server default but not less.
How Uploads Work
Upload Flow
- User selects a file to upload
- Frontend requests a signed URL from the backend
- Backend validates:
- User authentication
- File type allowed
- Channel permissions (if applicable)
- Backend generates a time-limited signed URL
- Frontend uploads directly to GCS using the signed URL
- Frontend notifies backend of successful upload
- Backend creates the Image/File record in the database
Signed URL Security
- URLs expire after 15 minutes
- Each URL is specific to one file
- URLs include authentication tokens
- Direct bucket access is not allowed
Image Features
Image Properties
| Property | Description |
|---|---|
url | The public URL of the image |
alt | Alternative text for accessibility |
caption | Optional caption displayed with image |
longDescription | Extended description for screen readers |
copyright | Copyright information |
hasSensitiveContent | Flag for adult/sensitive content |
hasSpoiler | Flag for spoiler content |
Image Scanning
Images can be scanned for malware and inappropriate content:
| Status | Description |
|---|---|
PENDING | Awaiting scan |
CLEAN | Passed all scans |
INFECTED | Malware detected |
SUSPICIOUS | Flagged for review |
FAILED | Scan failed |
Image Moderation
Moderators can:
- Archive - Hide image from public view
- Permanently Remove - Delete image and purge from storage
- Report - Create a moderation issue for review
All moderation actions are linked to Issues for audit trails.
Enabling Image Uploads Per Channel
Channels can individually enable or disable image uploads:
- Go to Channel Settings
- Find Image Uploads Enabled
- Toggle on/off
- Save changes
Related channel settings:
imageUploadsEnabled- Allow direct image uploadsmarkdownImagesEnabled- Allow embedding images via markdown URLsemojiEnabled- Allow emoji reactions
File Versioning
Downloadable files support version history:
- Each version tracks filename, size, and changelog
- Users can download previous versions
- Version history is preserved
Troubleshooting
Upload Failures
- Verify GCS bucket exists and is accessible
- Check service account has Storage Admin role
- Verify CORS configuration
- Check file type is allowed
- Verify base64 encoding of credentials
CORS Errors
If you see CORS errors in the browser console:
- Verify CORS configuration includes your frontend domain
- Check that the request method is allowed
- Ensure Content-Type header is permitted
Permission Denied
- Check user has
canUploadFilepermission - Verify channel allows uploads (
imageUploadsEnabled) - Check file type is in allowed list