Documentation

Getting started

From nothing to a federating instance. This page covers the happy path and the two places people usually get it wrong: the domain names, and the reverse proxy.

The source is not published yet

These are the real commands, but you cannot clone the repository today. Read this as a description of the interface rather than a recipe you can run now. The documentation index says what changes when the code lands.

Build it

Go 1.26 or newer is required to build from source. Nothing else is.

make build
./littlefedi init       # choose "instance"
./littlefedi --config littlefedi.toml

The result is one static executable with CGO disabled. It has no shared library dependencies, no interpreter, and no external database. You can build it on one machine and copy it to another of the same architecture.

Run the wizard

littlefedi init asks the questions that are painful to answer later: single-user or multi-user, the domains, the database, where media lives, whether to join littleMesh, and the address of the reverse proxy it should trust. It writes a complete littlefedi.toml, creates the first administrator, and comments out everything you declined so the file still documents it.

Then open http://localhost:8080 and sign in with that administrator.

That address is for local testing only

init already asked for the web_domain other instances will use. Federation needs that domain served over public HTTPS, not a direct connection to port 8080. Nothing federates until a proxy is in front.

Two domains, one server

Existing single-domain configurations may keep using domain. New installations should use both:

local_domain = "example.com"
web_domain   = "social.example.com"

local_domain is the domain in account handles, the thing people type. web_domain serves the web interface, the API, media, and the ActivityPub objects. When the two differ, the local domain must redirect WebFinger requests to the web domain, or nobody can find your accounts.

Pick these before you federate. Changing the actor domain of a live instance means every remote server holds a cached identity that no longer resolves, and there is no clean way back.

Put a proxy in front

littleFedi listens on loopback and does not terminate TLS itself. Configuration examples for nginx and Caddy ship in the packaging/ directory, along with the littleMesh gateway files.

  • Point A and AAAA records at the proxy and test both address families. If IPv6 is not routed and firewalled properly, do not publish an AAAA record.
  • Set http.proxy_uri to the exact public HTTPS origin.
  • Set http.trusted_proxies to the proxy's address. In the usual single-host topology that is loopback and nothing else. Never put broad internet ranges in there.
  • Permit inbound TCP 80 and 443 only. Keep port 8080, the metrics endpoint, the profiler, the database and SSH off the public network.
  • Use an automated ACME client and alert 21 days before expiry.

Then check the three endpoints that tell you it worked:

curl --fail http://127.0.0.1:8080/health
curl --fail http://127.0.0.1:8080/readyz
curl --fail https://social.example.com/.well-known/nodeinfo

Fill in the instance profile

init offers to write the one-line and paragraph descriptions, the moderation contact and the server rules. That is what /about and every Mastodon client show about your server, and an empty one looks abandoned before anyone has read a post.

You can also do it later from the admin console, without a restart. The config file is the seed and the console is the override; see the instance profile for how the two interact, including the one field where they do not.

Email and SMTP TLS

SMTP defaults to STARTTLS on port 587. Use implicit_tls = true for SMTPS, normally on port 465. Certificate-chain and hostname verification stay enabled in both modes, and there is an administrator SMTP test in the console that only ever sends to your own address.

The escape hatch, and its price

A private relay with a self-signed certificate can opt out with insecure_skip_verify = true or LITTLEFEDI_SMTP_INSECURE_SKIP_VERIFY=true. This accepts any certificate on that connection, not only the one you had in mind. Use it on a trusted network, log the fact, and replace it with a valid certificate. A startup warning is logged for as long as it is on.

Small machines

On a Raspberry Pi Zero W or anything of that size, start here:

low_power = true

[media]
cache_remote = "off"

The preset selects one database connection and one queue worker, a bounded memory cache, one image decoder, a 13 million pixel bound on decoded images (enough for a 4032 by 3024 phone photo), a 1600 pixel cap on stored uploads, cheaper thumbnail resampling, and no dynamic gzip.

Measure on the actual device before making capacity claims. The preset makes the server fit; it does not make the hardware faster.

Other build variants

make build-postgres
make build-s3
make build-postgres-s3
make build-blog

Build tags keep optional dependencies out of the default binary: postgres adds PostgreSQL storage and cross-process streaming, s3 adds S3-compatible media storage and migration, and blog adds static blog generation. If you do not ask for them, they are not linked in.

Your first post

printf 'Hello from a new instance.\n' | \
  ./littlefedi --config littlefedi.toml post

./littlefedi --config littlefedi.toml post --username alice \
  --markdown --visibility private post.md

Then follow someone remote from the web interface, wait for them to appear in the home timeline, and check the queue drained. That round trip is the real smoke test: everything before it only proves the process starts.

Before you invite anyone

  • Keep registrations closed until somebody is willing to moderate.
  • Enroll TOTP for the administrator, store the recovery codes offline, then turn on require_admin_mfa and confirm you can still get in.
  • Publish rules, a moderation contact and terms. The policy checklist lists what they should cover.
  • Take a backup and restore it somewhere else. A backup you have never restored is a belief, not a backup.
  • Read the deployment guide for the service account, the file modes, the descriptor limit and the alerts.