Private images
Mark an image private so only a link with a valid signature can open it. How to set it, how to generate time-limited signed links, how it interacts with caching, 302 redirects and hotlink protection, and what it protects against and what it does not.
When to use it
By default an image link is public: anyone who knows the link can open it. Some images should be seen only by certain people for a while, such as the pictures of an unpublished article or a screenshot sent to a colleague. Mark them private:
- The public link of a private image (
/i/<id>) does not open and returns 404. - Only a link with a valid signature opens it. A signed link is time-limited and stops working when it expires.
- A private image is always served by this service, never through a channel's direct link, and never cached by a CDN.
Marking an image private
Three ways:
- At upload: set the form or JSON field
privatetotrue; see Upload. The Upload dialog of the admin console has a Private switch. - Afterwards: the Private image switch in the image details, or
PATCH /api/admin/images/{id}withprivate. The owner and admins can change it. - Back to public: turn the same switch off. The original public link works again immediately.
Bulk import and uploads through the S3-compatible API cannot set it; mark the images afterwards, one by one.
Generating a signed link
A private image has no permanent link. To share it, generate a time-limited signed link first:
- Admin console: open the image details, pick a validity (1 hour, 1 day, 7 days, 30 days), click Generate link, then copy it in the format you need.
- API:
POST /api/admin/images/{id}/signed-urlwith the body{"ttl_seconds": 3600}; the validity is 1 second to 365 days, and the response has the full signed link and its expiry. - Upload response: for a private upload,
urlitself is the signed link, its expiry is inexpires_at, and it is valid for 24 hours by default; usesigned_ttl(seconds) to change that. Clients such as PicGo that takeurldirectly need no change.
A signed link looks like:
https://img.example.com/i/Ab3xK9?exp=1893456000&sig=hF3...exp is the expiry (Unix seconds) and sig is an HMAC-SHA256 signature over the image's short ID, its signing generation and the expiry. The generation goes up by one every time the private switch changes. You can still append processing parameters such as w and format; they are not part of the signature. Every generated signed link is recorded in the audit log.
Access rules
| Request | Result |
|---|---|
| Public link without a signature | 404 |
Tampered signature, mismatched image ID, non-canonical exp, or an old link used after the private switch changed | 404 |
Correct signature, past exp | 404 |
| Correct signature, not expired | 200, the image |
| Thumbnails and previews in the admin console | By login session: the owner and admins can view, no signature needed |
| GetObject and HEAD on the S3-compatible API | By S3 credentials, unaffected by private |
Every "cannot view" case returns the same 404, whether the image does not exist, has no signature or has an expired one, so a prober cannot tell whether a private image exists.
Opening a private image through its S3 object key alias /o/<user id>/<object key> needs a signature too: the signature is always over the image's short ID, so generate it with that ID.
How it interacts with other features
- Caching: responses carry
Cache-Control: private, no-store, so neither browsers nor CDNs keep them. Every access comes back to this host to check the signature. - 302 direct links: even in
redirectaccess mode a private image is served by this host and never redirected to a channel's public address. - On-demand processing: a signed link can carry
wandformat; variants are cached only on this host and never published. - Hotlink protection: it still applies, and a valid signature does not bypass the allowlist. With hotlink protection configured and Allow empty referer off, opening a signed link directly in the address bar is rejected.
- Deduplication: images with identical bytes share one physical file, but whether an image is private is judged per image record; a public record is not affected by a private one.
- Access counting: accesses with a valid signature are counted as usual.
- Recovering image records: images recovered from channel objects are public, because objects in a channel carry no private flag; mark the ones that used to be private again afterwards. Backups and exports of the metadata database include the flag, so restoring a backup is unaffected.
What a signed link protects against, and what it does not
- It protects against links being guessed, crawled or kept forever: the public link does not open, and a signed link stops working when it expires.
- It does not stop the holder from forwarding it: anyone who has the link during its validity can open it. For a shorter exposure window, generate a link with a shorter validity.
- To recall links already handed out before they expire: make the image public again, then private again. Every change of the private switch invalidates all links signed before it; while the image is public, its public link can be opened.
- For an image that was public before it became private, copies cached earlier by browsers or CDNs (up to a year), and channel direct links already returned in
redirectmode, are not recalled: the object behind a direct link stays reachable. Do not expect the private switch to take back the past. - The signing key is derived from the master key. Changing the master key invalidates every signed link, but it is not a way to recall links: it also affects encrypted channels, see the master key section.
- Private does not change the storage layer: objects in a channel are still plaintext (unless the channel has storage encryption) and visible to anyone who can sign in to the storage provider account.
Accessing images
The two forms of image links, on-demand resizing and format conversion, caching, the proxy and 302 access modes, hotlink protection, and access counting.
Lifecycle and deduplication
How lifetimes are resolved and renewed on access, expiry cleanup and the delete flow, reviewing cold images, and automatic merging and manual review of duplicate images.