Publishing files¶
Four ways in, all writing to the same place. Which one fits depends on who is doing it and how often.
| who it is for | what it needs | |
|---|---|---|
| the CLI | a person at a terminal, a CI job | a token |
| the HTTP API | a script, a deploy step, another service | a token |
| the browser | someone who does not have a terminal | an account |
| an S3 client | a tree you already sync with rclone |
a token, as an S3 key pair |
All four land in the same store_object, which puts the bytes in S3, then in the local cache, then writes the index row. The order is what keeps a crash from leaving a row that points at nothing.
The CLI¶
cdn login writes the address and the token to ~/.config/cdn/config.json, so the rest of the commands take neither.
cdn login https://cdn.example.com cdn_a1b2c3d4e5f6_…
cdn put assets ./logo.png img/ # upload one file
cdn ls assets img/ # list what is there
cdn url assets img/logo.png # print the public URL
cdn rm assets img/logo.png # delete it
CDN_URL and CDN_TOKEN override the stored configuration, which is what a CI job should use.
Uploading a directory¶
cdn sync assets ./dist # upload what differs
cdn sync assets ./dist --delete # …and remove what the directory lacks
cdn sync assets ./dist --dry-run # say what would happen
A file is skipped when its size and MD5 match the object already there, so a second run over an unchanged tree transfers nothing. --delete is destructive and --dry-run exists to be used before it.
The HTTP API¶
One PUT sends the bytes as the body:
curl -T ./logo.png \
-H "Authorization: Bearer $CDN_TOKEN" \
-H "Content-Type: image/png" \
https://cdn.example.com/_/api/v1/zones/assets/objects/img/logo.png
201 when the object is new, 200 when it replaced one. The response describes what was stored:
{
"path": "img/logo.png",
"size": 20480,
"etag": "d41d8cd98f00b204e9800998ecf8427e",
"content_type": "image/png",
"url": "https://cdn.example.com/assets/img/logo.png"
}
The content type is taken from the header when you send one and guessed from the path otherwise. X-CDN-Cache-Control overrides the zone's caching header for that one object.
Bodies are streamed to disk as they arrive, so the size of an upload is bounded by CDN_MAX_UPLOAD_BYTES and the disk, never by RAM. The surface is in the HTTP API reference.
The browser¶
Sign in at /_/ui, open a zone, and drop files onto the file browser. Each row has the public URL next to it, and a Sign button for a private zone.
The browser is for the cases a terminal is wrong for: someone who needs to put one file somewhere and send a link, or an owner who wants to look at what is in a zone. It uploads through the same path as everything else.
Which zone¶
A zone's name is the first path segment of every URL in it, and zone names are global: they are part of a public URL, so two organisations cannot both have assets. Pick names that will still make sense in a year: acme-assets, acme-releases.
Uploads only go into storage zones. A pull zone's content belongs to its origin, and accepting an upload into one would write an object that the next cache miss silently replaces. That is refused with a message saying so, rather than accepted and lost.