Tutorial: Microblog

Microblog

A microblog is essentially a website where you can post short status updates for your followers to read. It's a simple concept but incredibly popular, as proven by platforms like Twitter and Mastodon. This makes it an exellent candidate for a web software project, and you'll find plenty of tutorials online for how to create your own microblog using your framework of choice. However, all of these are limited in practicality, because without other users to be social with what's the point of a social media site?

The difference with this tutorial is that, by using the ActivityPub protocol, we'll have a huge pool of real people who will be able to follow us, and who we'll be able to follow; users of Mastodon, Pleroma, Pixelfed, PeerTube... that's millions of people!

The next advantage this gives us is that we can create a single-user application; because the Fediverse is already full of users we can forget about the messy business of signups, multi-user authentication, and the rest of it. Of course you could create a multi-user site if you wanted, but we won't cover that in this guide.

This guide will walk you through how to create your own microblog service from scratch, using node-activitypub. I'm trying to aim this guide at all levels, from beginner to expert, as I believe the more people there are writing software for ActivityPub the better it will be.

Requirements

Summary:

- [Heroku cli](https://devcenter.heroku.com/articles/heroku-cli)
- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- [Node v12 & npm](https://nodejs.org/en/download/)

In the examples I'll be using Heroku as the host as it's free and fairly easy to configure, but there's nothing to stop you from using another service if you know what you're doing. I'll make use of the Heroku command line tool which you'll need to install. Using Heroku means we also need to use git - but I'll try and be specific enough that you can get by even if you haven't used it before (we'll only be using the init, add, commit and push commands anyway).

The version of Node I'm using is v12, so please update to this version if you're using an older version.

Finally, a note for Windows users: all of the commands I'm running are meant for Linux/Unix environments. For you to follow along verbatim you'll need either to run a virtual machine or Windows Subsystem for Linux. If you decide to try doing this using Windows PowerShell let me know where you have trouble and I'll try to update this guide accordingly.

To keep things simple we won't be using any frontend frameworks; our example will be fairly Brutalist in design: simple and functional.

Let's go!

Create a new directory for your project:

mkdir microblog
cd microblog

Initialize the NPM project:

npm init

NPM will ask you a bunch of questions, most of which you can leave blank.

Now install our main dependency, node-activitypub:

npm install https://gitlab.com/paulkiddle/node-activitypub/paulkiddle/node-activitypub

Now we're ready to start writing code.

My first Actor

The first thing we're going to do is create a server, and create an actor.

The Actor is the most important ActivityPub object, without Actors you really can't do anything interesting. In our case the Actor is the user who will be publishing statuses and following other users. There are other types of actor, but don't worry about those for now.

Once we've done that we can create a server, which will listen on a specific port and respond to http requests. node-activitypub automatically handles requests for ActivityPub objects, so there's really very little configuration you need to do to get everything working.

Create a file called index.js and add this code:

const { ActivityPub } = require('node-activitypub');

const pub = new ActivityPub();

// This function creates a new actor and stores it in memory
// so the webserver can look it up later when it needs to.
pub.createActor('Paul');

// The `listen` function will create a webserver and listen on the default port.
// You can provide a callback to call when then server has finished setting up
// and started listening for requests.
pub.listen(() => {
	// The ActivityPub class exposes a property called `appRoot` which is the base url for your app.
	console.log('App root:', pub.appRoot);
});

If you now run node index.js it will output the app root. If you navigate to this URL you'll get a 404, because we haven't configured a landing page - we'll do that later.

But if you add /u/Paul to the end of the URL you'll be presented with a JSON representation of your actor!

This is the first step of connecting to ActivityPub.

Production server

In order to federate, your server needs to be on the public internet; that means creating a production server.

We're going to use Heroku as it's easy and straightforward. Create an account and go to the dashboard to create your new site. The hostname of your new site will be of the form example-app.herokuapp.com.

If you haven't already, install git and the Heroku CLI.

Init a new git repository and commit these changes (see Appendix A for more), not forgetting to add node_modules to the .gitignore file:

# .gitignore
node_modules
git init
git add .
git commit -m "Set up activitypub server"

Before we can push this code to production, we need to make a couple of changes: first, we need to tell node-activitypub what the hostname is. Secondly, we need to create a keypair. ActivityPub uses public key cryptography to verify an actor is who they say they are. In development mode this key is generated for you under the hood, a different keypair each time you run the program. On production we need these keys to stay the same for each user, so we'll have to generate one and save it as an environment variable.

node-activitypub provides a script you can run to generate the keys for you:

./node_modules/.bin/gen-keypair

You can set these values as environment variables using the heroku CLI:

heroku config:set HOST=example-app.herokuapp.com
heroku config:set KEYPAIR="$(./node_modules/.bin/gen-keypair)"

If you're struggling with the CLI you can also use Heroku's web interface and paste these values in.

node-activitypub will look for the HOST variable without any further configuration, but not the KEYPAIR variable. To pass that to our actor we need to make another little adjustment:

const keypair = process.env.KEYPAIR && JSON.parse(process.env.KEYPAIR);

pub.createActor({
	username: 'Paul',
	keypair
});

Add and commit this file and push it to the server:

git add .
git commit -m "Add production configuration variable"
heroku git:remote -a example-app
git push --set-upstream heroku master

Now visit https://example-app.herokuapp.com/u/Paul - you'll see the actor you created. Congratulations, your actor is now online! If you paste the actor's URL into Mastodon's search bar you should see a basic profile for your user. node-activitypub also handles webfingers - try searching @paul@example-app.herokuapp.com, or check https://webfinger.net/lookup/?resource=paul%40apub-test.herokuapp.com

Appendix A

Use git init to create a new local git repository. Using git we can save our code as a collection of file changes, and send them to the production server in an organised way. Some of the files we don't need to send over; for example, the node_modules directory (created by npm, containing our dependencies) is not necesarry, because Heroku can read our package.json file and recreate this folder automatically. We can tell git to ignore this directory by creating a file called .gitignore and adding the files to ignore.

Now run git add . to mark all files as ones you want to add, and git commit -m "Initial commit" to commit them.