User Tools

Site Tools


computing:pix3lfed

  • pixelfed
  • Jonathan Haack
  • Haack's Networking
  • support@haacksnetworking.org

pixelfed


Introduction - Setting up Pixelfed on Debian

This tutorial provides users of Debian GNU/Linux with a roadmap for installing a Pixelfed instance. These isntructions are drawn from the Pixelfed documentation. Most steps were straightforward, however, there were a few issues not covered in their documentation, namely, special permissions for some OAUTH bits, initializing of storage, and a few other things. As with most other tutorials on this Wiki, make sure you first have a hardened VPS w/ LAMP ready to go - if not, head over to Apache Survival first and set that up. Okay, here we go!

Step 1: LAMP Requirements

Your LAMP stack might not have all php dependencies, redis, and/or imagick. Let's make sure those are installed. Also you should be using mpm_event with php8.4-fpm - not the legacy handler. We will also make sure to install git and ensure that you installed all LAMP-bits properly:

sudo apt update
sudo apt install php8.4-fpm php8.4-mysql php8.4-curl php8.4-gd php8.4-mbstring php8.4-xml php8.4-zip php8.4-bcmath php8.4-intl php8.4-redis php8.4-imagick php8.4-imap php8.4-ldap php git apache2 mariadb-server* imagick* redis* -y
sudo systemctl restart php8.4-fpm

If you need help switching to mpm_event, head over to the WordPress tutorial which has an adaptable codeblock (midway down) that purges the legacy handler and switches you over to mpm_event. Once you are sure these modules are installed and that you have the correct php handler, make sure they are enabled:

sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod cache
sudo a2enmod rewrite
sudo a2enmod setenvif
sudo a2enmod mpm_event
sudo a2enmod rewrite
sudo a2enmod proxy
sudo a2enmod proxy_fcgi
sudo a2enmod mime
sudo a2enmod expires
sudo a2enmod deflate
sudo a2enconf php8.4-fpm
sudo apache2ctl configtest  
sudo systemctl restart apache2
sudo systemctl restart php8.4-fpm

After that, let's make sure fpm is ready for simultaneous connections by opening up sudo nano /etc/php/8.4/fpm/pool.d/www.conf and adjusting these settings to something like the suggestions below:

pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18

Of course, adjust these to your use case and expected amount of users. The suggestions above should work well for 100-200 users with roughly 10-40 using services at the same time (or overlapping). You should also make sure that your php memory is boosted a bit as well as matching (or exceeding) the Pixelfed upload limits and caps. To do that, open sudo nano /etc/php/8.4/fpm/php.ini and enter something like:

upload_max_filesize = 5G        
post_max_size = 5G
memory_limit = 512M                
max_execution_time = 600
max_input_time = 600

My settings are very aggressive as there are some other things I do on this box. You can simply match Pixelfed's settings if you prefer. Okay, it's now time for DB creation.

Step 2: Set up Your Database

Create a new database named 'pixel' (for example) with a dedicated user for security. Log in to MySQL with mysql -u root -p and enter something like:

CREATE DATABASE pixel CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'pixel'@'localhost' IDENTIFIED BY 'strongpass';
GRANT ALL PRIVILEGES ON pixel.* TO 'pixel'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Okay, now that the db is setup, it is time to download and configure Pixelfed.

Step 3: Download, Configure, & Initialize Pixelfed & It's Virtual Environment

Pixelfed is in its infancy so use the dev branch until the stable version is released:

cd /var/www
git clone -b dev https://github.com/pixelfed/pixelfed.git pixelfed

Once it is downloaded, let's set up our permissions:

cd pixelfed
sudo chown www-data:www-data /var/www/pixelfed
sudo chown -R www-data:www-data ./ 
sudo find . -type d -exec chmod 755 {} \; 
sudo find . -type f -exec chmod 644 {} \; 
sudo chmod -R 775 /var/www/pixelfed/storage /var/www/pixelfed/bootstrap/cache
sudo chmod 600 /var/www/pixelfed/storage/oauth-private.key
sudo chmod 600 /var/www/pixelfed/storage/oauth-public.key

Once the permissions are setup, we can now initialize and setup Laravel, artisan, etc., and configure our virtual environment:

cd /var/www/pixelfed
sudo -u www-data composer install --no-dev --optimize-autoloader

Now that dependencies are installed, let's make a copy of the example environment config with cp .env.example .env and then open it up sudo nano /var/www/pixelfed/.env and drop in some settings something like mine, but adjusted to your use-case:

