Migrating Mastodon To A New Server Notes v0.1

Good Day Readers!

This was supposed to be on my main blog (synfinner.ru), however, things broke and now it's on here ;).

I recently switched to a different hosting provider for my Mastodon instance (dreadsec.social). There is an 'official' guide for doing this (https://docs.joinmastodon.org/admin/migrating/), however, I also wanted to share my notes.

Let's begin!


These notes are separated in two sections, Prepping The Old Server and Configuring The New Server. It is worth noting that I've setup dreadsec.social to use an S3 service for images. This leads to us not needing to backup the /live/public/system data.

Highlevel steps:

Prepping The Old Server

Let's turn off the running services.

Stop the running mastodon services: systemctl stop mastodon-*.service Stop NGINX (optional): service nginx stop

Backup Let's Encrypt Certificates

Archive the certificates stored in /etc/letsencrypt/archive

sudo tar -chvzf certs.tar.gz /etc/letsencrypt/archive/dreadsec.social /etc/letsencrypt/renewal/dreadsec.social.conf

Copy the cert archive to synfinner's laptop.

scp wtfjoey@dreadsec.social:~/certs.tar.gz .

Backup Postgres

We 100% want to backup the Mastodon postgres DB.

su - mastodon
pg_dump -Fc mastodon -f backup.dump
cp backup.dump /home/wtfjoey/backup.dump

Copy the dump to synfinner's laptop.

scp wtfjoey@dreadsec.social:~/backup.dump .

Copy .env.production file

Nothing fancy here, we just did a cat .env.production and copied the text.

At this point, pause the old server.

Configuring The New Server

The first step we have here is to ensure that we've put our backups onto the new server.

scp certs.tar.gz backup.dump wtfjoey@dreadsec.social:~/

Setup Requirements

curl -sL https://deb.nodesource.com/setup_12.x | bash -
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
apt update
apt install -y \
  imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file git-core \
  g++ libprotobuf-dev protobuf-compiler pkg-config nodejs gcc autoconf \
  bison build-essential libssl-dev libyaml-dev libreadline6-dev \
  zlib1g-dev libncurses5-dev libffi-dev libgdbm5 libgdbm-dev \
  nginx redis-server redis-tools postgresql postgresql-contrib \
  certbot python-certbot-nginx yarn libidn11-dev libicu-dev libjemalloc-dev

Install Ruby under the mastodon user:

adduser --disabled-login mastodon
su - mastodon

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec bash
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 2.6.6 --verbose
rbenv global 2.6.6
gem install bundler --no-document
exit

Setup the postgres Mastodon User.

sudo -u postgres psql

CREATE USER mastodon CREATEDB;
\q

Restore Postgres

su - mastodon

Create new empty DB

createdb -T template0 mastodon

Restore the dump:

pg_restore -U mastodon -n public --no-owner --role=mastodon \
  -d mastodon backup.dump

Restore Let's Encrypt Certificates

cd /
sudo tar -xvf ~/certs.tar.gz

While we've extracted the contents, we need to repair the symlinks necessary for Let's Encrypt.

mkdir -p /etc/letsencrypt/live/dreadsec.social
sudo ln -s /etc/letsencrypt/archive/dreadsec.social/cert4.pem /etc/letsencrypt/live/dreadsec.social/cert.pem
sudo ln -s /etc/letsencrypt/archive/dreadsec.social/chain4.pem /etc/letsencrypt/live/dreadsec.social/chain.pem
sudo ln -s /etc/letsencrypt/archive/dreadsec.social/fullchain4.pem /etc/letsencrypt/live/dreadsec.social/fullchain.pem
sudo ln -s /etc/letsencrypt/archive/dreadsec.social/privkey4.pem /etc/letsencrypt/live/dreadsec.social/privkey.pem

Install and Configure Mastodon

su - mastodon

Clone and install:

git clone https://github.com/tootsuite/mastodon.git live && cd live
git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)

bundle config deployment 'true'
bundle config without 'development test'
bundle install -j$(getconf _NPROCESSORS_ONLN)
yarn install --pure-lockfile

Copy over our .env.production file to Mastodon's /live directory

cp .env.production /home/mastodon/live/
chown mastodon.mastodon /home/mastodon/live/.env.production

Precompile assets and rebuild user feeds:

RAILS_ENV=production bundle exec rails assets:precompile
RAILS_ENV=production ./bin/tootctl feeds build

Copy over the nginx config

cp /home/mastodon/live/dist/nginx.conf /etc/nginx/sites-available/mastodon
ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon

Be sure to set the site settings to the proper host name and uncomment the ssl key files.

Copy systemd service configs and start the service!

cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/
systemctl daemon-reload
systemctl start mastodon-web mastodon-sidekiq mastodon-streaming
systemctl enable mastodon-*