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 rather than writing a config file.
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 with 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 rather than held in memory, so the size of an upload is bounded by CDN_MAX_UPLOAD_BYTES and the disk, not 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.