APP_NAME="GNU/Linux Pics"
APP_ENV=production
APP_KEY=generated with artisan later
APP_DEBUG=false
APP_URL=https://gnulinux.pics
APP_DOMAIN=gnulinux.pics
ADMIN_DOMAIN=gnulinux.pics
SESSION_DOMAIN=gnulinux.pics
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=pixel
DB_USERNAME=pixel
DB_PASSWORD=strongpass
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_CLIENT=predis
REDIS_SCHEME=tcp
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
HORIZON_PREFIX=horizon-
MAIL_MAILER=smtp
MAIL_HOST=mail.haacksnetworking.org
MAIL_PORT=587
MAIL_USERNAME=webmaster
MAIL_PASSWORD=strongpass
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=webmaster@haacksnetworking.org
MAIL_FROM_NAME="GNU/Linux Pics"
ACTIVITY_PUB=true
AP_REMOTE_FOLLOW=true
AP_INBOX=true
AP_OUTBOX=true
AP_SHAREDINBOX=true
RELAY=true
OPEN_REGISTRATION=true
ENFORCE_EMAIL_VERIFICATION=true
PF_MAX_USERS=1000
PF_OPTIMIZE_IMAGES=true
IMAGE_QUALITY=80
MAX_PHOTO_SIZE=15000
MAX_CAPTION_LENGTH=500
MAX_ALBUM_LENGTH=4
INSTANCE_DISCOVER_PUBLIC=true
PF_ENABLE_CLOUD=false

Something like the above are the minimum settings one would want on spinup. Of course, you can add cloud storage and other stuff later if you so desire. You could also adjust it to use an off-site db and/or adjust your mailer to use sendgrid, etc. Personally, I prefer the db to be local as well as the mail server. I will eventually build a mail server on this instance and migrate the MAIL settings to using it instead, but for now, I've used an existing and working management mail server. It is now time to initialize the virtual environment using artisan:

cd /var/www/pixelfed
sudo -u www-data php artisan migrate --force
sudo -u www-data php artisan storage:link
ls -l /var/www/pixelfed/public/storage #optionally verify storage symlink
sudo -u www-data php artisan key:generate
sudo -u www-data php artisan passport:keys --force
sudo -u www-data php artisan passport:install --force
sudo -u www-data php artisan horizon:install
sudo -u www-data php artisan config:cache
sudo -u www-data php artisan route:cache
sudo -u www-data php artisan view:cache
sudo -u www-data php artisan optimize
sudo -u www-data php artisan instance:actor
sudo -u www-data php artisan import:cities

Step 4: Additional Apache Tweaks

During testing, I was having some spinning and other issues that seemed to stem from re-writes and overrides glitching a bit. For this reason, I added an override inside each vhost as an extra precaution. You also want to ensure that the /var/www/pixelfed/public sub-directory is specified and that your php handler is explicitly declared. Open up your vhost(s), and ensure these additions are within your IfModule declarations:

  DocumentRoot /var/www/pixelfed/public
  <Directory /var/www/pixelfed/public>
      Options Indexes FollowSymLinks
      AllowOverride All
      Require all granted
  </Directory>
  <FilesMatch \.php$>
      SetHandler "proxy:unix:/run/php/php8.4-fpm.sock|fcgi://localhost/"
  </FilesMatch>

Pixelfed has a nested .htaccess file inside public so let's ensure that Overrides are enabled globally. Let's open up sudo nano /etc/apache2/apache2.conf and change None to All in the appropriate sections (this matches the Override rule in the vhost). In the webroot block, or <Directory /var/www/>, it should look like:

<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride All ### NOTE "All" instead of "None" ###
    Require all granted
</Directory>

Additionally, the Pixelfed website mentions that some users of apache might have difficulty with the default .htaccess file in public so they recommended changing it. My instance indeed had trouble finding certain locations and directories unless I changed to their recommendation. Open up sudo nano /var/www/pixelfed/public/.htaccess and enter the recommendation as follows:

<IfModule mod_rewrite.c>
Options +FollowSymLinks -Indexes
RewriteEngine On
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>

Now that apache is fully configured, let's create out systemd unit file.

Step 5: Create and Enable Horizon Systemd Service

First, let's create the unit file over in sudo nano /etc/systemd/system/pixelfed.service and inside that unit file, put something similar to the following:

