Pixelfed

Pixelfed is a web based, ethical photo sharing tool. The software is free and open source and contains no tracking, analytics or algorithms which seek to steer what you view. In this document I am going to attempt to get things going on my VPS, and it will eventually be available at https://pictures.yidhra.farm.

In this document I will generally follow the Pixelfed Instructions for running my own instance.

Pre-Requisites I Used

These are what I will be using:

Web Server

I already have Nginx installed and running, so made sense not to keep going with it. Pixelfed requires use of HTTPS URLs so HTTPS will need to be set up and working at least on perimeter.

Database

While Pixelfed supports several databases, I again have a Maria DB up and running so it made sense to choses that for me. I signed in as database administrator and set up database as follows, setting an actual password different from as indicated below.

sudo mysql -u root -p
create database pixelfed;
grant all privileges on pixelfed.* to 'pixelfed'@'localhost' identified by 'strong_password';
flush privileges;

PHP

Pixelfed requires PHP version 7.2 or better.

php -v
PHP 7.4.10 (cli) (built: Sep  9 2020 06:55:12) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.10, Copyright (c), by Zend Technologies

Check required modules are loaded by php. Output below reduced to show only required modules.

$ php -m
[PHP Modules]
bcmath
curl
exif
gd
iconv
imagick
intl
json
mbstring
mysqli
openssl
pdo_mysql
redis
tokenizer
xml
zip

Apply desired upload limits by setting the appropriate values for the below in the php.ini file that your web server uses. In my case the correct file was located here: /etc/php/7.4/fpm/php.ini.

  • post_max_size (default 8M, set a little greated than max post size desired)
  • file_uploads (default On, which it needs to be)
  • upload_max_filesize (default 2M, set <= post_max_size)
  • max_file_uploads (default 20, must be >= your desired attachment limit)
  • max_execution_time (default 30, set up to 600 or > to avoid task interrupton)

Create User Account

Always a good idea to run services under dedicated accounts for the service. Create whatever account you wish.

useradd -rU -s /bin/bash pixelfed

Configure PHP-FPM Pool and Socket

I had to hunt around a little bit to find the location of the right directory, with /etc/php/7.4/fpm/pool.d eventually turning out to be the needful, as Debian based instance. When all else fails check your php.ini file for path include= is set to.

Create file and edit.

cd /etc/php/7.4/fpm/pool.d/
cp www.conf pixelfed.conf
$EDITOR pixelfed.conf

