Installing Pixelfed Glitch on a Raspberry Pi

Although the official Pixelfed Glitch Docker docs are fairly short, I found a few rough edges when installing it on a Raspberry Pi. This guide pulls the official instructions together with the fixes I needed along the way.

This uses the Docker version of Pixelfed Glitch, with MariaDB and Redis running as Docker containers.


Step 1. Install Docker

Pixelfed Glitch will run inside Docker containers. This means we do not need to manually install PHP, MariaDB, Redis, Node, Composer, or most of the other application dependencies on the Raspberry Pi itself.

i. Update the package list:

sudo apt update && sudo apt upgrade

ii. Install the packages needed to add Docker's repository:

sudo apt install -y ca-certificates curl

iii. Create the keyrings directory:

sudo install -m 0755 -d /etc/apt/keyrings

iv. Download Docker's GPG key:

sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc

v. Make the key readable:

sudo chmod a+r /etc/apt/keyrings/docker.asc

vi. Add Docker's repository:

sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

vii. Update the package list again:

sudo apt update

viii. Install Docker and the Compose plugin:

sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

ix. Check Docker is running:

sudo systemctl status docker

x. Enable Docker to start at boot:

sudo systemctl enable docker.service
sudo systemctl enable containerd.service


Step 2. Allow your user to run Docker

By default, Docker commands need sudo. To run docker compose as your normal user, add your user to the docker group.

i. Create the group, if it does not already exist:

sudo groupadd docker 2>/dev/null || true

ii. Add your user to it:

sudo usermod -aG docker $USER

iii. Log out of SSH and log back in, or reboot the Pi.

iv. Test Docker without sudo:

docker run hello-world

If this works, Docker is ready.


Step 3. Create the Pixelfed Glitch directory

I installed Pixelfed Glitch under my home directory:

cd /home/pi
mkdir -p pixelfed-glitch
cd pixelfed-glitch

Change /home/pi to match your own username if needed.


Step 4. Download the Docker files

Download the Docker Compose file and the example environment file from the Pixelfed Glitch repository:

curl -fsSL https://raw.githubusercontent.com/pixelfed-glitch/pixelfed/develop/docker-compose.yml -o docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/pixelfed-glitch/pixelfed/develop/.env.docker -o .env

The docker-compose.yml file defines the containers. The .env file holds site-specific settings such as the domain name, database password, upload limits, email settings, and Docker image tags.


Step 5. Edit the environment file

Open the .env file:

nano .env

At minimum, change the following values.

Set the name of the site:

APP_NAME="My Pixelfed Site"

Set the domain name, without https:// and without a trailing slash:

APP_DOMAIN="photos.example.com"

Leave APP_URL like this:

APP_URL="https://${APP_DOMAIN}"

Leave ADMIN_DOMAIN like this:

ADMIN_DOMAIN="${APP_DOMAIN}"

Set a public contact email address:

INSTANCE_CONTACT_EMAIL="[email protected]"

Set a secure database password:

DB_PASSWORD="CHANGE_THIS_TO_A_LONG_RANDOM_PASSWORD"

If you do not plan to send email at first, you can disable mandatory email verification:

ENFORCE_EMAIL_VERIFICATION="false"

Make sure OAuth is enabled, as this is needed for Pixelfed mobile apps:

OAUTH_ENABLED="true"

Leave APP_KEY empty at this stage:

APP_KEY=

Pixelfed will generate this later. If you ever set it manually, it must be one single Laravel key, for example:

APP_KEY=base64:CHANGE_THIS_TO_ONE_VALID_KEY_ONLY

Do not paste two keys together on the same line.


Step 6. Prepare Pixelfed's storage directories

The Docker image expects several Laravel storage paths to exist. Creating them now avoids a startup error such as:

Please provide a valid cache path.

Run:

cd /home/pi/pixelfed-glitch

