Prerequisites

This guide assumes:

  • You've already gotten a server setup with Ubuntu 19.10
  • Nginx
  • MySQL 5.6+ (or MariaDB 10.2.7+)
  • PHP 7.2+ with the following extensions bcmath, ctype, curl, exif, iconv, imagick, intl, json, mbstring, mysql, gd, openssl, tokenizer, xml and zip
  • Redis
  • ImageMagick
  • Supervisor
  • Git

I would also recommend installing JPEGOptim, OptiPNG and PNGQuant. These will strip exif data and optimizes jpeg and png photos.

$ apt install jpegoptim
$ apt install optipng
$ apt install pngquant

Here's a list of the packages I have installed:

MariaDB

libmariadb3
mariadb-client-10.4
mariadb-client-core-10.4
mariadb-client
mariadb-common
mariadb-server-10.4
mariadb-server-core-10.4
mariadb-server
mysql-common

ImageMagick

imagemagick-6-common
imagemagick-6.q16
imagemagick
libmagickcore-6.q16-6-extra
libmagickcore-6.q16-6
libmagickwand-6.q16-6
php-imagick

PHP

php-common
php-composer-ca-bundle
php-composer-semver
php-composer-spdx-licenses
php-composer-xdebug-handler
php-igbinary
php-imagick
php-json-schema
php-psr-container
php-psr-log
php-redis
php-symfony-console
php-symfony-filesystem
php-symfony-finder
php-symfony-process
php-symfony-service-contracts
php7.3-bcmath
php7.3-cli
php7.3-common
php7.3-curl
php7.3-fpm
php7.3-gd
php7.3-intl
php7.3-json
php7.3-mbstring
php7.3-mysql
php7.3-opcache
php7.3-readline
php7.3-tidy
php7.3-xml
php7.3-xmlrpc
php7.3-zip

Misc

git/eoan-updates,eoan-security,now 1:2.20.1-2ubuntu1.19.10.1 amd64 [installed,automatic]
composer/eoan,now 1.9.0-2 all [installed]
supervisor/eoan,now 3.3.5-1 all [installed]
libhiredis0.14/eoan,now 0.14.0-3 amd64 [installed,automatic]
php-redis/eoan,now 5.2.1+4.3.0-1+ubuntu19.10.1+deb.sury.org+1 amd64 [installed]
redis-server/eoan,now 5:5.0.5-2build1 amd64 [installed]
redis-tools/eoan,now 5:5.0.5-2build1 amd64 [installed,automatic]
sendmail-base/eoan,now 8.15.2-13 all [installed,automatic]
sendmail-bin/eoan,now 8.15.2-13 amd64 [installed,automatic]
sendmail-cf/eoan,now 8.15.2-13 all [installed,automatic]
sendmail/eoan,now 8.15.2-13 all [installed]

Installation

First create a new user:

$ adduser pixelfed

Login as that user via SSH.

Now, clone the Pixelfed repository, move into it and use composer to install necessary packages:

$ cd ~
$ git clone https://github.com/pixelfed/pixelfed
$ cd pixelfed
$ composer install

Next we'll need to create a configuration file for the site:

$ cp .env.example .env
$ php artisan key:generate

Next open the .env file in your editor of choice and update it so it matches your configuration. Of note, I utilized Mailgun for my email service, however I could not get it working using the 'mailgun' driver. I had to use the 'smtp' driver with SMTP credentials I created from the Mailgun dashboard. Here's what I have for my mail configuration:

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME="pixelfed@mydomain.com"
MAIL_PASSWORD="password-here"
MAIL_ADDRESS="pixelfed@mydomain.com"
MAIL_FROM_ADDRESS="pixelfed@mydomain.com"
MAIL_FROM_NAME="Pixelfed"
MAIL_ENCRYPTION=tls

Once you've updated your .env file, save it. Next we need to get the database setup. This is how I created my MySQL user and database.

CREATE DATABASE pixelfed CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'pixelfed'@'localhost' IDENTIFIED BY 'PASSWORD';
GRANT ALL PRIVILEGES ON pixelfed.* TO 'pixelfed'@'localhost';

Run the command php artisan migrate. This will create the necessary structure and stuff in the MySQL database. Make sure to answer 'yes' to any prompt(s) that come up. It may take a minute or two to complete.