[Unit]
Description=Pixelfed Horizon Queue Worker (Laravel Horizon)
After=network.target apache2.service php8.4-fpm.service redis-server.service mariadb.service
Wants=apache2.service php8.4-fpm.service redis-server.service mariadb.service
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/pixelfed
ExecStart=/usr/bin/php artisan horizon
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
NoNewPrivileges=yes
PrivateTmp=true
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/www/pixelfed/storage
ReadWritePaths=/var/www/pixelfed/bootstrap/cache
[Install]
WantedBy=multi-user.target

After you create the unit file, let's reload the daemon, restart the service and check for any errors. Restart all services and check a web browser to see if the instance resolves after restarting the services.

sudo systemctl daemon-reload
sudo systemctl enable pixelfed.service
sudo systemctl restart pixelfed.service
sudo systemctl status pixelfed.service
journalctl -u pixelfed.service -n 50
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo systemctl restart apache2 php8.4-fpm pixelfed.service redis-server

At this point, most essential lifts are done. As long as your landing page resolves, which it should by this stage, you can now move on to creating an admin user and then managing the instance via the GUI web panel:

Step 6: User Creation & Instance Management

Let's create the admin user:

cd /var/www/pixelfed
sudo -u www-data php artisan user:create

Follow the prompts it provides with your desired values and make sure to state yes when it asks you to make this user and admin. Navigate to your instance in a web browser and log in. If it works, then you are good to go! If not, here are some common commands I ran to test and debug things while I was setting everything up:

redis-cli ping
redis-cli keys "horizon:*"
journalctl -u pixelfed.service -n 50
sudo -u www-data php artisan config:show queue | grep default 
tail -n 100 /var/www/pixelfed/storage/logs/laravel.log | grep -i "activitypub\|federat\|outbox\|inbox\|error\|fail\|exception" 

I am currently still working on getting the well-known to function correctly. I am unsure if the errors I am getting are due to the instance not yet being approved or if it is an error on my end. I will update here once confirmed:

curl -s https://gnulinux.pics/.well-known/nodeinfo
curl -s https://gnulinux.pics/api/nodeinfo/2.0
sudo -u www-data php artisan route:list | grep -i nodeinfo

For updating, something like the following is minimally required:

cd /var/www/pixelfed
git pull origin dev
sudo -u www-data composer install --no-dev --optimize-autoloader
sudo -u www-data php artisan migrate --force
sudo -u www-data php artisan config:cache
sudo -u www-data php artisan route:cache
sudo systemctl restart pixelfed.service apache2 php8.4-fpm redis-server

After updating, the instance will hose the permissions on the OAUTH bits, so I decided to make a fun script to reset all caches and perms as follows. I created sudo nano /usr/local/bin/refresh.sh and put the following inside it:

#!/bin/bash
cd /var/www/pixelfed
echo "Starting full Pixel refresh โ€“ hold tight!"
sleep 2s
echo "๐Ÿ”ฅ Clearing all old caches..."
sudo -u www-data php artisan optimize:clear
sudo -u www-data php artisan config:clear
sudo -u www-data php artisan cache:clear
sudo -u www-data php artisan route:clear
sudo -u www-data php artisan view:clear
echo "๐Ÿ”ฅ Rebuilding fresh caches..."
sudo -u www-data php artisan config:cache
sudo -u www-data php artisan route:cache
sudo -u www-data php artisan view:cache
sudo -u www-data php artisan optimize
echo "๐Ÿ”ฅ Re-locking down the OAuth keys ..."
sudo chmod 600 /var/www/pixelfed/storage/oauth-private.key
sudo chmod 600 /var/www/pixelfed/storage/oauth-public.key
echo "๐ŸŽ‰ Restarting services โ€“ bringing it all back online..."
sudo systemctl restart apache2 php8.4-fpm pixelfed.service redis-server

This little script just helps me refresh everything if/when changes or adjustments need to be made. Once the instance gets approved and/or I have resolved the well-known federation and/or discovery stuff, I will post an update. Thanks all and happy hacking !!


Debugging, Miscellaneous, Updates

From here forward, I post miscellaneous debugging. To fix images in DMs failing, as per github #5217, #5365, #5496, I edited the db to accept wrongly submitted null values from the bad DM code:

mysql -u root -p
USE pixel;
ALTER TABLE statuses MODIFY COLUMN caption TEXT NULL;
EXIT;

This solves the issue and allows users to upload images inside their DMS. Here are the issues that helped me fix this:

โ€” oemb1905 2026/03/01 21:49

computing/pix3lfed.txt ยท Last modified: by oemb1905