Are you sick of data mining and ads? Want to share photos in an Instagram like way with friends and keep control over your data? Pixelfed is an open source alternative that's fairly easy to self host.

This guide will show you an easy way to get an instance up in no time with the help of Traefik and Docker. If you already have a server with Traefik running then continue. Otherwise I recommend you read my previous post and you'll be back here soon.

It's also possible to skip using Traefik and put your own reverse proxy (f.e nginx) in front of Pixelfed. Using https is a must today.

Bear in mind that the current release is v0.9.4, so things are still a work in progress. With that said, it's working fine for me and my group of friends.

Prerequisites

This guide assumes some general knowledge of Linux and that you have a server available with these services installed:

For cheap and good servers, checkout DigitalOcean or Hetzner. Also I always recommend this guide when setting up a new VPS.

If you want to use Digital Ocean feel free to use my referral link to get $100 for your server or my Hetzner link to get €20 😊

Setup

We start with cloning the repository to its own directory and build the docker image from there. There are pre-built ones, like this, but in this case I recommend building your own.

Let's make a directory for your data to live in, as sudo if needed.

sudo mkdir -p /opt/pixelfed_source
sudo chown $USER:$USER /opt/pixelfed_source

Fetch the repo, checkout the commit of the release then build the image (replace v0.9.4 in the tag with whatever the latest version is for easy rollback) and wait...

git clone git@github.com:pixelfed/pixelfed.git /opt/pixelfed_source
# OR 
git clone https://github.com/pixelfed/pixelfed.git /opt/pixelfed_source
cd /opt/pixelfed_source
git checkout v0.9.4
docker build -t pixelfed:v0.9.4 . 

Now we can create a directory for the service.

sudo mkdir -p /opt/pixelfed
sudo chown $USER:$USER /opt/pixelfed
cd /opt/pixelfed

Configuration

Next, let's edit the configuration.

cp ../pixelfed_source/.env.example .env
nano .env

Replace all *_DOMAIN with your hostname and APP_URL=http://localhost with your full hostname including protocol.

We will have Pixelfed generate an APP_KEY for us later, so don't touch that one.

I'm using Postgres, mostly because MySQL was throwing weird errors but also because it's what I generally use, so these need to change.

DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432
DB_DATABASE=pixelfed
DB_USERNAME=pixelfed
DB_PASSWORD=USE_A_PROPER_PASSWORD

Since we are using docker and an internal network for the database and Redis, also change this: REDIS_HOST=redis

If you don't want federation, change the following.

ACTIVITY_PUB=false
REMOTE_FOLLOW=false

You can also edit these:

# For a personal server, I don't really feel this is necessary
ENFORCE_EMAIL_VERIFICATION=false
# I had trouble running Horizon (background jobs) embedded in Docker
HORIZON_EMBED=false

Docker

Next we need that internal network for docker.

docker network create pixelfed

And now we can add a docker-compose file.

touch docker-compose.yml
nano docker-compose.yml

Copy and paste this.

version: '3'
services:

  app:
    image: pixelfed:v0.9.4
    restart: unless-stopped
    # This is for Traefik
    labels:
       - traefik.enable=true
       - traefik.frontend.rule=Host:pixelfed.example.com
       - traefik.port=80
       - traefik.docker.network=web
    env_file:
      - ./.env
    volumes:
      - "app-storage:/var/www/storage"
      - "app-bootstrap:/var/www/bootstrap"
      # We can remove this after generating APP_KEY
      - ./.env:/var/www/.env
    networks:
      - web
      - pixelfed

  db:
    image: postgres:9.6.4
    restart: unless-stopped
    networks:
      - pixelfed
    volumes:
     - db-data:/var/lib/postgresql/data
    environment:
     - POSTGRES_PASSWORD=${DB_PASSWORD}
     - POSTGRES_USER=${DB_USERNAME}

  worker:
    image: pixelfed:v0.9.4
    restart: unless-stopped
    env_file:
      - ./.env
    volumes:
      - "app-storage:/var/www/storage"
      - "app-bootstrap:/var/www/bootstrap"
    networks:
      - web  # Required for ActivityPub
      - pixelfed
    command: gosu www-data php artisan horizon

  redis:
    image: redis:5-alpine
    restart: unless-stopped
    volumes:
      - "redis-data:/data"
    networks:
      - pixelfed

# Adjust your volume data in order to store data where you wish
volumes:
  redis-data:
  db-data:
  app-storage:
  app-bootstrap:

networks:
  pixelfed:
    internal: true
  web:
    external: true

☝️ Remember to replace pixelfed.example.com in traefik.frontend.rule with your hostname. Also make sure to add/replace your Traefik network (in my case web) in networks.

If you are not using Traefik, replace the labels section for app with this to be able to reverse proxy.

  ports:
    - "127.0.0.1:8080:80"

Now we should be able to start the services and generate an APP_KEY.

docker-compose up -d
docker-compose exec app php artisan key:generate
# Make sure there's a value
cat .env | grep APP_KEY 

And now we can restart, clear the cache and run the migrations on the database.

docker-compose restart app
docker-compose exec app php artisan config:cache
docker-compose exec app php artisan migrate
# Answer yes

That's it 👏 Your Pixelfed instance should be up and running. Now go register a user! You can do that either on the web or through your terminal.

docker-compose exec app php artisan user:create

pixelfed-1

Site admin

Then you probably want to make yourself an admin of the site...

docker-compose exec app php artisan user:admin [username]

Updating

To update, just do a git pull and checkout the newest tag. Then build the image again...

cd /opt/pixelfed_source
git checkout dev
git pull origin dev
git checkout v0.10.0
docker build -t pixelfed:v0.10.0 .

... and when finished you can change your docker-compose.yml.

cd /opt/pixelfed
nano docker-compose.yml
  app:
    image: pixelfed:v0.10.0
  #...
  worker:
    image: pixelfed:v0.10.0

Then restart and run the migrations.

docker-compose up -d
docker-compose exec app php artisan migrate
# Answer yes

Also if you want to free up some disk space you can remove the old image(s).

docker images
docker rmi [IMAGE ID]
# Or if you're feeling adventurous
docker image prune

The end

I hope you enjoy your social photo sharing and don't hesitate to drop me a line for help (with this guide, for Pixelfed issues check out their Help center).