Commit b6494849 authored by Izalia Mae's avatar Izalia Mae
Browse files

Reorganize codebase

parent 5c5f212d
FROM python:3-alpine
WORKDIR /workdir
# install build deps for pycryptodome and other c-based python modules
RUN apk add alpine-sdk autoconf automake libtool gcc
ADD requirements.txt /workdir/
RUN pip3 install -r requirements.txt
# add env var to let the relay know it's in a container
ADD . /workdir/
# setup various container properties
VOLUME ["/data"]
CMD ["python", "-m", "relay"]
EXPOSE 8080/tcp
WORKDIR /opt/activityrelay
# install and update important python modules
RUN pip3 install -U setuptools wheel pip
VOLUME ["/workdir/data"]
# only copy necessary files
COPY relay ./relay
COPY requirements.txt .
COPY setup.cfg .
COPY .git ./.git
# install relay deps
RUN pip3 install -r requirements.txt
......@@ -10,72 +10,14 @@ Affero General Public License version 3 (AGPLv3) license. You can find a copy o
in this package as the `LICENSE` file.
## Setup
You need at least Python 3.6 (latest version of 3.x recommended) to make use of this software.
It simply will not run on older Python versions.
Download the project and install with pip (`pip3 install .`).
Copy `relay.yaml.example` to `relay.yaml` and edit it as appropriate:
$ cp relay.yaml.example relay.yaml
$ $EDITOR relay.yaml
Finally, you can launch the relay:
$ python3 -m relay
It is suggested to run this under some sort of supervisor, such as runit, daemontools,
s6 or systemd. Configuration of the supervisor is not covered here, as it is different
depending on which system you have available.
The bot runs a webserver, internally, on localhost at port 8080. This needs to be
forwarded by nginx or similar. The webserver is used to receive ActivityPub messages,
and needs to be secured with an SSL certificate inside nginx or similar. Configuration
of your webserver is not discussed here, but any guide explaining how to configure a
modern non-PHP web application should cover it.
## Getting Started
Normally, you would direct your LitePub instance software to follow the LitePub actor
found on the relay. In Pleroma this would be something like:
$ MIX_ENV=prod mix relay_follow https://your.relay.hostname/actor
Mastodon uses an entirely different relay protocol but supports LitePub relay protocol
as well when the Mastodon relay handshake is used. In these cases, Mastodon relay
clients should follow `http://your.relay.hostname/inbox` as they would with Mastodon's
own relay software.
## Performance
Performance is very good, with all data being stored in memory and serialized to a
JSON-LD object graph. Worker coroutines are spawned in the background to distribute
the messages in a scatter-gather pattern. Performance is comparable to, if not
superior to, the Mastodon relay software, with improved memory efficiency.
## Management
You can perform a few management tasks such as peering or depeering other relays by
invoking the `relay.manage` module.
This will show the available management tasks:
$ python3 -m relay.manage
When following remote relays, you should use the `/actor` endpoint as you would in
Pleroma and other LitePub-compliant software.
$ MIX_ENV=prod mix relay_follow https://your.relay.hostname/actor
## Docker
You can run ActivityRelay with docker. Edit `relay.yaml` so that the database
location is set to `./data/relay.jsonld` and then build and run the docker
image :
## Documentation
$ docker volume create activityrelay-data
$ docker build -t activityrelay .
$ docker run -d -p 8080:8080 -v activityrelay-data:/workdir/data activityrelay
To install or manage your relay, check the [documentation](docs/
#!/usr/bin/env bash
case $1 in
docker build -f Dockerfile -t activityrelay . && \
docker volume create activityrelay-data && \
docker run -it -p 8080:8080 -v activityrelay-data:/data --name activityrelay activityrelay
docker stop activityrelay && \
docker container rm activityrelay && \
docker volume rm activityrelay-data && \
docker image rm activityrelay
docker start activityrelay
docker stop activityrelay
docker exec -it activityrelay python3 -m relay "$@"
docker exec -it activityrelay bash
docker run -it --rm --entrypoint bash -v activityrelay-data:/data activityrelay
if [ -z ${EDITOR} ]; then
echo "EDITOR environmental variable not set"
CONFIG="/tmp/relay-$(date +"%T").yaml"
docker cp activityrelay:/data/relay.yaml $CONFIG && \
docker cp $CONFIG activityrelay:/data/relay.yaml && \
COLS="%-22s %s\n"
echo "Valid commands:"
printf "$COLS" "- start" "Run the relay in the background"
printf "$COLS" "- stop" "Stop the relay"
printf "$COLS" "- manage <cmd> [args]" "Run a relay management command"
printf "$COLS" "- edit" "Edit the relay's config in \$EDITOR"
printf "$COLS" "- shell" "Drop into a bash shell on the running container"
printf "$COLS" "- rescue" "Drop into a bash shell on a temp container with the data volume mounted"
printf "$COLS" "- install" "Build the image, create a new container and volume, and run relay setup"
printf "$COLS" "- uninstall" "Delete the relay image, container, and volume"
# Commands
There are a number of commands to manage your relay's database and config. You can add `--help` to
any category or command to get help on that specific option (ex. `activityrelay inbox --help`).
Note: Unless specified, it is recommended to run any commands while the relay is shutdown.
## Run
Run the relay.
activityrelay run
## Setup
Run the setup wizard to configure your relay.
activityrelay setup
## Inbox
Manage the list of subscribed instances.
### List
List the currently subscribed instances or relays.
activityrelay inbox list
### Add
Add an inbox to the database. If a domain is specified, it will default to `https://{domain}/inbox`.
If the added instance is not following the relay, expect errors when pushing messages.
activityrelay inbox add <inbox or domain>
### Remove
Remove an inbox from the database. An inbox or domain can be specified.
activityrelay inbox remove <inbox or domain>
### Follow
Follow an instance or relay actor and add it to the database. If a domain is specified, it will
default to `https://{domain}/actor`.
activityrelay inbox follow <actor or domain>
Note: The relay must be running for this command to work.
### Unfollow
Unfollow an instance or relay actor and remove it from the database. If the instance or relay does
not exist anymore, use the `inbox remove` command instead.
activityrelay inbox unfollow <domain, actor, or inbox>
Note: The relay must be running for this command to work.
## Whitelist
Manage the whitelisted domains.
### List
List the current whitelist.
activityrelay whitelist list
### Add
Add a domain to the whitelist.
activityrelay whitelist add <domain>
### Remove
Remove a domain from the whitelist.
activityrelay whitelist remove <domain>
## Instance
Manage the instance ban list.
### List
List the currently banned instances
activityrelay instance list
### Ban
Add an instance to the ban list. If the instance is currently subscribed, remove it from the
activityrelay instance ban <domain>
### Unban
Remove an instance from the ban list.
activityrelay instance unban <domain>
## Software
Manage the software ban list. To get the correct name, check the software's nodeinfo endpoint.
You can find it at nodeinfo\['software']\['name'].
### List
List the currently banned software.
activityrelay software list
### Ban
Add a software name to the ban list.
If `-f` or `--fetch-nodeinfo` is set, treat the name as a domain and try to fetch the software
name via nodeinfo.
If the name is `RELAYS` (case-sensitive), add all known relay software names to the list.
activityrelay software ban [-f/--fetch-nodeinfo] <name, domain, or RELAYS>
### Unban
Remove a software name from the ban list.
If `-f` or `--fetch-nodeinfo` is set, treat the name as a domain and try to fetch the software
name via nodeinfo.
If the name is `RELAYS` (case-sensitive), remove all known relay software names from the list.
activityrelay unban [-f/--fetch-nodeinfo] <name, domain, or RELAYS>
# Configuration
## DB
The path to the database. It contains the relay actor private key and all subscribed
instances. If the path is not absolute, it is relative to the working directory.
db: relay.jsonld
## Listener
The address and port the relay will listen on. If the reverse proxy (nginx, apache, caddy, etc)
is running on the same host, it is recommended to change `listen` to `localhost`
port: 8080
## Note
A small blurb to describe your relay instance. This will show up on the relay's home page.
note: "Make a note about your instance here."
## Post Limit
The maximum number of messages to send out at once. For each incoming message, a message will be
sent out to every subscribed instance minus the instance which sent the message. This limit
is to prevent too many outgoing connections from being made, so adjust if necessary.
push_limit: 512
## AP
Various ActivityPub-related settings
### Host
The domain your relay will use to identify itself.
### Whitelist Enabled
If set to `true`, only instances in the whitelist can follow the relay. Any subscribed instances
not in the whitelist will be removed from the inbox list on startup.
whitelist_enabled: false
### Whitelist
A list of domains of instances which are allowed to subscribe to your relay.
### Blocked Instances
A list of instances which are unable to follow the instance. If a subscribed instance is added to
the block list, it will be removed from the inbox list on startup.
### Blocked Software
A list of ActivityPub software which cannot follow your relay. This list is empty by default, but
setting this to the above list will block all other relays and prevent relay chains
- activityrelay
- aoderelay
- unciarelay
## Cache
These are object limits for various caches. Only change if you know what you're doing.
### Objects
The urls of messages which have been processed by the relay.
objects: 1024
### Actors
The ActivityPub actors of incoming messages.
actors: 1024
### Actors
The base64 encoded hashes of messages.
digests: 1024
# ActivityRelay Documentation
ActivityRelay is a small ActivityPub server that relays messages to subscribed instances.
# Installation
There are a few ways to install ActivityRelay. Follow one of the methods below, setup a reverse
proxy, and setup the relay to run via a supervisor. Example configs for caddy, nginx, and systemd
in `installation/`
## Pipx
Pipx uses pip and a custom venv implementation to automatically install modules into a Python
environment and is the recommended method. Install pipx if it isn't installed already. Check out
the [official pipx docs]( for more in-depth instructions.
python3 -m pip install pipx
Now simply install ActivityRelay directly from git
pipx install git+
Or from a cloned git repo.
pipx install .
Once finished, you can set up the relay via the setup command. It will ask a few questions to fill
out config options for your relay
activityrelay setup
Finally start it up with the run command.
activityrelay run
Note: Pipx requires python 3.7+. If your distro doesn't have a compatible version of python, it can
be installed via
## Pip
The instructions for installation via pip are very similar to pipx. Installation can be done from
python3 -m pip install git+
or a cloned git repo.
python3 -m pip install .
Now run the configuration wizard
activityrelay setup
And start the relay when finished
activityrelay run
## Docker
Installation and management via Docker can be handled with the `` script. To install
ActivityRelay, run the install command. Once the image is built and the container is created,
your will be asked to fill out some config options for your relay.
./ install
Finally start it up. It will be listening on TCP port 8080.
./ start
......@@ -9,18 +9,25 @@ port: 8080
# Note
note: "Make a note about your instance here."
# maximum number of inbox posts to do at once
post_limit: 512
# this section is for ActivityPub
# this is used for generating activitypub messages, as well as instructions for
# linking AP identities. it should be an SSL-enabled domain reachable by https.
host: ''
- ''
- ''
whitelist_enabled: false
- ''
- ''
# uncomment the lines below to prevent certain activitypub software from posting
# to the relay (all known relays by default). this uses the software name in nodeinfo
......@@ -28,3 +35,9 @@ ap:
#- 'aoderelay'
#- ''
#- 'unciarelay'
# cache limits as number of items. only change this if you know what you're doing
objects: 1024
actors: 1024
digests: 1024
from . import logging
__version__ = '0.2.0'
from aiohttp.web import Application
import asyncio
import aiohttp
import aiohttp.web
import yaml
import argparse
from . import logger
parser = argparse.ArgumentParser(
description="A generic LitePub relay (works with all LitePub consumers and Mastodon).",
prog="python -m relay")
parser.add_argument("-c", "--config", type=str, default="relay.yaml",
metavar="<path>", help="the path to your config file")
args = parser.parse_args()
def load_config():
with open(args.config) as f:
options = {}
## Prevent a warning message for pyyaml 5.1+
if getattr(yaml, 'FullLoader', None):
options['Loader'] = yaml.FullLoader
yaml_file = yaml.load(f, **options)
config = {
'db': yaml_file.get('db', 'relay.jsonld'),
'listen': yaml_file.get('listen', ''),
'port': int(yaml_file.get('port', 8080)),
'note': yaml_file.get('note', 'Make a note about your instance here.'),
'ap': {
'blocked_software': [v.lower() for v in yaml_file['ap'].get('blocked_software', [])],
'blocked_instances': yaml_file['ap'].get('blocked_instances', []),
'host': yaml_file['ap'].get('host', 'localhost'),
'whitelist': yaml_file['ap'].get('whitelist', []),
'whitelist_enabled': yaml_file['ap'].get('whitelist_enabled', False)
return config
CONFIG = load_config()
from .http_signatures import http_signatures_middleware
app = aiohttp.web.Application(middlewares=[
from . import database
from . import actor
from . import webfinger
from . import default
from . import nodeinfo
from . import http_stats
app = Application()
import asyncio
import aiohttp.web
import logging
import platform
import sys
import Crypto
import time
from . import app, CONFIG
def crypto_check():
vers_split = platform.python_version().split('.')
pip_command = 'pip3 uninstall pycrypto && pip3 install pycryptodome'
if Crypto.__version__ != '2.6.1':
if int(vers_split[1]) > 7 and Crypto.__version__ == '2.6.1':
logging.error('PyCrypto is broken on Python 3.8+. Please replace it with pycryptodome before running again. Exiting in 10 sec...')
logging.warning('PyCrypto is old and should be replaced with pycryptodome')