So you want to start your own Fediverse server? This guide will walk you through it step-by-step, including the concrete details.

Preface

This will take you 2–4 hours and cost you at least $15/mo. You can collect donations using PayPal or Patreon to help you cover the cost.

Technical experience is needed. If you don't have the experience, you should read Run Your Own Social instead and find someone with technical experience to read this article. You'll need someone able to use a terminal.

This article covers the doing. Shoot first and ask questions later.

You'll need to use a terminal to run commands on the server

About me

I created spinster.xyz with MK Fain. It gained over 7000 users in its first month, and sustained attacks from the outside due to its controversial nature. User activity crashed the server and I had to scale it. This article will incorporate what I've learned.

Spinster stats from fediverse.network at time of writing

Mastodon vs Pleroma vs Gab

  • Mastodon is the most feature-rich option. I highly recommend it as the main choice.
  • Pleroma is significantly more efficient than Mastodon. It's geared towards advanced users.
  • There are also some Mastodon forks, such as glitch-soc, Gab Social, and Spinster. They have different goals and limited development resources.

For this guide, we'll be using Mastodon. Please don't overthink this. Running my own fork has taught me it's not for the faint of heart. Pleroma is great if your users are advanced, but this guide is intended for servers geared towards the average person.

Step 1: Domain name

Choose a domain name for your server. Ideally, choose something that's 2 syllables or less and resonates with your users.

I recommend using NameCheap to buy the domain name. You can search for available names there.

When naming Spinster, we tried a few different things.

  1. I created word clouds with data from Wikipedia and Reddit.
  2. We used Namelix to generate business names using artificial intelligence.
Word cloud generated from Wikipedia's List of Feminist Literature.

These activities got us thinking, but ultimately didn't lead us to the answer.

While scanning our bookshelf I saw The Spinster and Her Enemies by Sheila Jeffreys. It occurred to me that "Spinster" sounds like "Twitter," and that it could be used in a positive way like Jeffreys intended.

When I pitched the name Spinster, it was met with hesitation.

Conversation with MK about the name "Spinster"

Go with your gut. Spend time on this, but once you have a name you like don't second-guess yourself or you'll stall.

Once you have a name idea, start searching on NameCheap. .com is the best option, but in my opinion .xyz is just as good and it's usually cheap too. spinster.xyz cost us $1, so you should not feel pressure to spend a lot of money.

Step 1.1: Use Cloudflare

Cloudflare is a free service that will protect your site against DDoS attacks. It works by sitting between your domain name and server, absorbing malicious traffic.

How Cloudflare works

Once you've purchased your domain name on NameCheap, create an account on Cloudflare and follow the instructions. You will need to go back to Namecheap and configure your DNS to point to Cloudflare.

Adding a domain name on Cloudflare

On NameCheap, go into your domain settings and change the "Nameservers" dropdown to "Custom DNS," then enter the names provided by Cloudflare. More detailed instructions are here (although Cloudflare screenshots are outdated).

Configuring NameCheap to use Cloudflare nameservers

From now on, your domain will be configured through Cloudflare. You'll log into Cloudflare, not NameCheap, to manage subdomains and DNS records.

One last thing while you are here, go under the SSL/TLS tab and set encryption mode to Full. This will be needed later to prevent infinite redirects.

Cloudflare SSL mode

Step 1.2: Set up email

You will need an email provider to send confirmation emails, "I forgot my password" emails, and other notification emails to your users.

To do this, create an account with Postmark and follow the instructions to set it up with your domain name. You will need to:

  • Create a server.
  • Add a domain.

Under the "servers" tab, click "Create server" and follow the instructions.

Creating a Postmark server

You will also want to add a domain. In the screenshot below, choose the left option ("any email address") and follow the instructions.

Remember, you will need to configure this within Cloudflare. Go back into Cloudflare, then "DNS". Add a TXT record and CNAME record as instructed. I had to set the CNAME to "DNS only" by clicking the orange cloud icon before it worked.

