The other week I had written about Pixelfed and my plans for using it. Since this is self-hosted software and I spent a fair amount of time setting it up, I wanted to write out a detailed installation guide. Hopefully, it helps someone else out there looking to create their own setup.
Starting with the basics
The basics of my setup are:
- An Intel i3 Intel NUC machine 1
- Running Ubuntu Linux 20.04
I have Docker and docker-compose installed.
Begin with the Pixelfed Repo
Start here: https://github.com/pixelfed
Clone that repository locally on your machine. This article is based upon the Pixelfed v0.11.2 release.
Make a few changes:
- Modify
composer.json
andcomposer.lock
to include"beyondcode/laravel-self-diagnosis": "^1.5"
. This is needed because of issue #3150. Hopefully this is fixed in Pixelfed v0.11.3+! - Add
- "./.env.docker:/var/www/.env"
indocker-compose.yml
for the worker service. It’s possible this is not needed, but I added it during a troubleshooting step and figure better safe than sorry.
Once those changes are complete, run docker-compose build
. This will use the Dockerfile from the repository to build docker images. You can examine the Dockerfile by looking at what is specified in the docker-compose.yml
file:
build:
context: .
dockerfile: contrib/docker/Dockerfile.apache
image: pixelfed
Your Docker Compose File
With the Pixelfed image built, turn your attention to the other services spec’d in the docker-compose.yml
file.
First off, switch the db
service to use mariadb.
db:
image: mariadb:latest
With v0.11.2 of Pixelfed I initially tried and failed to use MySQL. I found this Github issue #2989 which explains the problem I was seeing, and perhaps there are other problems with using MySQL.
Next, start your containers with docker-compose up -d
. Give them a second to load, and check their status with docker-compose ps
.
With the containers running follow Pixelfed’s install guide.
Pixelfed Install Guide Steps
A very useful reference is Pixelfed’s Installation Guide. Please note: there is a potential re-write of this guide coming sometime in 2022, as mentioned in Pixelfed’s Discord server.
From the guide, use these specific sections:
- Configure environment variables
- Setting up services
Environment Variables
Follow Pixelfed’s instructions to set APP_NAME
, APP_URL
, APP_DOMAIN
, ADMIN_DOMAIN
, and SESSION_DOMAIN
.
These are my general settings:
## General Settings
APP_NAME="Pixelfed"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://pix.mattedwards.org
APP_DOMAIN="pix.mattedwards.org"
ADMIN_DOMAIN="pix.mattedwards.org"
SESSION_DOMAIN="pix.mattedwards.org"
Note that the URL is a full URL, while the domains are simply the host info.
Side note on hosting and DNS: Depending on where you are installing Pixelfed (your own homelab server, or a cloud droplet like DigitalOcean or Linode) you should consider how that domain name you are giving to Pixelfed is being resolved and routed. Are you using Traefik as a reverse proxy for your homelab server? Explaining that is beyond the scope of this article, but is important to think about!
For the database settings, you can use the MYSQL_* settings with MariaDB. There are MariaDB specific environment variables but when not supplied the MySQL ones are used instead. Make sure to set a strong database password (even for these internally-hosted services behind a reverse proxy!). If you change the database port, make sure other containers are appropriately configured.
## Databases (MySQL)
DB_CONNECTION=mysql
DB_DATABASE=pixelfed_prod
DB_HOST=db
DB_PASSWORD=<<REPLACE_WITH_YOUR_PASSWORD>>
DB_PORT=3306
DB_USERNAME=pixelfed
# pass the same values to the db itself
MYSQL_DATABASE=pixelfed_prod
MYSQL_PASSWORD=<<REPLACE_WITH_YOUR_PASSWORD>>
MYSQL_RANDOM_ROOT_PASSWORD=true
MYSQL_USER=pixelfed
I left the Postgres values commented out in the file. You may choose to delete them, if you prefer.
For redis make sure to choose a strong password.
## Cache (Redis)
REDIS_CLIENT=phpredis
REDIS_SCHEME=tcp
REDIS_HOST=redis
REDIS_PASSWORD=<<REPLACE_WITH_YOUR_PASSWORD>>
REDIS_PORT=6379
REDIS_DATABASE=0
For ActivityPub federation, which allows you to follow different Pixelfed servers - and even Mastodon servers! - you can set these flags to true. If you’re simply experimenting and would rather not risk exposing your server to the Fediverse just yet, you can leave these set to their default FALSE values and flip them TRUE later on.
## ActivityPub Federation
ACTIVITY_PUB=true
AP_REMOTE_FOLLOW=true
AP_SHAREDINBOX=true
AP_INBOX=true
AP_OUTBOX=true
ATOM_FEEDS=true
NODEINFO=true
WEBFINGER=true
Finally, a few miscellaneous settings I have enabled.
INSTANCE_PUBLIC_HASHTAGS=true
should be allowing my hashtags to be available to all users (right now, it’s just me!).
INSTANCE_PUBLIC_LOCAL_TIMELINE=true
enables a public timeline, so I can share my public posts.
STORIES_ENABLED=true
Instagram-like Stories functionality, enabled mostly for fun.
APP_TIMEZONE=America/New_York
to ensure my post times are accurate.
OPEN_REGISTRATION=false
as I do not want rando’s registering on my personal Pixelfed instance. If I wanted to give someone access, I’ll create an account for them via the command line.
Setting up Services
These tasks need only be performed one time following the initial setup. You can run all of these commands in a specific container using this syntax:
docker-compose exec CONTAINER COMMAND
Which tells docker-compose to run COMMAND within the specified CONTAINER. Note that both the app
and worker
containers share an image and volume storage; running a command in either one should be fine and I have not noticed a difference.
To start, generate an APP_KEY
using the app container:
docker-compose exec app php artisan key:generate
This key prints out to the command line and should be automatically inserted into your .env.docker
configuration file. Verify by opening the file.
Next, link your storage:
docker-compose exec app php artisan storage:link
Run database migrations. This would need to be done again when upgrading Pixelfed to a newer version, as well.
docker-compose exec app php artisan migrate --force
Enable support for location on posts. This is just a simple list of common cities and does not include places.
docker-compose exec app php artisan import:cities
If you chose to enable ActivityPub Federation run the below. If not, you can always do this later.
docker-compose exec app php artisan instance:actor
According to Pixelfed’s docs, “Routes should be cached whenever the source code changes or whenever you change routes. Every time you edit your .env file, cache config.” So now run:
docker-compose exec app php artisan route:cache
docker-compose exec app php artisan view:cache
docker-compose exec app php artisan config:cache
Finally, we must deal with Job Queueing. I got this working with Laravel Horzion, and have no experience with or opinion on Queue Worker.
docker-compose exec worker php artisan horizon:install
docker-compose exec worker php artisan horizon:publish
docker-compose restart worker
Note that I’m switching to the worker
container in the above commands. The purpose of this container is to run Laravel Horzion. You can see this in the docker-compose.yml
line which tells the container to run it at start:
command: gosu www-data php artisan horizon
The Pixelfed guide includes steps to setup a systemd job which runs Horizon. You need not do that with the docker setup. The worker
container is handling the Horizon queues.
The final command above was to restart the worker
container. Horizon is now running.
Side Notes
- I skipped setting up email since I’m planning on this being a private instance just for me. On the cheap you could setup your gmail account with an app password, or you could configure any SMTP solution you like.
Web UI
My setup runs self-hosted on that little Intel NUC sitting atop my desk. I route traffic to it using Traefik Proxy.
I will not get into detail in this post on how to configure Traefik, but I will share my docker labels being used. These labels are applied on the app
container.
labels:
- "traefik.enable=true"
- "traefik.docker.network=web"
- "traefik.http.routers.pixelfed.rule=Host(`pix.mattedwards.org`)"
- "traefik.http.routers.pixelfed.entryPoints=secure"
- "traefik.http.routers.pixelfed.tls=true"
- "traefik.http.routers.pixelfed.service=pixelfed"
- "traefik.http.services.pixelfed.loadbalancer.server.port=80"
- "traefik.http.services.pixelfed.loadbalancer.server.scheme=http"
From top to bottom, these labels are doing the following:
- Enabling this container and telling Traefik to route traffic to it via my
web
docker network. - Identifying that Traefik should send requests for the host
pix.mattedwards.org
coming in via secure entry point (TLS/443). - Naming the service, so in the final labels I can tell Traefik to route traffic to Pixelfed on port 80 via http.
Getting the first user
With Pixelfed up, running, and route-able you can now configure one or more users. I prefer to do this via the command line. I do not need to register users via the web and I do not need to worry about having a working email provider to send out user account confirmation emails.
This guide: https://docs.pixelfed.org/running-pixelfed/administration.html#user-management
Contains a quick run-down of the user management commands.
docker-compose exec app php artisan user:create
Now, follow the prompts. Ensure that email verification = yes, to avoid having to send an email and confirm the user. If this is your first user / yourself, choose the Make Admin option.
Public profile pages
You can easily link to someone’s public profile. Images they post with Public visibility will show up here. Here is mine!
https://pix.mattedwards.org/matt
Other Excellent Resources
- Pixelfed’s discord. @pixelfed on Mastodon.social.
- Pixelfed Beta with Docker and Traefik
Specific model is BOXNUC8i3BEK1. ↩︎