Each file can be up to 1 GB. Accepted types are JPEG, PNG, GIF, WebP, AVIF, BMP and TIFF images, and MP4 and MOV video. What a network will publish is usually far smaller, and each network decides that itself.
Networks fetch your media by URL
PostQueen stores each file’s full address with the post. Several networks download the file from that address themselves instead of receiving it from PostQueen: Instagram, Facebook, Threads, Slack, TikTok photo posts and everything on TikTok Business. For those, the address must be reachable from the public internet over HTTPS. A laptop or a private network cannot serve it, so posts with media to those networks fail there. Networks that receive the file from PostQueen, such as X, LinkedIn and Bluesky, work from anywhere.Local storage
The Compose file ships ready for it:postqueen-uploads volume at /uploads. Keep those values in the official image: its nginx serves exactly the /uploads folder, and a different UPLOAD_DIRECTORY writes files that are never served. NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY is written without slashes.
Several containers need a volume that every one of them mounts (ReadWriteMany on Kubernetes), or R2.
Move to a new address
Local storage saves each file’s address asFRONTEND_URL + /uploads/.... Change FRONTEND_URL later, for a new domain or a move from http to https, and existing media keeps pointing at the old address: it stops loading and cannot be published.
Put the old address in PREVIOUS_FRONTEND_URLS next to the new FRONTEND_URL:
docker restart or
docker compose restart keeps the old container and its old environment.
In the folder that holds docker-compose.yaml, recreate only the postqueen service:
docker compose down for a settings change: on
a host that runs other Compose services in the same project, it stops them too. On Kubernetes, see
Kubernetes with Helm.
At start, the backend rewrites every stored address under the old one to the new one, in the media library, posts, drafts and channel avatars, and logs what it moved as an [uploads] line.
- List every earlier address, separated by commas, each written in full with
http://orhttps://. - An address is skipped, with a warning in the log, when none of its files exist under
UPLOAD_DIRECTORY. Check that the volume is mounted, then recreate the container again. - Leaving the variable set afterwards is harmless.
CLOUDFLARE_BUCKET_URL and do not change with FRONTEND_URL.
Cloudflare R2
CLOUDFLARE_BUCKET_URL and the CORS policy. Any of those choices gives a public HTTPS address, so the networks that fetch by URL work.
How an upload travels
By default the browser uploads straight to the bucket, in parts, with addresses the backend signs for it. The file never passes through your server. WithUPLOAD_VIA_SERVER=true, the browser sends the file to the backend, which writes it to the bucket.
Uploads fail with a CORS error in the browser
Uploads fail with a CORS error in the browser
The browser reports
blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present, while the backend’s own calls (create-multipart-upload, sign-part) succeed. Usually the bucket answered 403 because something between the browser and R2 changed the signed request, such as a privacy extension stripping query parameters or a corporate proxy. R2 sends no CORS headers on errors, so the browser shows a CORS message instead. Check the bucket’s CORS policy first; if it is right, set UPLOAD_VIA_SERVER=true.Video processing
Every uploaded video is converted in the background before it can be published: H.264 video and AAC audio in MP4, at most 1080p, turned upright, with the index at the start of the file and a poster frame. That is why a MOV from a phone works everywhere. The upload answers at once with the statusprocessing, and the media becomes ready when the conversion is done. The work runs in the orchestrator, on its own media queue, with the ffmpeg that ships in the image. A file ffmpeg cannot read fails with an error on the media item and is not retried.
Related
- Cloudflare R2
- Backups and upgrades: what to back up with each storage
- Configuration reference
- Upload a file through the public API