In followup to my last article I wanted to document all the changes I have made to run Mastodon on relatively minimal resources. With the changes below Mastodon averages about 1GB of RAM for running processes, suggesting a box with about 1.5GB would be sufficient.

I won’t touch on Postgres here since the topic is pretty well explored by other blogs and tools. As my other article says I am currently using a 1GB box to host postgres, but 512 would plausibly work.

Everything below assumes that your Mastodon instance followed the install from source guide, and runs using systemd on linux.

Puma

Mastodon runs its primary web service via Puma using a default configuration of two workers with five threads each. This configuration is able to handle a considerable amount of traffic, and frankly far more than a single user instance needs.

To reduce the memory required, Puma can be run in “non-clustered” mode with only one process (rather than the three run by default). To make this change an environmental variable must be inserted into /etc/systemd/system/mastodon-web.service.

11a12
> Environment="WEB_CONCURRENCY=0"

The environmental variable cannot be placed in .env.production as that is not loaded prior to Puma instantiation and will therefore be ignored. The change must be in the systemd configuration.

Once the change is made run systemctl daemon-reload and systemctl restart mastodon-web.

Sidekiq

Mastodon runs all of it’s background tasks through a job system called Sidekiq. By default this is configured with 25 workers, each with a connection to the database. Again, this is far more than a typical single-user instance needs, so we can reduce it. At the same time, we can reduce the DB connection pool as it should always match the worker count.

The precise value to use is difficult to guess, so trial and error is recommended. I am currently using ten workers, but a smaller value is likely fine. To make this change several environmental variables need to be changed in /etc/systemd/system/mastodon-sidekiq.service.

10c10
< Environment="DB_POOL=25"
---
> Environment="DB_POOL=10"
13c13
< ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25
---
> ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 10

I also tweaked the nice and oom_score_adjust values for Sidekiq as it should never be allowed to crash the system due to load. With the changes below (inserted into the same file as above) Sidekiq will run at a lower CPU priority and be the first process killed due to memory pressure.

50a51,53
> OOMScoreAdjust=1000
> Nice=10

Once the change is made run systemctl daemon-reload and systemctl restart mastodon-sidekiq.

To reduce memory sprawl, I also restart sidekiq hourly. The following line, when added to the root crontab, will work:

@hourly systemctl restart mastodon-sidekiq

nginx

For nginx, I enabled gzip_static in nginx. Mastodon pre-compresses all static assets but doesn’t use them by default so it is incumbent on the user to enable this setting.

Happily, the change is quite easy, just add the following to your /etc/nginx/sites-enabled/mastodon config.

46a51
>   gzip_static on;

Nightly Cleanup

Finally, I run the various cleanup tasks nightly using the script below. This script is stored at /home/mastodon/nightly.sh and is executed using the crontab also below. These scripts remove files from media storage and clean up the database.

Before using this script, consider the values that you feel are appropriate for deletion. Mine may be higher or lower than you would want. Also note that the days argument for preview_cards doesn’t appear to work, so I think it always deletes data after seven days.

#!/usr/bin/env bash

set -uexo pipefail

run_all() {
	export RAILS_ENV=production
	export PATH=/home/mastodon/.rbenv/shims:/home/mastodon/.rbenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

        date
        nice /home/mastodon/live/bin/tootctl media remove --days=30 --concurrency=1 --prune-profiles
        date
        nice /home/mastodon/live/bin/tootctl media remove --concurrency=1 --days=7
        date
        nice /home/mastodon/live/bin/tootctl preview_cards remove --concurrency=1 --days=7
        date
}

run_all | tee -a ~/nightly.log
0 10 * * * /home/mastodon/nightly.sh