Postmark DNS on Cloudflare

You can verify everything is working once you have all green checkmarks.

Green checkmarks indicate the domain is working

Finally, you will need to take note of your credentials. Go into your server, then click "Default Transactional Stream," "Setup Instructions," and finally "SMTP."

You will need these credentials later when configuring your server

Leave this tab open or copy the contents somewhere for later reference.

Step 2: Create the Mastodon server

Now we need to set up the public-facing server on the internet running Mastodon. We'll use DigitalOcean for this because it provides a 1-click installer for Mastodon.

After creating a DigitalOcean account, it's a good idea to create a team so multiple people can easily manage the server in the future.

Creating a team in DigitalOcean

Once in the team, you will want to create a new Droplet. Choose "Marketplace" then find the "Mastodon" option and select it.

Creating a Mastodon droplet

Scroll down and choose the $10/mo option. Choosing a smaller size could prevent Mastodon's assets from compiling due to running out of RAM.

Use this configuration:

  • Any datacenter region you want.
  • Select "Private networking", "IPv6", and "Monitoring"
  • Add your SSH key.
  • For the hostname, enter your server's full domain name.

Finally, click "Create droplet" and wait. Once the droplet is ready, you will need to point Cloudflare to it.

Step 2.1: Point Cloudflare to your droplet

Copy the IPv4 address of the droplet, then return to Clouflare, go to "DNS," and delete any entries containing A, AAAA, and CNAME. Add a new A record, enter @ as the name and paste your droplet's IP address in.

Adding an A record to Cloudflare

Find your droplet's IPv6 address by clicking into the droplet, then create a AAAA record in Cloudflare like before using the IPv6 address as the value.

Step 2.2: Media storage

When users upload pictures, they will need to be stored somewhere. You do not want them to be stored directly on the droplet. Apart from being a security risk, you will wake up one day to learn your server is offline due to storage running out. The solution is DigitalOcean Spaces.

The same way you created a droplet, create a space instead. Give it a unique name and use the default settings. You can put it in the same datacenter region as your droplet.

A new empty space on DigitalOcean

Media files will be hosted on a subdomain of your site, such as media.mysite.com. To start this process, first go under "Settings" in your space and choose "Enable CDN." Click the dropdown, then "Add new subdomain certificate." Within the modal, click "Bring your own certificate." We'll generate one from Cloudflare.

SSL certificate generated by Cloudflare

Back on Cloudflare, go to SSL/TLS > Origin Server > Create Certificate. Click Next, then copy the certificate text back into DigitalOcean.

Adding a certificate from Cloudflare

Once the CDN is enabled, you'll need to point media.mysite.com to it. Back on Cloudflare, go under DNS again and create a CNAME entry. Set the name to media and the value to the endpoint from your DigitalOcean space.

Cloudflare media settings

Next we need to generate API keys for Mastodon to connect to your media server. You'll use the keys when configuring Mastodon in step 2.3.

In DigitalOcean, click Manage > API from the left sidebar. Scroll down to the Spaces access keys section and click Generate New Key. The name is for your personal reference.

A DigitalOcean Spaces API key

Once created, save the values somewhere. The private key will disappear when you refresh the page. If you lose the private key, just delete it and create another key.

Step 2.3 Provision the server

From your terminal, run ssh root@my-droplet-ip replacing the actual IP address of your droplet. Type "yes" to continue. You will be greeted with a screen containing further instructions.

Mastodon boot screen

