I'm working on my own implementation of ActivityPub in Rust. activitypub.rocks is a great starting point, the specs are quite readable and there is the very good book written by Evan. But those are not very helpful if I think I followed their rules, yet other servers don't want to talk to my code.
In theory "other servers" means every other AP server, but I had to get started somewhere. The obvious choice was Mastodon, because it is the most common one. So my idea was:
Is it feasible to have a local Mastodon instance for development? I would let my code talk to it, and if something goes wrong, I'll fire up a debugger to have a live view of why Mastodon is unhappy with my request.
The answer is "Yes!" and this document will show I got this working without too much effort.
Mastodon actually has very straightforward docs for this. I chose the "Manual install from source" option, because I wanted to attach the process to a Ruby debugger later. I have only very basic Ruby skills and don't want to increase the challenge by adding Docker to the mix.
Most additional services are optional, but you will need Postgres and Redis.
This compose.yaml is all you need:
services:
db:
image: "postgres:17"
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: adminpwd
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- type: bind
source: ./pg_data
target: /var/lib/postgresql/data
redis:
image: "redis"
ports:
- "6379:6379"
Run docker compose up and you should be ready to go.
Some features require me to expose my development instance to the public Internet. My general approach of using Caddy and a tiny Hetzner VM is described here. The Caddyfile for this use case looks like this:
dev.my.domain {
reverse_proxy * 0.0.0.0:3333
}
masto.my.domain {
handle_path /api/v1/streaming {
reverse_proxy * 0.0.0.0:4000
}
reverse_proxy * 0.0.0.0:3000
}
To prevent confusion: Port 3333 is used by my own app and it uses the dev
subdomain. Port 3000 is used by the main Rails application. The Vite server
uses port 4000. Getting the streaming stuff right was the most challenging
part, because it requires additional tweaking.
A few required settings are missing to get everything working via the public URL. Look at the great Mastodon docs for details. Using a Fish shell, I set the required variables to those values:
set -x LOCAL_DOMAIN masto.my.domain
set -x RAILS_LOG_LEVEL debug
set -x RAILS_ENV development
set -x DB_USER mastodon
set -x DB_PASS mastodon
set -x DB_HOST localhost
set -x RAILS_SERVE_STATIC_FILES 1
set -x STREAMING_API_BASE_URL wss://masto.my.domain
Most settings should be obvious, assuming you have basic web dev skills. The
trickiest part for me was the last line. The development setup expects
requests from the local machine. The WebSocket connection will not work via
the SSH tunnel from the public domain. Hardcoding STREAMING_API_BASE_URL to
the correct wss connection was the simplest fix I could find.
Now would be a good time to have a break and check that everything is working fine.
The remaining steps were suprisingly easy. I'm a user of Neovim, but for this debugging experiment I decided to go for Visual Studio Code. After a fresh install, I added the "Ruby LSP" and "VSCode rdbg Ruby Debugger" extensions.
Finally, open the Procfile.dev in your Mastodon folder and change the line for web to this one:
web: env PORT=3000 bundle exec rdbg --open -n -c --\
bundle exec puma -C config/puma.rb
The bundle exec rdbg --open -n -c part runs Mastodon with remote
debugging enabled. After restarting your instance: