Pixelfed: the fediverse photo app whose shipped config starts with federation switched off
Photo Sharing. For Everyone.
At a glance
- What is it?
- A self-hosted, AGPL photo sharing server written in PHP, run through Docker compose with MySQL and Redis. Reading .env.example before the first boot tells you more about the software than any feature list, because federation, registration and mail all arrive disabled.
- Who is it for?
- Pixelfed fits an operator who wants to run their own photo sharing instance and read the configuration before the first boot. Before anything else, work through .env.example, because a stock install has ACTIVITY_PUB and the inbox, outbox and shared inbox all set to false, registration closed with a user cap, and MAIL_HOST pointing at a mail testing service.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- pixelfed/pixelfed7,144 ★ · +37
| Repository | 2026-09-23 | 2026-11-14 |
|---|---|---|
| pixelfed/pixelfed | 7.1k | 7.1k |
37 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Federation and registration both arrive switched off
The ActivityPub block in `.env.example` is set to false five times over: `ACTIVITY_PUB`, `AP_REMOTE_FOLLOW`, `AP_INBOX`, `AP_OUTBOX` and `AP_SHAREDINBOX`. A fresh install is therefore a local photo site until an operator turns those on, which is the right default for anyone copying the example file without reading it and the wrong surprise for anyone expecting federation on first boot. Registration is closed too, with `OPEN_REGISTRATION="false"`, `PF_MAX_USERS="1000"` and `PF_MIN_REGISTRATION_AGE="16"`, so an instance caps its own population and its youngest members by default. Two settings cut the other way: `ENFORCE_EMAIL_VERIFICATION="false"` and `INSTANCE_DISCOVER_PUBLIC="true"`. OAuth is on, the PAT variant is off, and `ENABLE_CONFIG_CACHE` is on.
MySQL 9 and MariaDB 11 are supported, PostgreSQL is best effort
The database line is where most self-hosted surprises live, and the project is unusually blunt about it. MySQL 8 or newer is officially supported, with strict mode not default. MariaDB 11 or newer is also officially supported, and there strict mode is on by default, so the same schema behaves differently between the two supported engines. PostgreSQL 14 or newer is called best effort as of writing and marked not recommended. The stated reason is not performance: the project says it needs to improve the ecosystem to test and validate the codebase as database agnostic, and calls that considerable engineering effort. If you are evaluating Postgres for your instance, you are evaluating an unsupported path, and regression reports are explicitly invited.
Docker compose runs three services and the README gives no compose command
As of September 2026 the project recommends Docker compose, and says the Dockerfile will be the artifact kept current with best practices and latest releases, while a non-Docker install remains supported. The compose file defines three containers, and its header calls MariaDB and Redis optional. The database is `mysql:9` named `pixelfed-db`, with `MYSQL_DATABASE`, `MYSQL_USER`, `MYSQL_PASSWORD` and `MYSQL_ROOT_PASSWORD` all read from `.env`, its data in `./mysql-9-data`, and a `mysqladmin ping` healthcheck that retries three times. Redis is `redis:8-alpine` named `pixelfed-redis`, running with `redis-server --appendonly yes`, data in `./redis-data`, and a `redis-cli ping` healthcheck. The app container is `pixelfed-app`, built from the Dockerfile, publishing `8080:8080`, with `SSL_MODE: "off"` on the assumption that a reverse proxy terminates TLS, and `PHP_OPCACHE_ENABLE` on. Note the comment above the database says MariaDB while the image is mysql:9. Documentation lives on docs.pixelfed.org, and `DOCKER_COMPOSE_SETUP.md` sits in the repository root.
db:
image: mysql:9
container_name: pixelfed-db
restart: unless-stopped redis:
image: redis:8-alpine
container_name: pixelfed-redis
restart: unless-stopped
command: redis-server --appendonly yes pixelfed:
build:
context: .
dockerfile: Dockerfile
container_name: pixelfed-app
restart: unless-stopped
ports:
- "8080:8080"The image compiles ffmpeg from source before it serves a photo
The Dockerfile starts `FROM serversideup/php:8.5-frankenphp` and then builds an ffmpeg of its own, taking `FFMPEG_VERSION=9.0.2` as a build argument you can override with `--build-arg FFMPEG_VERSION`. That step installs a toolchain including cmake, meson, ninja, nasm and yasm, then configures with `--toolchain=hardened` and `--enable-lto`, and the comment next to those two flags explains why: ffmpeg is a tool that parses untrusted user-uploaded media. It builds shared libraries with GPL and version3 enabled and `--disable-ffplay`, `--disable-static` and `--disable-doc` to keep the image smaller. The practical consequence is that your first image build is a compile of a media library, not a pull, so plan for the wait before blaming the network.
Media limits are small enough to shape what a post can be
Six settings decide what reaches the disk. `IMAGE_DRIVER=vips` is the default, with `gd` and `imagick` as the alternatives, and the driver has to be present in the image for the choice to work. `PF_OPTIMIZE_IMAGES="true"` re-encodes on the way in, and `IMAGE_QUALITY="80"` sets where that lands, so originals are not stored as uploaded. The ceiling values are unusually tight for a photo site: `MAX_PHOTO_SIZE="15000"`, `MAX_CAPTION_LENGTH="500"` characters and `MAX_ALBUM_LENGTH="4"`. The container sets `PHP_POST_MAX_SIZE` and `PHP_UPLOAD_MAX_FILE_SIZE` to `500M`, which is the transport limit, not the photo limit. If your users want longer albums or captions, these are the lines to change.
Mail points at a testing service and cloud storage is commented out
The mail block is labelled post-installer, and its defaults are placeholders rather than a working configuration. `MAIL_HOST=smtp.mailtrap.io` with `MAIL_PORT=2525` and `MAIL_AUTO_TLS=true` commented as STARTTLS, which you can set to false to bypass, points at someone else's mail testing service. `MAIL_DRIVER=log` is the safer default while you work on it. Storage is local unless you change it: `PF_ENABLE_CLOUD=false` with `FILESYSTEM_CLOUD=s3`, and every `AWS_` line is commented out. So an instance left alone sends no mail and keeps files on its own disk, which is fine for a test and a problem for a real signup flow that needs verification mail, except that email verification is also off by default.
The front end is Vue 2 built by Laravel Mix, with static analysis wired in
Asset building goes through `webpack.mix.js` with a short set of npm scripts. Development runs mix once, watch and hot recompile on change, watch-poll polls options every second, and production builds with `--production`. The pinned versions tell you the era: Vue 2.6, Bootstrap 4.5, webpack 5.72, Chart.js 2.7, plus jquery, sass and vuex with vue-router. Media playback pulls in hls.js and howler, lazy loading uses infinite-scroll, and the bundled libraries include fancybox, glide, blurhash and a couple of PeerTube p2p media loader packages. On the PHP side the repository carries phpstan.neon, psalm.xml with a psalm-baseline.xml, pint.json, rector.php and phpunit.xml, and translations live in `lang/` with crowdin.yml driving them.
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"production": "mix --production"Machine-written contributions are refused, and the release rhythm is quick
The project states that AI-generated contributions are not accepted: pull requests, patches, documentation, translations, issues or anything else substantially generated by generative AI or large language models will be turned down, and contributors are expected to understand, author and take responsibility for what they submit. Linters, formatters, autocomplete and spellcheckers are explicitly unaffected, so tooling is welcome and generated prose is not. Before any interaction you are asked to read the Code of Conduct; the channels after that are Matrix at #pixeldev, a Mastodon account and [email protected]. Funding comes from NLnet Foundation, NGI0 Discovery and Fastly. The dev branch took a push on November 2, 2026, and v0.15.2, a security update, shipped on October 21, 2026 after v0.15.1 on October 18 and v0.15.0 on October 16.
Editorial conclusion
Pixelfed fits an operator who wants to run their own photo sharing instance and read the configuration before the first boot. Before anything else, work through .env.example, because a stock install has ACTIVITY_PUB and the inbox, outbox and shared inbox all set to false, registration closed with a user cap, and MAIL_HOST pointing at a mail testing service. Budget for the image build too, since ffmpeg is compiled from source. If you need PostgreSQL, know that it is marked best effort and not recommended before you design a schema around it.
Frequently asked questions
what is pixelfed
Pixelfed is a self-hosted photo sharing server for the fediverse, written in PHP and released under the AGPL license, with the tagline Photo Sharing. For Everyone. The README describes it as letting casual shots and creative photography find an audience without algorithmic barriers.
how to install pixelfed
As of September 2026 the project recommends Docker compose, with the compose file defining a mysql:9 database, a redis:8-alpine cache and queue, and the app built from the Dockerfile on port 8080. Non-Docker installs remain supported, and documentation sits at docs.pixelfed.org.
is pixelfed free
The software is open source under the AGPL license, so nothing has to be paid to run it. What costs money is your own hosting, and the Dockerfile builds ffmpeg from source, which makes the first image build a compile rather than a pull.
is pixelfed dead
The dev branch took a push on November 2, 2026, and three releases landed within a week in October: v0.15.0 on October 16, v0.15.1 on October 18 and v0.15.2 on October 21, 2026. That is the activity pattern of a project still being worked on.
is pixelfed safe
The project hardens what it can name: the Dockerfile compiles ffmpeg with a hardened toolchain and comments that ffmpeg parses untrusted user-uploaded media, and registration is closed by default with OPEN_REGISTRATION set to false, a user cap and a minimum registration age. Anything else about your instance's security depends on your configuration and reverse proxy.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pixelfed-pixelfed)Star history chart for your README
[](https://hysenlabs.com/projects/pixelfed-pixelfed)Was this useful?