Documentation
Static blogs
Long-form writing deserves a quiet, durable home. littleFedi can turn selected fediverse posts into a conventional static site, so a piece stays federated and also stays readable in ten years by anyone with a browser and no account.
Turning it on
Blog generation is an optional build, so a server that will never use it never links the code in.
make build-blog
./littlefedi --config littlefedi.toml admin blog allow --username alice
[blog]
enabled = true
output_dir = "blogs"
directory_enabled = true
slug_format = "{year}/{month}/{day}/{title}"
allow_user_slug_format = true
all_accounts = false
Generated blogs are listed at /blogs. Set
directory_enabled = false to remove that page; each author can also
opt out individually, which hides them from the list without changing their
blog's direct address.
Every generated blog publishes /@username/blog/sitemap.xml. When
the directory is on, /sitemap.xml indexes those per-blog maps and
/robots.txt advertises the index. Opted-out blogs are left out of
both.
Who may blog
Nobody, until an administrator says so, per account, with
admin blog allow or the button in the admin accounts page. That is
the right default: a static site is public writing under the instance's name.
Set all_accounts = true to grant it to every local account instead.
While that is on, the per-account permission is ignored rather than merged, so
the admin button and admin blog allow refuse to run and say why.
Turning it back off returns the instance to whatever each account was
individually granted, because those grants were never overwritten.
Publishing a post
An allowed account gets a Blog post option in the composer. From the shell:
./littlefedi --config littlefedi.toml post --blog
./littlefedi --config littlefedi.toml post --blog --blog-slug my-permalink
./littlefedi --config littlefedi.toml admin blog rebuild --username alice
The post federates exactly like any other post. The static page is an additional rendering of the same thing, not a separate publication you have to keep in sync.
Permalinks
A post's address comes from slug_format, rendered once when the post
is first published and then stored. Editing the post later never moves its URL,
which is the whole reason a static blog is worth having.
| Placeholder | Expands to |
|---|---|
{year} {month} {day} | Publication date, as shown on the page |
{title} | The post's first line, lowercased and hyphenated |
{id} | The full status id |
{shortid} | The first 8 characters of the status id |
The template must contain {title}, {id} or
{shortid}, must not start or end with a slash, and must not begin
with a segment the generator owns: tags, archive,
media, feed.xml, style.css,
index.html. An invalid template is rejected at startup rather than
at the moment somebody publishes.
With allow_user_slug_format = true, the default, each author can
override the template for their own blog. Set it to false to impose
one style across the instance. Either way an author can type a custom URL for a
single post in the composer. Duplicate slugs get a -2,
-3 suffix.
Posts published before permalinks existed keep working: the old
/@username/blog/<status-id>/ address is regenerated as a
static redirect, and Atom entry ids stay pinned to the status id, so no feed
reader resurfaces an old post as new.
What a blog contains
Each blog lives at /@username/blog/ and holds:
- An index, and a permanent page for every selected post.
- Hashtag indexes and a chronological archive.
- An Atom feed at
feed.xml. - A small static theme with no application JavaScript and no database work on a page request.
- Self-contained copies of local attachments. S3 attachments keep their public object URLs.
What can never leak into it
Only public, top-level, non-boost posts that were explicitly marked as blog posts are published. Replies, followers-only posts and direct messages cannot end up on the static site. That is a property of the generator, not a setting you can accidentally invert.
Appearance
Four themes ship: Marginalia for long reads, with each post's date and tags in a margin column; Ledger for technical notes, with monospace metadata on a strict grid and code that breaks out of the reading column; Kiosk for short posts and links, with a full-width colour band and tags as pills; and Dusk, a dark-first journal with no rules and one amber mark per post.
All four work without JavaScript, without images, in light and dark, and load no external fonts. Authors can paste or upload their own CSS on top, capped at 64 KB, and there is a Rebuild blog now button in the same place. See the theming guide.
Rebuilds and the one real limit
Rebuilds run through the durable job queue and replace the complete site only after rendering succeeds. A failed build leaves the previous site standing. Publishing a post rebuilds that post's page and leaves the stylesheet alone; changing your theme or CSS queues a full rebuild, but only when something actually changed.
Blog output is a single-process feature. Leave it disabled in a multi-process deployment until shared publication and cross-process rebuild ownership exist. This is stated here rather than discovered later, when two processes have quietly overwritten each other's output.