Run Your Own Mastodon Server on FreeBSD in a Potluck Container


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:

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_untrusted="inet netmask"

You will also need a domain name, with the subdomains and 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

Obtaining The Playbook And Setting Up Environment

Clone the git repo and configure the environment as follows:

git clone
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:


Set the hostname or IP address of your server in the following field, do not change other fields on this line:

server1 ansible_host=REPLACE-WITH-IP-HOSTNAME ...

If your server has IPv6 enabled, make sure to set the following field from no to yes:


Update the following fields with a long complicated string of characters to secure your minio instance. This is the minio admin user:


Update the following fields to set your email address and domain names for certificate registration:


Update the haproxy frontend IP address to match your server’s public IPv4 address:


Scroll down and set a grafana admin user and password:


Also include mail server parameters for alertmanager notices:


Further down the file is the following setting, configure it as files.your.domain:


Scroll further down and modify the zincsearch admin user and password:


Page down some more and set a postgresql_exporter password:


You can also set the Mastodon user password for postgresql:


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:


Configure email notifications for Mastodon with the following fields:


Use the same postgresql password as above:


Then update the following field to match the files.your.domain configuration:


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:


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 (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 with the user/pass you configured in the inventory file.

All the monitoring services are on the same fixed internal IP, 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 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.