How I self-hosted Pixelfed on my tiny server with Docker

How I self-hosted Pixelfed on my tiny server with Docker

Pixelfed! An ethical alternative to Instagram. Ethical because this decentralized network is run by enthusiastic users as moderators instead of the "Grow at all costs" corporation, which will be compelled to use your data against your own goodwill if that churns enough profits for them.

The best thing about Pixelfed is that, it's open source, and it's self-hostable. If you have some spare space on your servers, you could spin up a Pixelfed server and interact with the rest of the Fediverse. Isn't that cool? I recently spun up a Pixelfed instance on my server, and this is an explanatory post about the steps required to host an instance for yourself on your server. Let's dive in, shall we?

Before we could dive in...

Note: The instructions mentioned in this post concerns with Pixelfed version 0.11.3 with additional commits upto 352500f . I can't guarentee the instructions will ever work for the uncoming releases. Feel free to get in touch with me at Mastodon or Email if necessary.

Environment Setup

Assuming that you have installed docker and docker-compose on your server, the next thing to note is to set up an .env file for docker-compose of Pixelfed. My .env file for my self-hosted instance is as follows

APP_NAME="Pixelfed"
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=https://pixelfed.lhin.space

APP_DOMAIN="pixelfed.lhin.space"
ADMIN_DOMAIN="pixelfed.lhin.space"
SESSION_DOMAIN="pixelfed.lhin.space"
TRUST_PROXIES="*"

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=mariadb
DB_PORT=3306
DB_DATABASE=somedatabase # Change this
DB_USERNAME=someusername # Change this
DB_PASSWORD=somepassword # Change this

PUID=1000
PGID=1000
MYSQL_DATABASE=somedatabase 		# Change this
MYSQL_USER=someusername 			# Change this
MYSQL_PASSWORD=somepassword			# Change this
MYSQL_ROOT_PASSWORD=somepassword	# Change this

BROADCAST_DRIVER=redis
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_DRIVER=redis

REDIS_SCHEME=tcp
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

# For this setup, you could add any email config as your email provider.
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mail.host
MAIL_PORT=587
MAIL_USERNAME=mailbox@server.name
MAIL_PASSWORD=somepassword
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=mailbox@server.name
MAIL_FROM_NAME=Pixelfed

OPEN_REGISTRATION=false
ENFORCE_EMAIL_VERIFICATION=true
PF_MAX_USERS=1000

MAX_PHOTO_SIZE=15000
MAX_CAPTION_LENGTH=150
MAX_ALBUM_LENGTH=4

ACTIVITY_PUB=true
AP_REMOTE_FOLLOW=true
AP_SHAREDINBOX=true
AP_INBOX=true
AP_OUTBOX=true
ATOM_FEEDS=true
NODEINFO=true
WEBFINGER=true

HORIZON_DARKMODE=true
HORIZON_EMBED=true
INSTANCE_CONTACT_EMAIL=admin@server.name
OAUTH_ENABLED=true
ENABLE_CONFIG_CACHE=false
.env.pixelfed
  • Create a file .env.pixelfed in your server directory.
  • Copy the contents from the above to the .env.pixelfed file.

Make sure to replace the values mentioned under change this with the respective values that the database and mail server complies with. Once this .env file is all set and done, we move on to docker-compose setup.

Docker Setup

The following is my docker-compose.yml file. I'm using the zknt/pixelfed image from the Dockerhub, since it's the most downloaded and actively maintained image of Pixelfed, yet.

version: '3'

networks:
  internal:
    internal: true
  web:
    driver: bridge
    external: true

volumes:
  pixelfed_redis:
    external: true
  pixelfed_mariadb:
    external: true
  pixelfed_storage:
    external: true
  pixelfed_bootstrap:
    external: true

