Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save groundcat/609941314d817f377758b3ea7f2f248c to your computer and use it in GitHub Desktop.

Select an option

Save groundcat/609941314d817f377758b3ea7f2f248c to your computer and use it in GitHub Desktop.

Migrating a glitch-soc Server to a New Machine

This guide walks through moving an existing glitch-soc instance from one server to another with minimal data loss. Expect some downtime during the migration window.

Note: This guide assumes Ubuntu 24.04 or Debian 13 on both machines. Adjust commands as needed for other setups.


Overview

At a high level, the process is:

  1. Prepare the new server (install dependencies, set up services)
  2. Stop glitch-soc on the old server
  3. Transfer the database, media files, config, and Redis data
  4. Start glitch-soc on the new server
  5. Rebuild feeds and search indices
  6. Cut over DNS

Before You Begin

A day before migrating, set your domain's DNS TTL to 30–60 minutes. This ensures DNS propagates quickly once you point it to the new server's IP.

Optionally, edit ~/live/public/500.html on the old server to show a maintenance message to users during the migration window.


Part 1: Prepare the New Server

Set up the new server from scratch, but do not run mastodon:setup and only leave the PostgreSQL service running at the end. Follow the steps below.

System Repositories

apt install -y curl wget gnupg lsb-release ca-certificates

Node.js:

curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list

PostgreSQL:

wget -O /usr/share/keyrings/postgresql.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc
echo "deb [signed-by=/usr/share/keyrings/postgresql.asc] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/postgresql.list

System Packages

apt update
apt install -y \
  imagemagick ffmpeg libvips-tools libpq-dev libxslt1-dev file git \
  protobuf-compiler pkg-config autoconf bison build-essential \
  libssl-dev libyaml-dev libreadline-dev zlib1g-dev libffi-dev \
  libgdbm-dev nginx nodejs redis-server postgresql certbot \
  python3-certbot-nginx libidn-dev libicu-dev libjemalloc-dev

Enable Yarn via corepack:

corepack enable

Create the mastodon User

adduser --disabled-password mastodon

Set up PostgreSQL

Optional performance tuning: Use pgTune to generate a config for /etc/postgresql/18/main/postgresql.conf, selecting "Web application" as the DB type.

Create the database user. If your old server used a password for the mastodon PostgreSQL user, set the same password here for convenience:

sudo -u postgres psql
ALTER USER mastodon WITH PASSWORD 'YOUR_PASSWORD';
\q

Then create an empty database using template0 (required for a clean pg_restore):

createdb -T template0 mastodon_production

Check out glitch-soc

Switch to the mastodon user:

su - mastodon

Clone the glitch-soc repository:

git clone https://github.com/glitch-soc/mastodon.git live && cd live
git checkout main

Install Ruby

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install

Install Dependencies

bundle config deployment 'true'
bundle config without 'development test'
bundle install
yarn install

Note: Do not run mastodon:setup. The database and config will come from the old server.

Switch back to root:

exit

Stop Redis on the New Server

Before copying the Redis data over, make sure Redis is not running on the new machine so it doesn't overwrite the incoming dump:

systemctl stop redis-server.service

Part 2: Stop the Old Server

On the old server, stop all glitch-soc services:

systemctl stop 'mastodon-*.service'

Part 3: Transfer Data

What Needs to Be Copied

Critical — the migration will not work without these:

  • PostgreSQL database dump
  • ~/live/public/system/ — user-uploaded media (skip if using S3)
  • ~/live/.env.production — server config and secrets
  • Redis database at /var/lib/redis/ — unprocessed Sidekiq jobs

Recommended — copy for convenience:

  • nginx config: /etc/nginx/sites-available/mastodon
  • systemd service files: /etc/systemd/system/mastodon-*.service
  • SSL certificates (see the Certbot section below)
  • PgBouncer config: /etc/pgbouncer (if applicable)

Dump and Restore PostgreSQL

Note: pg_dump and pg_restore can take hours for large databases (e.g. a ~15GB dump). Consider temporarily tuning Postgres performance before starting.

On the old server, as the mastodon user:

pg_dump -Fc mastodon_production -f backup.dump

Copy the dump to the new server:

rsync -avz backup.dump mastodon@example.com:~/backup.dump

On the new server, as the mastodon user, restore the dump (replace # in -j# with your CPU count):

pg_restore -Fc -j# -U mastodon -n public --no-owner --role=mastodon \
  -d mastodon_production backup.dump

If the PostgreSQL username differs between servers, update both -U and --role to match the new server's username.

Copy Media Files

On the old server, as the mastodon user:

rsync -avz ~/live/public/system/ mastodon@example.com:~/live/public/system/

Re-run this command if any files change on the old server before DNS is cut over.

Copy the Configuration File

rsync -avz ~/live/.env.production mastodon@example.com:~/live/.env.production

Copy the Redis Database

On the old server, as root, save and stop Redis, then copy the data:

redis-cli SAVE
systemctl stop redis-server.service
rsync -avz /var/lib/redis/ root@example.com:/var/lib/redis

SSL Certificates (Certbot)

Do not copy the entire /etc/letsencrypt/live/ folder — Certbot will complain when you later try to renew. Instead, copy only the certificate files referenced by ssl_certificate and ssl_certificate_key in your nginx config to a temporary directory on the new server, and update the nginx config paths to match. Re-running Certbot later will overwrite them cleanly:

certbot certonly --nginx -d example.com

Part 4: Configure and Start the New Server

nginx

Copy the nginx config from the Mastodon repo or from your old server:

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

Edit /etc/nginx/sites-available/mastodon:

  1. Replace example.com with your domain
  2. Uncomment the SSL certificate lines:
ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Allow nginx to access asset files:

chmod o+x /home/mastodon

Pre-compile Assets

As the mastodon user:

cd ~/live
RAILS_ENV=production bundle exec rails assets:precompile

Note: glitch-soc ships with two front-end flavours, so this step takes more time and resources than on mainline Mastodon.

Switch back to root when done:

exit

Set up systemd Services

Copy the service files (or reuse those from your old server):

cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/

Verify usernames and paths are correct:

$EDITOR /etc/systemd/system/mastodon-*.service

Start everything:

systemctl daemon-reload
systemctl start redis-server
systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming
systemctl restart nginx

Part 5: Post-Migration Steps

Rebuild Home Feeds

This can take a long time depending on the number of users:

RAILS_ENV=production ./bin/tootctl feeds build

Rebuild Elasticsearch Indices (if applicable)

Skip this if you don't use Elasticsearch:

RAILS_ENV=production ./bin/tootctl search deploy

Update DNS

Point your domain's DNS records to the new server's IP address. You can monitor propagation progress at whatsmydns.net. To test the new server before DNS fully propagates, edit your local /etc/hosts to point your domain to the new IP.


Checklist

  • DNS TTL lowered a day in advance
  • Maintenance page shown on old server
  • New server fully provisioned (no mastodon:setup run)
  • PostgreSQL dumped and restored
  • Media files synced
  • .env.production copied
  • Redis database copied
  • nginx configured and SSL in place
  • Assets precompiled
  • systemd services started
  • Home feeds rebuilt
  • Elasticsearch indices rebuilt (if applicable)
  • DNS updated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment