Home Breaking things and having fun with ActivityPub

Breaking things and having fun with ActivityPub

My notes on installing and updating a tiny ActivityPub server implementation. Syndication

A call was sent out today by Terence Eden @[email protected] to try out a tiny AP server. I gave it a shot.

The code is now public and has a “CRAPL” licensce, which makes me chuckle.

This server is a single PHP file, along with an avatar photo and an .htaccess file for routing.

I’m calling it “ActivityPub Edent Server”, or “A.P.E.S.” for short.

It works!

Taking directly from Terence’s own words, this code is complete crap and shouldn’t be run in production. It’s just a lab to demonstrate how ActivityPub works.

Here’s the end result! You can follow me at @[email protected] and see my posts just like a grown up ActivityPub server.

The site is up for now but this is just for fun and most likely I will kill it at some point.


A screenshot of my A.P.E.S. account


  • A domain name
  • A SSL certificate
  • A web server
  • PHP 8
  • A web server module to rewrite paths

My installation:

I used a prepackaged docker container with an Apache/PHP image including mod_rewrite.

  • The Web Server: Apache 2.4
  • PHP Version: 8.3
  • Path Rewrites: Apache mod_rewrite

I couldn’t help it and created my own avatar just to be a bit different, but I veered away from touching any of the code for now (adding a banner image, some styling, etc.)

My hosting environment

My homelab on a BeeLink MiniPC in Portainer

It’s running behind Nginx Proxy Manager

Cloudflare is my DNS, but I’m not using the proxy. I might turn it on later.


Most of the configuration wasn’t that bad. As with all AP implementations, you need to give your domain a good thought before using it. Whatever you choose, even long after you’re tired of fiddling with it for fun, will continue to receive requests to it’s inbox (if it’s there or not). Be aware, if you ever lose control of your domain, the next person that owns it will have access to those incoming messages as well.

I always use a sub-domain, and in this instance chose ape.box464.social. Hopefully, this means that only ape.box464.social will be affected, and I can create a mastodon.box464.social and a friendica.box464.social and a bonfire.box464.social without them being hurt.

Public and Private Keys

This is what would probably scare off the most people. It’s not bad, really. Use the tool Edent linked to in the code to create your Public and Private keys - and then store them in your password vault so you don’t lose them. Use the 2048 key length option, as it’s currently the most common.

After that, you’ve got to do some trickyness by removing the actual line returns (\n) with the text “\n” instead so it’s just one long string.

I found BBEdit the easiest way to do this on my Mac, and that was with these Search and Replace settings.

You can achieve this using the Find and Replace functionality with regular expressions. Here’s a step-by-step guide:

  1. Open a text file in BBEdit and paste your private key.
  2. Press Command + F to open the Find window.
  3. Check the “Grep” option to enable regular expressions.
  4. In the “Find” field, enter \n (which represents the end of a line).
  5. In the “Replace” field, enter \\n (double backslash followed by ‘n’, which will be replaced by the literal string “\n”).
  6. Click on “Replace All” to replace all occurrences of line breaks with the literal string “\n”.
  7. Repeat with the public key in another text file

Copy the public and private strings into their appropriate locations in the file.


All tests worked as expected.


During my build, I ran into two issues:

Attempt 1

Used PHP 7.4 and /write endpoint failed

Fatal error: Uncaught Error: Cannot unpack array with string keys in /var/www/html/index.php:411 Stack trace: #0 /var/www/html/index.php(91): send() #1 {main} thrown in /var/www/html/index.php on line 411

Attempt 2

Used PHP 8.3 and now I receive a warning on Line 74, but everything works. I set my container to run in production mode so the error doesn’t appear right now.

Warning: Undefined array key "path" in /var/www/html/index.php on line 74

Follow Ups

After a day or so connected to a single follower on mastodon.social, I can see a lot of DELETE requests coming in. This is something I’ve noticed with my Postmarks and GtS instances as well, tons of DELETE requests along the way for people and objects that have never reached my instance. I guess in the fediverse, this is a necessity because you never know how a post would end up on a specific server, so you have to blast it out to everyone you’re aware of.

Logs are a bit cumbersome to review and there isn’t a way to remove older logs yet. Fun little weekend project and you can say “I’m on the fediverse!”.

Sprucing up the place

I’d like to see some simple sprucification of the home page and posting pages. With the followers available as a JSON it wouldn’t be hard to bring that on the page either.

Homepage could at least include the About Me and Profile Image, maybe the followers list.

To iterate through posts, you’d have to do so via PHP and then parse each JSON file.


I submitted a merge request, and now we have a little home page displaying basic info as expected. 😀

Also added one for converting line breaks to <br/> tags in posts prior to hitting the outboxes. Fingers crossed it will be accepted!

Final Thoughts

This was fun. It’s easy to read the code, it’s simple, and breaking it has no major effect on anyone else. Go have fun, hit it with hammers, destroy it, recreate it. Don’t be scared to play and learn.

This post is licensed under CC BY 4.0 by the author.

My Current Favorite Podcasts

Bluesky Personal Data Servers - Important, well constructed and boring as hell


Total Interactions: 32
23 Likes 0 Links 0 Posts 8 Re-posts 0 Bookmarks 1 Replies


Posts, Re-Posts and Bookmarks


  1. @box464 I am fairly confident that @Edent will endorse "A.P.E.S." as the official name of this code... ????️