Setting up Mastodon for development
I have been coding on my own Mastodon instance since 2017, the main thing I’m doing is customizing the styling. For this, it is a good idea to have a local development instance because redeploying (and rebuilding the assets) takes too long for a simple change like a different border color for some elements. In this post, I will show how I set up Mastodon for development.
but I tend to customize things and have found some pitfalls that are not mentioned in the official docs.
The official docs regarding development seem to have been deleted. Here’s the last snapshot from archive.org.
Let’s get right to it.
Prerequisites
Debian/Ubuntu dependencies
On Debian/Ubuntu based systems, there are a few dependencies that have to be installed using the package manager:
sudo apt install -y imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file git g++ libprotobuf-dev protobuf-compiler pkg-config gcc autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm5 libgdbm-dev libidn11-dev libicu-dev libjemalloc-dev
macOS Dependencies
The dependencies can installed using Homebrew:
brew install imagemagick libpq libxml2 libxslt protobuf autoconf bison gdbm ffmpeg icu4c libyaml libidn jemalloc
Errors when running bundle install
There might be errors when running bundle install
for the first time on macOS, because pg
and idn-ruby
fail to build.
This can be fixed using the following commands to install them (change the version numbers accordingly):
pg
- ` gem install pg – –with-pg-config=/opt/homebrew/Cellar/libpq/
/bin/pg_config`
- ` gem install pg – –with-pg-config=/opt/homebrew/Cellar/libpq/
libidn
gem install idn-ruby -- --with-idn-dir=/opt/homebrew/Cellar/libidn/<LIBIDN_VERSION>/
NodeJS
Mastodon needs NodeJS to run webpack and install (frontend) dependencies. I recommend using nvm to set up and manage NodeJS because it makes switching versions very easy.
After NodeJS is installed we need to install yarn
(an alternative to npm
).
This can be done by running:
npm i -g yarn
If you didn’t use nvm
to install NodeJS, you’ll probably run the command as root.
Mastodon Dependencies
To install the Mastodon NodeJS dependencies, run the following command from the Mastodon folder:
yarn install --pure-lockfile
Ruby
Mastodon is written in ruby so we’ll need it too.
Luckily there is something similar to nvm
that is able to manage ruby installations: rbenv.
After this tool is installed, you can run cat ./.ruby-version
from the Mastodon folder to get the currently needed ruby version which can then be installed with rbenv.
If you’re truly lazy, you can also run this as a oneliner (again from the Mastodon folder):
rbenv install $(cat ./.ruby-version)
This will use the value from the .ruby-version
file directly.
Bundler and Mastodon Dependencies
To be able to install Mastodon’s ruby dependencies, we first need to install bundler
, rails
and foreman
.
Those can be installed by running:
gem install rails bundler foreman
After bundler is installed, we can fetch and build the Mastodon dependencies:
bundle install --with development,test
The --with
argument will also download development (and test) dependencies.
Those are usually not needed when in production mode and thus not activated by default.
Docker
Mastodon runs on itself but needs a database and a redis instance to function properly. The official docs just state that you should simply install those services on your computer. However (by default) this leaves a database running on your system that you don’t need most of the time.
That’s why I’m using Docker to run the necessary services.
To install Docker you can simply follow the docs (Ubuntu) or download the app if you use macOS.
Postgres
After Docker is installed, we can start the database. But before that, we need to create a directory in which the data we save is persisted. This will allow us to keep all the data when the database is restarted.
Because I’m lazy, I just created a data
folder inside the Mastodon directory and added it to the .gitignore
(any file listed in there will be ignored by git).
Now when I open a shell inside the Mastodon folder, I can start the database like this:
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=changemepls --name=mastopg postgres:alpine
Here’s a quick explanation of what the arguments to:
run
tells docker that we want to run a given image-d
starts the service “detached” (ie. in the background)-p 5432:5432
sets the port we want to use-e POSTGRES_PASSWORD=changemepls
sets thePOSTGRES_PASSWORD
variable, this will be used by postgres itself--name=mastopg
sets the container’s name to mastopg. This way we can start/stop it by usingdocker {start,stop} mastodpg
postgres:alpine
is the image we want to run, alpine is a very minimal Linux distribution
Now there should be a running postgres visible when you run docker ps
Redis
The command to run redis is a lot shorter because we don’t need persistence and/or a password:
docker run --name mastoredis -p 6379:6379 -d redis
Again, with the name set to mastoredis
, we can start/stop the container by using docker {start,stop} mastoredis
.
You can validate that redis is running by running docker ps
again.
Configuring Mastodon
Now that the neccessary services are running, we need to tell Mastodon how to use them.
This can be easily done by creating the file .env.development
inside the Mastodon folder.
This file provides location and authentication information to Mastodon, it needs to have the following content:
REDIS_HOST=localhost
REDIS_PORT=6379
DB_HOST=localhost
DB_USER=postgres
DB_NAME=postgres
DB_PASS=changemepls
DB_PORT=5432
Since development
is the default environment when running Mastodon without setting RAILS_ENV
, we don’t need to do anything else to get Mastodon to use that file.
Initialization
The first time we run Mastodon, we’ll also need to create the initial database schema. Once the postgres container is running, this can be done by running the following command from the Mastodon folder:
bundle exec rails db:setup
This will output a ot of text which consists of all the commands necessary to initialize the database.
If you’ve just updated mastodon and already have an initialized database you can also run bundle exec rails db:migrate
to run only the difference between your setup and the currently necessary state.
Running Mastodon
Now that the initial setup is done, you can run Mastodon by opening a terminal in the Mastodon folder and running:
foreman start
This will start all Mastodon processes.
You can now go to http://localhost:3000
and log in as admin@localhost:3000
with the password mastodonadmin
.
Debugging Mastodon (web)
If you’re done setting up the first few users and start tinkering with stuff, you might want to set breakpoints to make debugging easier.
My solution to this is to use RubyMine. It works really well and does most things automatically.
To run all things appropriately, I usually comment out the first line in Procfile.dev
(starting with web: env PORT=
) so foreman start
doesn’t start the web worker.
RubyMine (at least in my case) automatically detects a Development: mastodon
run configuration that can be started in debug mode.
That way it’s even possible to set breakpoints (ie. evaluate expressions mid-execution) while rendering .haml
templates. 😱
Useful stuff to know
- When you register a new user, the registration mail will not be sent to the specified mail address. Instead the mail will be opened in a browser.
- This usually does not work when no browser is set as default.
- This means you can create accounts with invalid mail addresses just to test the design of the mails.
- You should not interact with any fediverse services running in production.
- Those usually only work with https endpoints and the origin server being
localhost
will eventually cause a connection attempt to the live server you were interacting with instead of your local machine - Fetching stuff (ie. pasting a remote profile link into the search bar to test the layout of remote profiles) should work (at least it does with my instance)
- Those usually only work with https endpoints and the origin server being
- Webpack will fail with a very non-helpful error message when dependencies are missing. If you didn’t change anything and webpack fails, running
yarn install
again will probably solve the problem- Same goes for bundler.
I hope this post was helpful. If you run into any problems, feel free to contact me by Mail or Mastodon.