Next run the following commands (especially if you're running a production environment):

$ php artisan config:cache
$ php artisan route:cache
$ php artisan view:cache

Next up is install Horizon. This will manage jobs that the application has (things like resizing images, deleting images, etc...):

php artisan horizon:install

Next we'll want to create a supervisor configuration for Horizon. I do this as my root user. Create the file /etc/supervisor/conf.d/horizon.conf and place the following inside:

[program:horizon]
process_name=%(program_name)s
command=php /home/pixelfed/pixelfed/artisan horizon
autostart=true
autorestart=true
user=pixelfed
redirect_stderr=true
stdout_logfile=/home/pixelfed/pixelfed/horizon.log
stopwaitsecs=3600

I recommend running the following commands (it will restart and enable the service):

$ systemctl enable supervisor
$ systemctl restart supervisor

If you run a ps auxfwww you should see something similar:

root     18629  0.0  0.2  27672 20696 ?        Ss   12:46   0:01 /usr/bin/python2 /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf
pixelfed 18651  0.1  0.7 136724 57568 ?        S    12:46   0:04  \_ php /home/pixelfed/pixelfed/artisan horizon
pixelfed 18658  0.1  0.7 136724 57844 ?        S    12:46   0:05      \_ /usr/bin/php7.3 artisan horizon:supervisor hostname-tixv:supervisor-1 redis --delay=0 --memory=128 --queue=high,default,feed --sleep=3 --timeout=60 --tries=3 --balance=auto --max-processes=20 --min-processes=1 --nice=0
pixelfed 18672  0.0  0.6 134676 56724 ?        S    12:46   0:01          \_ /usr/bin/php7.3 artisan horizon:work redis --delay=0 --memory=128 --queue=high --sleep=3 --timeout=60 --tries=3 --supervisor=hostname-tixv:supervisor-1
pixelfed 18677  0.0  0.7 138968 58944 ?        S    12:46   0:01          \_ /usr/bin/php7.3 artisan horizon:work redis --delay=0 --memory=128 --queue=default --sleep=3 --timeout=60 --tries=3 --supervisor=hostname-tixv:supervisor-1
pixelfed 18682  0.0  0.6 134676 56192 ?        S    12:46   0:01          \_ /usr/bin/php7.3 artisan horizon:work redis --delay=0 --memory=128 --queue=feed --sleep=3 --timeout=60 --tries=3 --supervisor=hostname-tixv:supervisor-1

Next (and you can do this as your root user or pixelfed user), add a cronjob to the pixelfed user:

* * * * * cd /home/pixelfed/pixelfed && php artisan schedule:run >> /dev/null 2>&1

You can read this for more information on what sorts of things are done during this scheduled task.

Post-Installation Tasks

Import Cities

Run the command php artisan import:cities to import cities into your database. This will allow users to select locations when they're posting content.

Configure Nginx

Create a file - /etc/nginx/sites-available/mydomain.com.conf with the following contents:

server {
    server_name mydomain.com;
    listen 80;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name mydomain.com;
    root /home/pixelfed/pixelfed/public;

    ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf;

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

    client_max_body_size 20m;
    client_body_buffer_size 128k;

    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/php7.3-pixelfed-fpm.sock;
        fastcgi_index index.php;
        include fastcgi.conf;
    }

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

Of course you'll want to swap out mydomain.com in the file name and file contents with your domain.

Next, we want to create a PHP-FPM pool just for our pixelfed user. So create a file /etc/php/7.3/fpm/pool.d/pixelfed.photos.conf and place the following inside of it:

[pixelfed]
user = pixelfed
group = pixelfed
listen = /run/php/php7.3-pixelfed-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic 
pm.max_children = 75 
pm.start_servers = 10 
pm.min_spare_servers = 5 
pm.max_spare_servers = 20 
pm.process_idle_timeout = 10s

Now, we're going to run these commands to enable Nginx and PHP-FPM and restart them:

$ systemctl enable nginx
$ systemctl restart nginx
$ systemctl enable php7.3-fpm
$ systemctl restart php7.3-fpm

You should now have a running system! Go ahead and visit your site, and sign up for a new account. If you've enabled email verification make sure you complete that. Once you're verified go back into SSH as the pixelfed user and into /home/pixelfed/pixelfed and run php artisan user:admin username_here. This will turn your account into an admin account. Once that is done you can visit the admin area of your site (it's linked in the dropdown menu in the upper right corner) as well as see the Horizon dashboard. It should show as Active.

Pixelfed Horizon Dashboard

I also recommend running php artisan storage:link.

Resources

The follow is several resources I used and should help you as well.