Make changes to ``pixelfed.conf` as below, adjusting as appropriate for user account, socket path and as needed to match your environment.

;     use the username of the app-user as the pool name, e.g. pixelfed
[pixelfed]
user = pixelfed
group = pixelfed
;    to use a tcp socket, e.g. if running php-fpm on a different machine than your app:
;    (note that the port 9001 is used, since php-fpm defaults to running on port 9000;)
;    (however, the port can be whatever you want)
; listen = 127.0.0.1:9001;
;    but it's better to use a socket if you're running locally on the same machine:
listen = /run/php-fpm/pixelfed.sock
listen.owner = http
listen.group = http
listen.mode = 0660
[...]

Configure Redis Socket

Find redis.conf file for your server, usually in /etc/ or subdirectory of /etc. And make changes as below to restrict network access and ensure both “redis” user and group have access to socket.

port 6379                           # change this to "port 0" to disable network packets
unixsocket /run/redis/redis.sock    #
unixsocketperm 770                  # give permission to "redis" user and group

At this point all the foundational pre-requisite work is done and we can get down to the business of installing and configuring Pixelfed itself.

Setting up Pixelfed files

Download source via Git

Change to where you want to install the application code and clone from Github. I am running under a dedicated account for the application so I installed in the home directory of the account.

cd /home/pixelfed # or wherever you to install application
git clone -b dev https://github.com/pixelfed/pixelfed.git pixelfed # checkout dev branch into "pixelfed" folder

Set correct permissions

Change into the directory where the application was cloned from Github and set permissions. As I am using a dedicated account, I set the ownership to the account I am using.

cd pixelfed
sudo chown -R pixelfed:pixelfed . # change user/group to pixelfed user and pixelfed group
sudo find . -type d -exec chmod 755 {} \; # set all directories to rwx by user/group
sudo find . -type f -exec chmod 644 {} \; # set all files to rw by user/group

Initialize PHP dependencies

The install process relies on the Composer dependency manager for PHP. Download and install, as it will be required to run against the files downloaded in the pixelfed folder.

/opt/pomposer/composer/opt/composer/composer.phar install --no-ansi --no-interaction --optimize-autoloader
...
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: beyondcode/laravel-self-diagnosis
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: fruitcake/laravel-cors
Discovered Package: intervention/image
Discovered Package: jenssegers/agent
Discovered Package: laravel/horizon
Discovered Package: laravel/passport
Discovered Package: laravel/tinker
Discovered Package: laravel/ui
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: pbmedia/laravel-ffmpeg
Discovered Package: pixelfed/laravel-snowflake
Discovered Package: spatie/laravel-backup
Discovered Package: spatie/laravel-image-optimizer
Discovered Package: stevebauman/purify
Package manifest generated successfully.
66 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
$

Configure environment variables

Copy one of the provided sample .env files to .env for modification and use. The Pixelfed website has detailed information on each of the variable on the Configuration. Below I simply note the variables I set.

cp .env.example .env

App variables

  • APP_NAME - Use to set application name.
  • APP_DEBUG - Toggle debug information on or off.
  • APP_URL - Set url for instance.
  • APP_DOMAIN - Specify domain name to use.
  • ADMIN_DOMAIN - Same as used for APP_DOMAIN.
  • SESSION_DOMAIN - Same as used for ADMIN_DOMAIN.

Database variables

  • DB_CONNECTION - Specify type of database, pgsql or mysql.
  • DB_HOST - Database hostname.
  • DB_PORT - Database port
  • DB_DATABASE - Database name.
  • DB_USERNAME - Database user name.
  • DB_PASSWORD - Database password.

Redis variables

  • REDIS_HOST - Redis server host name.
  • REDIS_PORT - Redis server port.
  • REDIS_PASSWORD - Redis password.
  • REDIS_SCHEME - Set to unix for sockets, or tcp for ip network connection.
  • REDIS_PATH - path to socket if using.

Email variables

  • MAIL_FROM_ADDRESS - Notification from address.
  • MAIL_FROM_NAME - Notification mail user name.
  • MAIL_ENCRYPTION - Specify mail encryption to use.
  • MAIL_DRIVER - Set as appropriate for mail solution.
  • MAIL_HOST - Specify mail server.
  • MAIL_PORT - Specify mail server port.
  • MAIL_USERNAME - Notification mail user for authentication.
  • MAIL_PASSWORD - Password associated with mail user.

Additional variables

  • IMAGE_DRIVER - Specify image manipulation tool used.
  • ACTIVITY_PUB - Enable/disable federation.
  • AP_REMOTE_FOLLOW - Allow/prevent remote following.

Setting up services

One-time setup tasks

php artisan key:generate #one time only, generates ```APP_KEY``` 
php artisan storage:link #one time only link storage directory to app
php artisan migrate --force # run database migrations
php artisan import:cities # enable support for location data
php artisan route:cache # run whenever source code changes
php artisan view:cache # run whenever source code changes
php artisan config:cache # run whenever .env changes

Job Queuing

Using Laravel Horizon

php artisan horizon:install
php artisan horizon:assets

Create a systemd service unit so Pixelfed and supporting products are started at boot time and run in the background. Create pixelfed.service in /etc/systemd/system/.

[Unit]
Description=Pixelfed task queueing via Laravel Horizon
After=network.target
Requires=mariadb
Requires=php-fpm
Requires=redis
Requires=nginx

[Service]
Type=simple
ExecStart=/usr/bin/php /usr/share/webapps/pixelfed/artisan horizon
User=http
Restart=on-failure

[Install]
WantedBy=multi-user.target

Review and modify the above to match the install configuration of system paying specific attention to the following:

  • Replacing mariadb with postgresql or mysql.
  • Replacing php-fpm with distribution specific PHP-FPM package name, e.g. php7.3-fpm.
  • Replacing nginx with apache.
  • Replacing Requires with Wants if not running in a production environment.
  • Replacing /usr/bin/php or /usr/share/webapps/pixelfed/artisan with the correct paths.
  • Replacing User=http to reflect the app user, e.g. User=pixelfed. Alternatively comment this line in order to run in the system slice.

Once file is correct, start the service.

sudo systemctl enable --now pixelfed

Scheduling periodic tasks

Paste the following into crontab, correcting paths as needed to match install.

* * * * * /usr/bin/php /usr/share/webapps/pixelfed/artisan schedule:run >> /dev/null 2>&1

Handling web requests

Nginx

Pixelfed includes a sample NGINX configuration at contrib/nginx.conf. You can copy the contents of this file or include it within your nginx.conf. Review comments, setting correct domain nme and paths.

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name pixelfed.example;                    # change this to your fqdn
    root /home/pixelfed/public;                      # path to repo/public

    ssl_certificate /etc/nginx/ssl/server.crt;       # generate your own
    ssl_certificate_key /etc/nginx/ssl/server.key;   # or use letsencrypt

    ssl_protocols TLSv1.2;
    ssl_ciphers EECDH+AESGCM:EECDH+CHACHA20:EECDH+AES;
    ssl_prefer_server_ciphers on;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php-fpm/php-fpm.sock; # make sure this is correct
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # or $request_filename
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

server {                                             # Redirect http to https
    server_name pixelfed.example;                    # change this to your fqdn
    listen 80;
    listen [::]:80;
    return 301 https://$host$request_uri;
}
  • FastCGI path - Make sure to use the correct fastcgi_pass socket path for your distribution and version of PHP-FPM.
  • If you have configured a PHP server over TCP, you may also pass to its IP and port, localhost:9000 by default.
  • Nginx web root - Make sure to use the /public folder as your server root. Example:server {root /var/www/pixelfed/public;}. If you set root to the install directory (Example: server {root /var/www/pixelfed;} Pixelfed will not work.

Use certbot to get an HTTPS certificate and then you should be off to the races with your Pixelfed instance.