- App
- Config
- Redis/Valkey
- Media
- Postgres
Just move over the app directory or re-clone it from a relevant git repo. Mastodon install instructions apply. It's best to set up a test instance first (on a different subdomain!), make sure everything works, then either clone the configs for production or just clobber the data and change the domain.
Use the same version to avoid doing a move and upgrade at the same time, unless you must. If you do upgrade at the same time, standard Mastodon upgrade instructions apply (database migrations etc) after the DB is moved over.
Copy over .env.production. This has important encryption/session keys.
Everything else is mostly based on what was customized, things to remember to check:
- Worker counts for web frontend
- Postgres max connections
- Nginx frontend configs
- Paths in systemd unit files (
ReadWritePaths=if you store media in a non-default directory)
Left as an exercise for the reader. Remember to deal with TLS certs etc. You might want to just copy the old ones over first, so the new and old web servers can be brought up in parallel and then you can just switch over DNS or IPs. (Do NOT run both instances at once though! The web server is okay, not the actual Mastodon app).
Just bring down the old server, copy over /var/lib/redis/dump.rdb, bring up the new server. Easy.
Rsync the attachments first. You want to copy over at least:
media/accounts
media/cache/custom_emojis
media/custom_emojis
media/media_attachments
media/site_uploads
Before the switchover, you should run one second-to-last rsync. Then after bringing down the old server, run one final rsync, which should be fast if the FS caches are warm.
Standard DB move/restore procedures apply. If you are using pg_dump, be aware that it is slow. Restoring a 50GB database took ~2 hours for me, excluding views.
At the end of the restore, the dump will have these commands:
REFRESH MATERIALIZED VIEW public.account_summaries;
REFRESH MATERIALIZED VIEW public.global_follow_recommendations;
REFRESH MATERIALIZED VIEW public.instances;
The first two take forever. You can see that it is doing those when the postgres worker says REFRESH in its command line (ps aux | grep REFRESH). When it gets there, it is safe to interrupt the restore.
Then, manually run REFRESH MATERIALIZED VIEW public.instances;. That one will run quickly, and is important. The other two are refreshed periodically by Mastodon in the background anyway, so you can just ignore them. It will just break follow recommendations until the first refresh.
Unless you moved the whole attachments/profile icons/headers caches, you need to clear those out in the DB so they can be refetched.
For accounts:
UPDATE accounts
SET avatar_file_name = NULL, avatar_content_type = NULL, avatar_file_size = NULL, avatar_updated_at = NULL
WHERE COALESCE(avatar_remote_url, '') != '' AND avatar_file_name IS NOT NULL;
UPDATE accounts
SET header_file_name = NULL, header_content_type = NULL, header_file_size = NULL, header_updated_at = NULL
WHERE COALESCE(header_remote_url, '') != '' AND header_file_name IS NOT NULL;For attachments:
UPDATE media_attachments
SET file_file_name=NULL, file_content_type=NULL, file_file_size=NULL, file_updated_at=NULL,
thumbnail_file_name=NULL, thumbnail_content_type=NULL, thumbnail_file_size=NULL, thumbnail_updated_at=NULL
WHERE COALESCE(remote_url, '') != '' AND file_file_name IS NOT NULL;For preview cards:
UPDATE preview_cards
SET image_file_name = NULL, image_content_type = NULL, image_file_size = NULL, image_updated_at = NULL
WHERE image_file_name IS NOT NULL;Note that preview cards are not refetched unless the link is posted again more than 2 weeks after the last fetch. So ideally you should transfer the media/cache/preview_cards directory instead of clearing the cache out as above.
Accounts will not be refetched automatically unless the profiles are explicitly searched for. After the move, run this command to repopulate all account data:
RAILS_ENV=production bin/tootctl accounts refresh --concurrency 40 --all--concurrency 40 is a good idea to make it not take forever, but keep in mind this uses postgres DB connection slots. Make sure to bump max_connections.
It is also a good idea to prime the cache with recent remote media:
RAILS_ENV=production bin/tootctl media refresh --concurrency 40 --days 7TODO: What's going on with the custom_emojis? Looks like those are problematic, best always copy those over and not clear them out. If you must, run tootctl emoji purge --remote-only after the move.