At the prompt, enter your domain name and follow the instructions. Use these answers:

  • Domain name: mysite.com
  • Do you want to store user-uploaded files on the cloud? No (DigitalOcean Spaces is not supported through this prompt, so we'll configure it after)
  • SMTP server: smtp.postmarkapp.com
  • SMTP port: 587
  • SMTP username: The username from step 1.2. It'll be in a format like 7b758fd4-9819-4b63-8841-00598d222f18
  • SMTP password: The password is identical to the username on Postmark.
  • SMTP authentication: plain
  • SMTP OpenSSL verify mode: none
  • E-mail address to send e-mails "from": Configure this how you want, eg My Site <noreply@mysite.com>
  • Send a test e-mail with this configuration right now? Yes

If all is well, an additional prompt will start up. Configure your admin account.

Mastodon first-time setup

If this succeeded, you should be able to access the site from your browser now. If not, you may have an error like Failed authorization procedure. mysite.com (http-01): urn:acme:error:unauthorized. In that case, something is wrong with your DNS. Try visiting your site in the browser and see if you can determine the issue.

Once the prompt is over, you'll still need to configure DigitalOcean Spaces for file uploads. Change to the Mastodon user with su - mastodon in the terminal, then run nano live/.env.production to edit the configuration file. At the bottom, add this configuration:

S3_ENABLED=true
S3_PROTOCOL=https
S3_BUCKET=spinster-dev
S3_ENDPOINT=https://nyc3.digitaloceanspaces.com
AWS_ACCESS_KEY_ID=91L7G1Z6HFS7S754BHE2
AWS_SECRET_ACCESS_KEY=uvrn655DcQ6L24rFYsX7DNsj31re22wTGXdbX1P73JP
S3_ALIAS_HOST=media.spinster.dev
Replace the values with the actual ones for your site

Replace the following values:

  • S3_BUCKET - find this in your DigitalOcean Space settings. It's the unique name you chose for the space.
  • S3_ENDPOINT - replace nyc3 with the region your Space is in.
  • AWS_ACCESS_KEY - this is the key you generated in step 2.2.
  • AWS_SECRET_ACCESS_KEY - the longer secret key from step 2.2.
  • S3_ALIAS_HOST - the domain name your media will be served at, as configured through Cloudflare in step 2.2.

Once done, press ctrl+X, Y, enter. Now reboot your server. Return to the root user by pressing ctrl+D, then type reboot.

Step 3: Updating the server

Both the base system and Mastodon version are outdated, so now is a good time to practice upgrading them. You'll have to do this periodically.

Shell into the droplet as the root user if you haven't already. Run this command to enable automatic updates:

dpkg-reconfigure unattended-upgrades

Ensure that <Yes> is highlighted then press enter. This will enable automatic security updates on the system, but won't update other packages.

Now lets update the base system packages. Run these commands in order:

apt update
apt upgrade

This will update the package index on the system then upgrade all packages. You'll want to do this periodically. You will probably get an error about conflicts in the GRUB file the first time you run this - just choose "keep the package maintainer's version."

Next we can update Mastodon itself. This will actually affect your end users. Before upgrading Mastodon, it's crucial you always make a database backup before upgrading.

I'm not playing around here. I destroyed my first Mastodon instance by trying to upgrade it and the upgrade failed, corrupting the database. Don't be lazy, back up the database.

First become the Mastodon user with su - mastodon. Now backup the database with this commmand:

pg_dump mastodon_production > db_latest.sql

Take a look at the Mastodon release notes and take note of the latest version. Read the upgrade notes - it's important.

Generally speaking, we'll upgrade Mastodon with these commands:

cd live
git fetch origin
git checkout v3.0.1
bundle install
yarn install
RAILS_ENV=production bundle exec rails assets:precompile
RAILS_ENV=production bundle exec rails db:migrate
Replace v3.0.1 with the latest Mastodon version

Finally, become the root user with ctrl+D the run reboot. You should be running the latest Mastodon version now.

Step 4: Securing the firewall

Cloudflare will hide your droplet's IP address from end users, but other servers you federate will be able to see IP in their system logs. Your server is still vulnerable to a DDoS attack against the direct IP.

To get around this, use a firewall to block all traffic that doesn't come from Cloudflare. This means users will be forced to interact with your server by its domain name, not its IP address.

Shell into the server as the root user. First you'll have to remove the firewall provisioned by the Mastodon one-click image:

apt purge -y iptables-persistent
rm /etc/iptables/rules.v4

Now we'll set up ufw instead. Enter these commands:

ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw enable

This will prevent the droplet from being accessed except by SSH. Give it a shot - you shouldn't be able to access it anymore from your web browser.

To allow Cloudflare traffic, we'll need to allow all Cloudflare IP ranges (which they helpfully document). Paste the following into the terminal:

ufw allow from 173.245.48.0/20 to any port 80
ufw allow from 103.21.244.0/22 to any port 80
ufw allow from 103.22.200.0/22 to any port 80
ufw allow from 103.31.4.0/22 to any port 80
ufw allow from 141.101.64.0/18 to any port 80
ufw allow from 108.162.192.0/18 to any port 80
ufw allow from 190.93.240.0/20 to any port 80
ufw allow from 188.114.96.0/20 to any port 80
ufw allow from 197.234.240.0/22 to any port 80
ufw allow from 198.41.128.0/17 to any port 80
ufw allow from 162.158.0.0/15 to any port 80
ufw allow from 104.16.0.0/12 to any port 80
ufw allow from 172.64.0.0/13 to any port 80
ufw allow from 131.0.72.0/22 to any port 80
ufw allow from 2400:cb00::/32 to any port 80
ufw allow from 2606:4700::/32 to any port 80
ufw allow from 2803:f800::/32 to any port 80
ufw allow from 2405:b500::/32 to any port 80
ufw allow from 2405:8100::/32 to any port 80
ufw allow from 2a06:98c0::/29 to any port 80
ufw allow from 2c0f:f248::/32 to any port 80
ufw allow from 173.245.48.0/20 to any port 443
ufw allow from 103.21.244.0/22 to any port 443
ufw allow from 103.22.200.0/22 to any port 443
ufw allow from 103.31.4.0/22 to any port 443
ufw allow from 141.101.64.0/18 to any port 443
ufw allow from 108.162.192.0/18 to any port 443
ufw allow from 190.93.240.0/20 to any port 443
ufw allow from 188.114.96.0/20 to any port 443
ufw allow from 197.234.240.0/22 to any port 443
ufw allow from 198.41.128.0/17 to any port 443
ufw allow from 162.158.0.0/15 to any port 443
ufw allow from 104.16.0.0/12 to any port 443
ufw allow from 172.64.0.0/13 to any port 443
ufw allow from 131.0.72.0/22 to any port 443
ufw allow from 2400:cb00::/32 to any port 443
ufw allow from 2606:4700::/32 to any port 443
ufw allow from 2803:f800::/32 to any port 443
ufw allow from 2405:b500::/32 to any port 443
ufw allow from 2405:8100::/32 to any port 443
ufw allow from 2a06:98c0::/29 to any port 443
ufw allow from 2c0f:f248::/32 to any port 443
echo "Done"

Now refresh your browser. If it's working, all is well!

Step 5: Automated backups

You can pay DigitalOcean a small fee to back up your server once per week. I suggest paying it. However, if you're really serious about this site, you should set up your own automated backups.

In order to have independence from your server provider, it's important to store backups in your physical control. I recommend purchasing a Raspberry Pi and configuring it to make backups for you. A really simple backup script will look like this:

DATE="$(date +%F_%T)"

ssh mastodon@1.1.1.1 "pg_dump mastodon_production > db_latest.sql"
scp mastodon@1.1.1.1:db_latest.sql /mnt/hdd/backups/db_$DATE.sql
Replace 1.1.1.1 with your server's IP address

You could save this script as a file like backup.sh then create a cron job with crontab -e adding a line like:

0 * * * * /home/pi/backup.sh

This will make the backup script run every hour. You can plug the Raspberry Pi directly into your wireless router and forget about it.

Periodically you'll have to prune the backups, or you can just add python-rotate-backups to the end of your backup script.