Install
One binary, one database, one reverse proxy. If you already run Pixelfed, read Migrate instead — this page is for running the binary itself.
What you need
- Linux, x86-64 or ARM64. The binary is static and links nothing, so the distribution does not matter.
- MySQL 8 or MariaDB 10.4+, holding a Pixelfed schema. GrainFed does not create that schema itself: it adopts one.
- A reverse proxy terminating TLS — nginx, Caddy, or whatever you already run. GrainFed listens on plain HTTP on localhost.
- Redis is optional and never authoritative.
Get the binary
curl -LO https://dl.grainfed.waxquixotic.com/grainfed-0.1.0-linux-amd64.tar.gz
curl -LO https://dl.grainfed.waxquixotic.com/SHA256SUMS
sha256sum --check --ignore-missing SHA256SUMS
tar xzf grainfed-0.1.0-linux-amd64.tar.gz
sudo install -m755 grainfed /usr/local/bin/grainfed
grainfed version
Replace amd64 with arm64 on ARM hardware. Both
builds are on the download page.
Point it at an instance
GrainFed reads Pixelfed's .env for its database credentials,
app key, storage paths and mail settings. Run it from the Pixelfed root, or
pass -env.
Start by asking it what it thinks of the instance. This writes nothing — the database session is put into read-only mode at the server, and that is verified rather than trusted:
grainfed doctor
Then run it:
grainfed serve -env /path/to/pixelfed/.env -read-only=false -addr 127.0.0.1:8080
It defaults to a read-only database session. Pointing
GrainFed at an instance you are only evaluating cannot write to it. You have
to pass -read-only=false deliberately, and until you do, the
server will refuse every write and say so.
As a service
[Unit]
Description=GrainFed
After=network.target mariadb.service
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/pixelfed
ExecStart=/usr/local/bin/grainfed serve -read-only=false -addr 127.0.0.1:8080
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Proxy to it, passing the real host through so federation URLs are built correctly:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 64m;
}
Settings of its own
Everything GrainFed adds is GRAINFED_-prefixed, so an adopted
.env can never switch one on by accident. Every one of them is
off, or set to Pixelfed's behaviour, unless you say otherwise.
| Variable | What it does |
|---|---|
GRAINFED_LOG_LEVEL | debug, info (default), warn, error. The federation queue logs every delivery attempt and its backoff at debug. |
GRAINFED_STORAGE | The Laravel storage/ directory, when it is not beside the .env. |
GRAINFED_MAX_EDGE | Long edge, in pixels, that uploads are resized to. Unset keeps Pixelfed's 1920×1080, which for an ordinary 4:3 photo means 1440×1080. |
GRAINFED_SLOW_QUERY_MS | Log any query slower than this. Off unless set. Start at 30. |
GRAINFED_ALLOW_PRIVATE_DELIVERY | Permits federation to private and loopback addresses. For a LAN lab — off by default, because the SSRF guard is what stops a peer turning delivery into a port scanner. |
GRAINFED_ALLOW_HTTP_DELIVERY | Permits plaintext http:// peers. A separate switch from the one above, because they are separate risks: a signed delivery over http leaks the whole activity — the signature authenticates it, it does not hide it. |
Checking it rather than running it
grainfed parity # how much of Pixelfed's surface is served
grainfed probe # call every route; report the ones that cannot work
grainfed resolve @someone@example.social
grainfed optimize # index changes that would make this instance faster
probe exists because registered is not the same as reachable,
and this project has shipped that difference more than once. resolve
exercises the whole outbound federation chain — WebFinger, the SSRF guard, the
fetch budget, the actor validator — against your own configuration, which is
otherwise only testable by waiting for a peer to send you something.
After it is running
Two screens in the admin panel are worth opening on day one. Settings → Status checks the database, object storage, Redis, the queue and mail by actually doing each thing, and reports where the database's memory is going. Mail log records every message the instance has tried to send and what the mail server answered.