Run Your Own Mastodon Server on FreeBSD in a Potluck Container
Introduction
Have you heard of Mastodon?
Mastodon is a self-hosted social networking service, where independently run servers federate content to each other using ActivityPub.
Each Mastodon server has its own set of users, own code of conduct, own terms and moderation policies.
Users post short messages (called “toots”) to the world, or to select people. They can also subscribe to other users’ feeds on any server.
ActivityPub is a standard for the Internet in the Social Web Networking Group of the World Wide Web Consortium (W3C).
It is an open, decentralized social networking protocol which provides an API for managing content, and federated server-to-server notifications and content distribution.
The collective term for federated services which use ActivityPub is “the fediverse”, a portmanteau of “federation” and “universe”.
Mastodon is one part of the fediverse, where Wikipedia maintains a listing of others.
What is Involved in Your Own Mastodon Instance?
Your own Mastodon instance will require a few things:
- Domain name and fixed IP
postgresql
redis
- Webserver with support for
ruby
,node
- S3-compatible file store (see How To Set Up a Minio Cluster From Potluck, Complete With Nextcloud, Monitoring And Alerting)
The setup itself is mainly configuring a number of parameters as described in this article and running the ansible
playbook described in this article which will pull the container images, configure and start them.
Easy Setup on FreeBSD With Potluck
There is an easy install using an ansible
playbook for FreeBSD systems, that will provide a complete environment with monitoring and alerting.
You will need a FreeBSD 13.2 or 14.0 server with the following prerequisites:
You must configure the server’s default network interface to be labelled ‘untrusted’. For example, with interface em0
:
ifconfig_em0_name="untrusted"
ifconfig_untrusted="inet 192.168.1.1 netmask 255.255.255.0"
You will also need a domain name, with the subdomains mastodon.domain.name
and files.domain.name
pointing at the same IP.
The ansible
script below will provision a version of Mastodon with a patch to allow 5000 character posts, alternatively you can also pull the official Mastodon versions from https://github.com/mastodon/mastodon.
Obtaining The Playbook And Setting Up Environment
Clone the git repo and configure the environment as follows:
git clone https://codeberg.org/Honeyguide/mastodon-sampler.git
cd mastodon-sampler
Set Up a Python Virtual Environment to Ensure Correct Version Of ansible
Set up a python
virtual environment to ensure correct version of ansible
as below.
If not already installed, install python
virtualenv:
python3 -m pip install virtualenv
Then create a virtual environment and activate it, before installing the required dependencies:
python3 -m venv .venv
source .venv/bin/activate
(.venv) .venv/bin/python3 -m pip install --upgrade pip
(.venv) .venv/bin/python3 -m pip install -r requirements.txt
It’s important to note that you will run the ansible-playbook executable from the virtual environment created, but do not do this yet!
.venv/bin/ansible-playbook -i [inventory] [playbook]
Update The Inventory Parameters
Update the inventory parameters to reflect all your specific details:
(.venv) cd inventory
(.venv) cp hosts.sample hosts
(.venv) nano hosts
Set your default username on the remote server in the following field. This is the username you ssh
to your server as:
my_default_username=REPLACE-WITH-USERNAME
Set the hostname or IP address of your server in the following field, do not change other fields on this line:
[servers]
server1 ansible_host=REPLACE-WITH-IP-HOSTNAME ...
If your server has IPv6 enabled, make sure to set the following field from no
to yes
:
pf_ipv6_enable=yes
Update the following fields with a long complicated string of characters to secure your minio
instance. This is the minio
admin user:
minio_user=REPLACE-WITH-LONG-MINIO-USERNAME
minio_pass=REPLACE-WITH-LONG-MINIO-PASSWORD
Update the following fields to set your email address and domain names for certificate registration:
my_acme_email=REPLACE-WITH-EMAIL-ADDRESS
my_acme_domain=REPLACE-WITH-DOMAIN-NAME
my_acme_alias1=mastodon.REPLACE-WITH-DOMAIN-NAME
my_acme_alias2=files.REPLACE-WITH-DOMAIN-NAME
Update the haproxy
frontend IP address to match your server’s public IPv4 address:
haproxy_public_ip=REPLACE-FRONTEND-IP
Scroll down and set a grafana
admin user and password:
pot_beast_grafana_user=REPLACE-GRAFANA-USER
pot_beast_grafana_pass=REPLACE-GRAFANA-PASSWORD
Also include mail server parameters for alertmanager
notices:
pot_beast_smtphostport=localhost:25
pot_beast_smtp_from=notices@REPLACE-WITH-DOMAIN-NAME
pot_beast_alertaddress=REPLACE-WITH-EMAIL
pot_beast_smtp_user=
pot_beast_smtp_pass=
Further down the file is the following setting, configure it as files.your.domain
:
pot_nomad_s3_domain_name=REPLACE-WITH-FILES-DOMAIN-NAME
Scroll further down and modify the zincsearch
admin user and password:
pot_zincsearch_user=SET-ZINC-USER
pot_zincsearch_pass=SET-ZINC-PASSWORD
Page down some more and set a postgresql_exporter
password:
pot_postgresql_exporter_pass=REPLACE-PGEXPORTER-PASS
You can also set the Mastodon user password for postgresql
:
pot_postgresql_mastodon_password=REPLACE-WITH-MASTODON-DB-PASSWORD
A little further down are parameters for the Mastodon instance.
Set the domain name of your mastodon instance, for the purposes of this playbook make it mastodon.your.domain
:
pot_mastodon_domain=REPLACE-WITH-DOMAIN-NAME
Configure email notifications for Mastodon with the following fields:
pot_mastodon_to_email=YOUR-EMAIL
pot_mastodon_from_email=YOUR-EMAIL
pot_mastodon_email_host=YOUR-EMAIL-HOST
pot_mastodon_email_port=465
pot_mastodon_smtp_user=YOUR-SMTP-USER
pot_mastodon_smtp_pass=YOUR-SMTP-PASS
Use the same postgresql
password as above:
pot_mastodon_db_pass=REPLACE-WITH-MASTODON-DB-PASSWORD
Then update the following field to match the files.your.domain
configuration:
pot_mastodon_public_s3_host=files.REPLACE-WITH-DOMAIN-NAME
For the purposes of this playbook we don’t set any secret_key
or otp_key
and related, we’ll allow the image to generate them. Leave these fields blank to have them autogenerated in the resulting image.
Finally, scroll to the very bottom and update the following field with a long complicated password for the Mastodon minio
user. This must be different from the admin password:
mastodon_minio_pass=REPLACE-WITH-LONG-MINIO-MASTODON-PASSWORD
Run The playbook
Change back to the parent directory and run the playbook as follows:
(.venv) cd ..
(.venv) .venv/bin/ansible-playbook -i inventory/hosts site.yml
The playbook will take approximately 60-90mins to provision your Mastodon server.
When complete, a QR code for a wireguard link will be displayed. Make sure to get a screen capture of this, then load it into a QR Code viewer to extract the text.
Copy the extracted text into your wireguard client and then connect.
You can now connect to the IP address displayed in the final task in the playbook.
Open http://10.1.2.10 (or whichever IP is assigned) to get an index page to the various internal services.
From here you can access the links, for example if you want to see charts you can access grafana
at http://10.1.2.250:3000 with the user/pass you configured in the inventory file.
All the monitoring services are on the same fixed internal IP 10.1.2.250, but the port changes between services.
You can also access dashboards for consul
, nomad
and traefik
which are on different IP addresses.
If you need to access minio
, you can do so directly at https://10.1.1.1:9000. Make sure to accept the self-signed certificate TWICE because the port changes automatically and you need to accept it for each port.
Configure First Mastodon User
Open mastodon.your.domain
and setup your first user.
In Case Of Problems
If you have any problems, you can clean the system and try over.
If you misconfigured your inventory, or something went wrong, you can run the clean.yml
playbook to clean your system of all images and data.
Important: make sure to disconnect your wireguard session before running clean.yml
.
(.venv) .venv/bin/ansible-playbook -i inventory/hosts clean.yml
All data will be wiped too so don’t run this on a system in regular use. It’s for cleaning a bad initial install.
Then make changes to the playbook or inventory and run site.yml
again to provision.