services:
  app:
    container_name: pixelfed-app
    image: zknt/pixelfed:2022-08-06
    restart: unless-stopped
    env_file:
      - .env.pixelfed
    volumes:
      - pixelfed_storage:/var/www/storage
      - pixelfed_bootstrap:/var/www/bootstrap
      - ./.env.pixelfed:/var/www/.env
    networks:
      - web
      - internal
    depends_on:
      - mariadb
      - redis
    labels:
      - traefik.enable=true
      - traefik.http.routers.pixelfed.rule=Host(`pixelfed.lhin.space`)
      - traefik.http.routers.pixelfed.tls=true
      - traefik.http.routers.pixelfed.service=pixelfed
      - traefik.http.routers.pixelfed.tls.certresolver=lets-encrypt
      - traefik.http.services.pixelfed.loadbalancer.server.port=80

  worker:
    container_name: pixelfed-worker
    image: zknt/pixelfed:2022-08-04
    restart: unless-stopped
    env_file:
      - .env.pixelfed
    volumes:
      - pixelfed_storage:/var/www/storage
      - pixelfed_bootstrap:/var/www/bootstrap
      - ./.env.pixelfed:/var/www/.env
    networks:
      - web
      - internal
    depends_on:
      - mariadb
      - redis
    entrypoint: /worker-entrypoint.sh
    healthcheck:
      test: php artisan horizon:status | grep running
      interval: 60s
      timeout: 5s
      retries: 1

  mariadb:
    image: ghcr.io/linuxserver/mariadb:alpine-version-10.5.9-r0
    container_name: pixelfed-mariadb
    restart: always
    networks:
      - internal
    env_file:
      - .env.pixelfed
    volumes:
      - pixelfed_mariadb:/config:rw

  redis:
    image: redis:5-alpine
    container_name: pixelfed-redis
    restart: unless-stopped
    env_file:
      - .env.pixelfed
    volumes:
      - pixelfed_redis:/data
    networks:
      - internal
docker-compose.yml

Copy the following contents to a docker-compose.yml file and keep it in the same directory as the .env.pixelfed file. Change the contents as it pleases you. This is all you need to set up a Pixelfed instance on your server.

Note: Since I'm using traefik to manage my docker images, I tend to have a web network that binds with the traefik docker image. You could use other reverse proxies by removing the labels in the app service and by adding ports: - 80:8080. In this you are redirecting the traffic coming to port 8080 to the docker port 80. More info here

Pre-requisites

In order to run Pixelfed, we need to create external docker volumes first. You could also use bind mounts to local directory. But I tend to use volumes so that I don't have to fiddle around with permission issues. The following commands will create four volumes.

docker volume create pixelfed_bootstrap
docker volume create pixelfed_storage
docker volume create pixelfed_mariadb
docker volume create pixelfed_redis
create-volume.sh

Voilà!

Now for the climax, you need to run docker-compose up -d (?)

Well, not so fast. You need to do so in steps so that the MariaDB and the Redis is set up properly.

  • First, you need to run docker-compose up -d mariadb redis. This will set up the MariaDB and Redis instance. You could also do docker-compose logs -f to check the logs and see what's cooking in there.
  • Once that's done, you should run docker-compose up -d app. This will  spin up the app instance and run all the database migrations that are required.
  • Next, You need to run docker-compose up -d worker. This will spin up the worker instance which will be responsible for Remote fetching account avatars and other ActivityPub stuff.

Once this is done, you could check the logs using docker-compose logs -f to see if there are any errors in the installation. If not, we move on to the next step.

Server Setup

Firstly, you need to create an app key. Run docker-compose exec app php artisan key:generate to generate an app key. This key will be added to your .env.pixelfed file in base64 format.

Now that the instance is set up properly, we need to create an admin user. You could do so by running docker-compose exec app php artisan user:create. Then answer the prompts given on the screen, and you are done.

Troubleshooting

  • Empty user profiles: For a brief moment, I had an issue of getting an empty user profile when remote account is being fetched. It was fixed by running docker-compose exec app php artisan passport:install on my server as mentioned in this issue.

Closing Thoughts

I'm very optimistic about a future where decentralized social media like, Pixelfed, Mastodon and the entirety of Fediverse is a thing. I hope to see this pick up steam among the netizens, and also hope to see the service itself becomes accessible to anyone and everyone. For that to happen, this is my small contribution to anyone who wants to spin up a server for themselves. Feel free to contact me for any assistance.

Have a nice day :)

Show Comments