This is a guide on how to install #pixelfed on ubuntu 18.04 since that is a distribution most probably to find on cheap VPS's.


In most servers this stuff is pre-installed, but when you just install ubuntu server with no extra options they are missing. There's no harm trying, worst that can happen is to get an “already installed” message.

In some cases (minimal default installation) you will need to add the add-apt-repository command. I also had to install the https transport for apt (that is a program that allows apt to download over https instead of http) because some newer repositories require it. Do this now because sometimes an installation might fail halfway through if it's not installed and that's a tough situation to get out of.

sudo apt install software-properties-common apt-transport-https

and the trash command so that you don't actually delete things permanently with rm

sudo apt install trash-cli

Then you can use trash useless-filename-here to delete stuff.

I like the micro editor because it uses the modern GUI editor conventions in the terminal (such as Ctrl+C, Ctrl+V for copy and paste).

The second command adds micro to PATH for all users because for some reason /snap/bin is not in the path for every user.

sudo snap install micro --classic
sudo sed -i 's#"$#:/snap/bin"#' /etc/environment

or if that doesn't work

curl https://getmic.ro | bash

Installation of dependencies

First add php ppa's. This step adds newer php versions to this old ubuntu because pixelfed doesn't run with older ones.

sudo add-apt-repository ppa:ondrej/php

(The ondrej apache ppa is not required but the ppa maintainer recommends adding it)

Then add mariadb (mysql-equivalent) repositories. The same goes here, pixelfed requires newer versions.

sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
sudo add-apt-repository 'deb [arch=amd64,arm64,i386,ppc64el] http://ftp.cc.uoc.gr/mirrors/mariadb/repo/10.2/ubuntu xenial main'

Refresh caches

sudo apt update

Upgrade what can be upgraded

sudo apt upgrade

Answer yes to the prompt

Install nginx

sudo apt install nginx

Install php and mysql

sudo apt install php7.3 mariadb-server

You might need to remove apache.

sudo apt remove apache2

If it says it's not installed don't worry about it, all is well.

Install other required modules

sudo apt install imagemagick composer redis-server jpegoptim optipng pngquant php7.3-xml php7.3-pdo php7.3-json php7.3-ctype php7.3-xml php7.3-mbstring php7.3-gd php7.3-tokenizer php7.3-bcmath php7.3-curl php7.3-zip unzip php7.3-pdo php7.3-mysql php7.3-intl php7.3-fpm

Install mail transport agent so that pixelfed can send confirmation emails.

sudo apt install postfix

In the dialog box that appears press Tab and then Enter to choose Ok and then choose Internet site from the list using the arrow keys on your keyboard and then press Enter to confirm. In the next page enter the name of your instance, e.g. myinstance.name.

At some point you will probably need to monitor processes and free memory so install htop before you actually need it, at which point will probably be impossible to do the installation

sudo apt install htop

Configuring nginx

I prefer to run nginx as a user I can log in to so now we will do that:

Create a new user pixelfed

sudo useradd -m pixelfed

Set his default shell to bash

sudo chsh pixelfed -s /bin/bash

Edit apache nginx config so that it runs using that user

sudo micro /etc/nginx/nginx.conf

Find and replace user nginx; with user pixelfed;. Save (Ctrl+S) and close (Ctrl+Q) the file.

Also we need to change the php-fpm user to pixelfed

sudo micro /etc/php/7.3/fpm/pool.d/www.conf

Find all occurences of www-data and change them to pixelfed (use Ctrl+F). There are two on lines 23 and 24 also two on 47 and 48

Change the web server root directory to the public directory of the pixelfed repository

sudo micro /etc/nginx/sites-available/default

Replace /var/www/html with /home/pixelfed/pixelfed/public.

Being here, you should also uncomment the php directives

        #location ~ \.php$ {
        #       include snippets/fastcgi-php.conf;
        #       # With php-fpm (or other unix sockets):
        #       fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        #       # With php-cgi (or other tcp sockets):
        #       fastcgi_pass;