sudo mkdir -p docker-compose-state/data/pixelfed/storage/app/public
sudo mkdir -p docker-compose-state/data/pixelfed/storage/framework/cache/data
sudo mkdir -p docker-compose-state/data/pixelfed/storage/framework/sessions
sudo mkdir -p docker-compose-state/data/pixelfed/storage/framework/testing
sudo mkdir -p docker-compose-state/data/pixelfed/storage/framework/views
sudo mkdir -p docker-compose-state/data/pixelfed/storage/logs
sudo mkdir -p docker-compose-state/data/pixelfed/storage/docker/lock
sudo mkdir -p docker-compose-state/data/pixelfed/cache

sudo chown -R 33:33 docker-compose-state/data/pixelfed/storage
sudo chown -R 33:33 docker-compose-state/data/pixelfed/cache

User ID 33 is www-data, which is the user Pixelfed runs as inside the container.


Step 7. Start Pixelfed Glitch

Start the containers:

docker compose up -d

This downloads the Pixelfed Glitch, MariaDB, and Redis images, creates the containers, and starts the first-time setup.

Check the containers:

docker compose ps

You should eventually see web, worker, cron, db, and redis as Up.

To watch the logs:

docker compose logs --tail=100 --follow

If you only want the web container logs:

docker compose logs --tail=100 web


Step 8. Generate the application and OAuth keys

If the site shows a 500 error and the logs mention either of these:

No application encryption key has been specified.
Invalid key supplied

run the following commands:

docker compose exec web php artisan key:generate --force
docker compose exec -u www-data web php artisan passport:keys --force

Then clear and rebuild Pixelfed's cached config:

docker compose exec -u www-data web php artisan view:clear
docker compose exec -u www-data web php artisan config:clear
docker compose exec -u www-data web php artisan cache:clear
docker compose exec -u www-data web php artisan config:cache

Restart the Pixelfed containers:

docker compose restart web worker cron


Step 9. Stop first-time setup from running again

After the first-time setup has completed and the keys have been created, edit .env again:

nano .env

Add this line:

DOCKER_APP_RUN_ONE_TIME_SETUP_TASKS="0"

This stops Pixelfed from trying to recreate encryption keys on every container start.

If this is not set, the container may restart repeatedly with an error like:

Encryption keys already exist. Use the --force option to overwrite them.

Restart the stack:

docker compose down
docker compose up -d

Do not use docker compose down -v, as that removes Docker volumes.


Step 10. Check the site

Open your Pixelfed URL in a browser:

https://photos.example.com

If you are using NGINX as a reverse proxy, make sure it points to the Docker web port. In the default Pixelfed Glitch Docker file this is:

8080

So the proxy target is:

http://127.0.0.1:8080

Check the running containers:

docker compose ps

If you see a 502 error, the web container is probably not running yet, or it is restarting. Check:

docker compose logs --tail=200 web


Step 11. Create the first user

Create the first account:

docker compose exec -u www-data web php artisan user:create

Follow the prompts.

To make the user an admin:

docker compose exec -u www-data web php artisan user:admin USERNAME

To manually verify an email address:

docker compose exec -u www-data web php artisan user:verifyemail USERNAME

For example:

docker compose exec -u www-data web php artisan user:admin rob
docker compose exec -u www-data web php artisan user:verifyemail rob


Step 12. Create another user

Run the same create command again:

docker compose exec -u www-data web php artisan user:create

Follow the prompts and enter the new username.

For example:

bnw

Only run the admin command for accounts that should have admin rights.


Step 13. Useful checks

Check container status:

docker compose ps

Show recent logs:

docker compose logs --tail=200 web

Check the current Pixelfed config values:

docker compose exec -u www-data web php artisan tinker --execute='
echo "app.url=".config("app.url").PHP_EOL;
echo "oauth=".(config("pixelfed.oauth_enabled") ? "true" : "false").PHP_EOL;
echo "session.domain=".config("session.domain").PHP_EOL;
'

Check the application key:

grep '^APP_KEY=' .env

A valid key should look like one single line:

APP_KEY=base64:LONG_RANDOM_STRING_HERE

Check the OAuth key files:

docker compose exec -u www-data web ls -l storage/oauth-private.key storage/oauth-public.key


Step 14. Mobile app login and 2FA

The web version worked fine for me with 2FA enabled.

The mobile app login flow was different. With 2FA enabled, the official Pixelfed app and Impressia both opened a web login pop-up, accepted the username, password, and 2FA code, then stayed in the web version inside the pop-up instead of returning to the app.

The workaround was:

  1. Keep 2FA enabled on the admin account.
  2. Use a separate non-admin account for mobile app login.
  3. Disable 2FA on that non-admin account before logging in to the apps.

If the web interface will not disable 2FA and clicking the green “Enabled” button only adds # to the URL, disable it from the database.

First check the 2FA column names:

docker compose exec -u www-data web php artisan tinker --execute='
print_r(array_values(array_filter(
    Schema::getColumnListing("users"),
    fn($c) => str_contains(strtolower($c), "two") || str_contains(strtolower($c), "2fa") || str_contains(strtolower($c), "otp")
)));
'

On my install the columns were:

2fa_enabled
2fa_secret
2fa_backup_codes
2fa_setup_at

To disable 2FA for a user called bnw:

docker compose exec -u www-data web php artisan tinker --execute='
DB::table("users")->where("username", "bnw")->update([
    "2fa_enabled" => false,
    "2fa_secret" => null,
    "2fa_backup_codes" => null,
    "2fa_setup_at" => null,
]);
echo "2FA disabled for bnw\n";
'

After that, app login worked.


Step 15. Reboot behaviour

The docker-compose.yml file uses:

restart: unless-stopped

This means the containers should come back up after a reboot, as long as Docker itself starts on boot.

Check Docker is enabled:

systemctl is-enabled docker

If needed:

sudo systemctl enable docker

After a reboot, check Pixelfed:

cd /home/pi/pixelfed-glitch
docker compose ps

One thing to remember: if you run this command:

docker compose down

the containers are removed. Docker cannot restart removed containers at boot. To recreate and start them:

cd /home/pi/pixelfed-glitch
docker compose up -d


Step 16. Backups

At minimum, back up the Pixelfed Glitch install directory:

/home/pi/pixelfed-glitch

This contains:

docker-compose.yml
.env
docker-compose-state/

The .env file contains secrets, including the database password and application key, so store backups securely.

The docker-compose-state directory contains the MariaDB data, Redis data, Pixelfed storage, and cache folders. For a live database, a proper database dump is safer than only copying files while containers are running.

A simple manual MariaDB dump can be created with:

cd /home/pi/pixelfed-glitch
docker compose exec db mariadb-dump -u pixelfed -p pixelfed_prod > pixelfed_db_backup.sql

You will be prompted for the database password from .env.


Troubleshooting notes


Docker permission denied

If you see:

permission denied while trying to connect to the docker API at unix:///var/run/docker.sock

your user is not in the docker group, or the current login session has not picked up the new group membership.

Fix:

sudo usermod -aG docker $USER

Then log out and back in.


Missing cache path

If the web container restarts and logs show:

Please provide a valid cache path.

create the Laravel storage and cache folders from Step 6.


Invalid application key

If the site shows a 500 error and logs show:

Unsupported cipher or incorrect key length

check .env:

grep '^APP_KEY=' .env

The key must be one single key. It must not look like this:

APP_KEY=base64:KEY_ONE=base64:KEY_TWO

To replace it on a new install:

new_key="base64:$(openssl rand -base64 32)"
sudo sed -i.bak "s|^APP_KEY=.*|APP_KEY=${new_key}|" .env

Then clear the caches:

docker compose exec -u www-data web php artisan view:clear
docker compose exec -u www-data web php artisan config:clear
docker compose exec -u www-data web php artisan cache:clear
docker compose exec -u www-data web php artisan config:cache
docker compose restart web worker cron


First-time setup keeps running

If the web container keeps restarting and logs show:

Encryption keys already exist. Use the --force option to overwrite them.

set this in .env:

DOCKER_APP_RUN_ONE_TIME_SETUP_TASKS="0"

Then restart:

docker compose down
docker compose up -d


Sources: Pixelfed Glitch Docker installation docs Pixelfed Glitch configuration docs Docker Engine Debian installation docs Docker Linux post-installation docs