should become

        location ~ \.php$ {
               include snippets/fastcgi-php.conf;
               # With php-fpm (or other unix sockets):
               fastcgi_pass unix:/var/run/php/php7.-fpm.sock;
        #       # With php-cgi (or other tcp sockets):
        #       fastcgi_pass;

Notice that two of the # remain and that php7.0 became php7.3

Configuring php

Change php max upload size (how large a file is allowed to be uploaded)

sudo micro /etc/php/7.3/apache2/php.ini

Search the file for upload_max_filesize and post_max_size and change to 80M and 120M respectively. You can go larger and just configure pixelfed to limit the sizes but I think 80M is a reasonable size. You can also increase the memory limit to 512M or maybe half your vps's RAM. Save and close the file.

Restart nginx and php-fpm

sudo systemctl restart nginx
sudo systemctl restart php7.3-fpm.service 

Configuring MariaDB

Log in to mysql as root

sudo mysql

Enter the mysql root password as you entered it above.

Create a pixelfed database and user and give the user permissions. On the prompt that appears

    CREATE SCHEMA pixelfed;
    CREATE USER 'pixelfed'@'localhost' IDENTIFIED BY 'supersecretpassword';
    USE pixelfed;
    GRANT ALL PRIVILEGES ON pixelfed.* TO 'pixelfed'@'localhost';

Installing Pixelfed

Log in as pixelfed

sudo su pixelfed

change to the home directory


Get the code

git clone https://github.com/pixelfed/pixelfed.git
cd pixelfed


Copy the default configuration

cp .env.example .env

Edit the configuration

micro .env

Set your instance name and domain as you wish.

    APP_NAME="PixelFed Test"

Set the username and password of MariaDB as you have configured them above. Find the following lines and complete the values after the =


Set the mail server configuration. Replace myinstance.name with the name of your instance.


Set the federation flags to true if you want


Save and close the file.


Run the post deployment commands as outlined here

cd /home/pixelfed/pixelfed # Or wherever pixelfed is installed
composer install --no-ansi --no-interaction --no-progress --no-scripts --optimize-autoloader
php artisan key:generate
php artisan config:cache
php artisan route:cache
php artisan migrate --force
php artisan horizon:purge

Link the storage directory

php artisan storage:link

Now we need to make sure horizon is always running.

Systemd setup

Exit the user shell


now create a new systemd service

sudo micro /etc/systemd/system/pixelfed.service

with the following contents

Description=Pixelfed task queueing via Laravel Horizon
ExecStart=/usr/bin/php /home/pixelfed/artisan horizon

enable the service so that it starts automatically on each boot

sudo systemctl enable pixelfed

and start it

sudo systemctl start pixelfed


restart nginx

sudo systemctl restart nginx

Let's encrypt and https

Go to certbot website and follow the instructions there. I copied them here for easy access:

sudo apt-get install certbot python-certbot-nginx
sudo certbot --nginx

Follow the instructions from there.

Certbot comes with a cronjob automating renewal so in theory you shouldn't need to do anything more at this time. Enjoy your pixelfed installation.

Creating your first user and setting as adminstrator

Go to the website (http://myinstance.name) and register a new account Go back to your vps and log on to mysql again

mysql -u pixelfed -p

Give the supersecretpassword In the prompt that appears make yourself adminstrator

use pixelfed;
update users set is_admin=1 where id=1;

If you have trouble seeing the activation email you can activate yourself too

update users set email_verified_at="2019-02-12 10:25:32" where id=1;

Final steps

Now go to the website again and log in. You should be able to administer the instance.

Happy posting!

This is a #pherephone “Announce” activity from a writefreely post. It works on mastodon but not on pleroma. I cannot understand why this is. Can any helpful #pleroma or #ActivityPub experts give a hint?

boosts appreciated

POST request to https://pleroma.site/users/qwazix/inbox succeeded (200): 200 OK 
Response: "ok" 
Request: {
        "@context": [
        "actor": "https://floorb.qwazix.com/myAwesomeList5",
        "cc": [
        "id": "https://floorb.qwazix.com/myAwesomeList5/item/ULeVhJOsBTqWN22v",
        "object": "https://mixt.qwazix.com/api/posts/mncqqz3y7u",
        "published": "2019-10-14T12:13:43+03:00",
        "to": "https://www.w3.org/ns/activitystreams#Public",
        "type": "Announce"
    Accept: application/activity+json; charset=utf-8
    Accept-Charset: utf-8
    Content-Type: application/activity+json; charset=utf-8
    Date: Mon, 14 Oct 2019 09:13:44 GMT
    Digest: SHA-256=Cl3iznjWvGXEFev5OP6ChwvVtY/Xtaw43ahnhXh4d4A=
    Host: pleroma.site
    Signature: keyId="https://floorb.qwazix.com/myAwesomeList5#main-key",algorithm="rsa-sha256",headers="(request-target) date host digest",signature="fnPHBAqWCIr3EpbwllBwFxhKJ03c23+evwPfX+Bcf/CEenQ/ZgTCViK5Gs0fW8qjzGuSCkYpFKFt7rmEiuXg7T4RkUy2LWq+kfTq8t/jWeS2LUCxNXRAgyJfhH2kioYefKqx6gl414js0qdFk6I0WWvtXpGuKIuiF/WK9FPx7WpJFJfN1WZ2kEdi87F0gRIAjllaGST15ZMx0mFkLVks2Vdff6saPR+V83muGClfzh78AN2XR4fnYve9m5Wm4/U6Q8n503CE/yfBb5bZSmfJZXZSlErT6L224b8LWKC7Q+IHe17k+aFibl/dNAknjmQwm/xFOdNzVHwGWXyhSrchGw=="
    User-Agent: pherephone 0.99

EDIT: I also tried after reversing the cc and to fields just as pleroma does.

/home/qwazix/go/src/github.com/writeas/activityserve/actor.go:502: POST request to https://iscute.moe/users/qwazix/inbox succeeded (200): 200 OK 
Response: "ok" 
Request: {
        "@context": [
        "actor": "https://floorb.qwazix.com/myAwesomeList5",
        "cc": "https://www.w3.org/ns/activitystreams#Public",
        "id": "https://floorb.qwazix.com/myAwesomeList5/item/EUyTQEnz1gJK3qu3",
        "object": "https://fosstodon.org/users/qwazix/statuses/102966679309503735",
        "published": "2019-10-15T16:40:40+03:00",
        "to": [
        "type": "Announce"
Headers: Accept: application/activity+json; charset=utf-8
Accept-Charset: utf-8
Content-Type: application/activity+json; charset=utf-8
Date: Tue, 15 Oct 2019 13:40:41 GMT
Digest: SHA-256=U30KWCsixidktfC/JToZSCX9HXoysMNrTqLPPzf62LI=
Host: iscute.moe
Signature: keyId="https://floorb.qwazix.com/myAwesomeList5#main-key",algorithm="rsa-sha256",headers="(request-target) date host digest",signature="DONBUM3O3s/YU/B4F9pWPWgFx1P7ZruJbuTrDVYIdY6m2EpVI7yihy157o3aUoC37acKuoo9F+F0sbOHyt3B3lwe+3eWHq0WbVDfoeIdOIFGVo2s9BxK748RHSSVU0lnLsIOQ/A3B3rRkkLlJ1zc3kdfHzfaNzQPUQJ9SL72x55sgzIthIY+vSAbS/IHbup5XomenkHynsj33F9RCYPqXajPRMUXPx0ljFcfRyQGX7/opipDQ4V2ANzjLHwosnHvKss+DQK9e2ZBbq3PaKYUwmKWdwDCQfzEok+hz6xTGzCnw8K7yICu2c1YNU0PD+q5rCATWhNuA3vPeme1iTcZ5A=="
User-Agent: pherephone 0.99

The thing that bothers me the most is that I get an “ok” response and a 200 but the post never appears in the interface.

testing #pherephone

test post #pherephone

At #APConf, the second day was called the unconference.


Everybody could add his subject to the board and we rearranged the post-its so that most of us could attend everything that sounded interesting.

I didn't have anything to present nor I had very strong feelings about which sessions I was going to participate in so I stayed a bit to the back of the crowd. Talking with @matt@writing.exchange I floated the following idea:

“What if there was a simple node-based interface, like blender or scratch, where the building blocks are the ActivityPub activities and types, and a user would be able, with minimal or no code, to create a simple social network?”

The idea sprang when I realized how small UI differences and allowed interaction paths help make mastodon and twitter, two otherwise very similar networks have such different culture: what if we could rapidly test such interaction and UI differences without having to develop a social network from scratch? Dragging and dropping stuff on a digital canvas should be enough to create a rudimentary social framework.

This application would also help wannabe #ActivityPub developers start from something that works and build upon that, shifting the development effort from spraying activities until one of them is accepted to trying not to break anything, which is much less frustrating.

The idea to caught on and soon after we had moved to the terrace and five of us were discussing this possibility.

The discussion went well and we soon had some rough notes on how this would work.

Each of the building blocks will include a minimal web component tailored to the type of item such as a textarea for a note or article, an image upload component for an image and so on.

By the way, when I presented pherephone @cjd@mastodon.social proposed a kind of bot that just boosts whatever item it's being mentioned in. Let's see how we would go about to create this social service.

At first we'd have to create the actor that has the endpoints we require. This actor doesn't like or follow anyone so it just requires an inbox, an outbox, and a followers list.

Here's how we would configure the actor in AAAG.

social graph

Endpoints can be added to the actor by dragging and dropping from the available endpoints on the left. Each connection can be edited by choosing from the options on the right.

This here is an actor that provides a blacklist of some spammer accounts, and auto-accepts follows by other actors.

When we finish editing the external relationships of our actor, we can double-click on it so we can inspect its inner workings. The interface changes to something like this.

actor mechanics

When an activity reaches our inbox we pass it through several conditional blocks and depending whether the answer is yes or no it follows the respective path, until its object reaches (or not) the outbox, wrapped in an Announce activity.

Another, more fine-grained but more complicated approach to the same thing would be the following graph.

actor mechanics, but operating on properties

In this graph we operate on activity properties instead of whole activities, but this breaks chaining so it requires gates if you need to express more complicated relationships.

UI design

There is a possibility to devise a system where AAAG will concoct a basic UI from the relationships described in the previous two screens, however it is probably more useful and flexible if we include a UI designer in the project.

This designer might look like this


In this interface, we can drag and drop UI elements into a browser window and assign nodes to them. For example, a list can be assigned a “followers” node, a “likes” node, an outbox and so on.


I don't know whether this is something I would ever find the time to pursue but I wanted to get the idea out there and see if anybody would be interested in creating something like this. I'd also like feedback on how this would be made easier for the uninitiated and ways that the social graph design page can incorporate more than one actor in meaningful ways so that it can represent different relationships and interactions between actors on the fediverse.


This is a #pherephone test

No, not from me. I don't have a new blog, account, or anything. However this will (hopefully) be the first #writefreely post boosted by #pherephone, an ActivityPub repeater.

If you're interested and you'll be at #ActivityPubConf in a few days, I'll be there to tell you all about it.

There's still work to do, but for now, the big achievement was unlocked.

Στη γιορτή της σχολής χορού, φυσικά είχα πάει με τη φωτογραφική μηχανή ανά χείρας. Σε κάποια φάση εκεί που παρακολουθώ και φωτογραφίζω με πλησιάζει μια κοπέλα: “Είσαι ο φωτογράφος της σχολής;” “Όχι, είμαι μαθητής εδώ” της λέω. “Η φωτογραφία είναι το χόμπυ μου”.

“Αλήθεια;” “Ναι, κάνω Pole” Κάνοντας μισό βήμα πίσω με επεξεργάζεται από την κορφή ως τα νύχια, χωρίς καμία προσπάθεια να το κρύψει. “Μα δεν φαίνεσαι καθόλου σαν...” παύση, “το άλλο φύλο”. “Δεν είναι απαραίτητο...” κρύβω ένα μειδίαμα “Να φαίνεσαι;” “Να είσαι” “Δεν είσαι;” “Όχι”

Προσπάθησε να τα μπαλώσει. Προσπάθησα να μη σκάσω στα γέλια.

Femme in bikini doing a floor dance move. Dancing pole in foreground.

#poledancing #smallstories #μικρέςΙστορίες

He was never there. And yet he was always watching. I am not even sure he is one man. Sometimes he would be proud of me. Others someone to be afraid of.

He was the monster under the bed and god himself. As she prepared breakfast she would cry and sometimes I'd be sure I heard his name among the sobs. Other times she'd stare at me with that weird look and say to him, even though he wasn't there: “I was right. I did good. Fuck you. Fuck you.” and then she'd tell me “What are you looking at? Eat your cereal” and then she go on talking to him “Bastard, fuck you, fuck you!”

I tried to say those two words once. She got angry and took my ruler with the little houses and the yellow dog and waved it in the air and she told me he'd come and be very angry and take me away. And then she'd sit there, her head in her hands, her hands tangled in shiny black hair, her hair hiding her face, a face full of tears.

I think he is that tall mister I saw after school that day I finished early. He held her waist in his arms and her bright red lips pressed into his. I didn't dare ask. He might have taken me away if he knew I knew. I kept it a secret. But I do have a drawing of them hidden well, I will not tell you where though. I don't trust you. You might be him.

If you are him please don't come take me away. I love her. I know you might be listening the other day I was crying. I didn't mean what I said. And she said “sorry”. Don't you know you should forgive when someone is sorry? She is sorry, and I think she's telling the truth and I don't hurt anymore when I press my finger on here, see? The blue is gone too.

Also if you are him please stop making her scream at night. I'm scared. I hide under my sheets and I don't dare go save her. If you are not, please, come and save her...

Goodnight now. I have to hide this and go to sleep. I think he is in the closet, watching me.