I recently had to migrate the main Libravatar server to a new virtual machine. In order to minimize risk and downtime, I decided to write a migration plan ahead of time.
I am sharing this plan here in case it gives any ideas to others who have to go through a similar process.
Prepare DNS
- Change the TTL on the DNS entries for
libravatar.org
andlibravatar.com
(i.e. bareA
andAAAA
records) to 3600 seconds. - Remove the mirrors I don't control from the DNS load balancer (
cdn
andseccdn
). - Remove the main server from
cdn
andseccdn
in DNS.
Preparing the new server
- Setup the new server.
- Copy the database from the old site and restore it.
- Copy
/var/lib/libravatar
from the old site. Hack my local
/etc/hosts
file to point to the new server's IP address:xxx.xxx.xxx.xxx www.libravatar.org stats.libravatar.org cdn.libravatar.org
Test all functionality on the new site.
Preparing the old server
Prepare a static "under migration" Apache config in
/etc/apache2/sites-enabled.static/default.conf
:<VirtualHost *:80> RewriteEngine On RewriteRule ^ https://www.libravatar.org [redirect=301,last] </VirtualHost> <VirtualHost *:443> SSLEngine on SSLCertificateFile /etc/libravatar/www.crt SSLCertificateKeyFile /etc/libravatar/www.pem SSLCertificateChainFile /etc/libravatar/www-chain.pem RewriteEngine On RewriteRule ^ /var/www/html/migration.html [last] <Directory /var/www/html> Allow from all Options -Indexes </Directory> </VirtualHost>
Put this static file in /var/www/html/migration.html:
<html> <body> <p>We are migrating to a new server. See you soon!</p> <p>- <a href="https://identi.ca/libravatar">@libravatar</a></p> </body> </html>
Enable the rewrite module:
a2enmod rewrite
Prepare an Apache config proxying to the new server in
/etc/apache2/sites-enabled.proxy/default.conf
:<VirtualHost *:80> RewriteEngine On RewriteRule ^ https://www.libravatar.org [redirect=301,last] </VirtualHost> <VirtualHost *:443> SSLEngine on SSLCertificateFile /etc/libravatar/www.crt SSLCertificateKeyFile /etc/libravatar/www.pem SSLCertificateChainFile /etc/libravatar/www-chain.pem SSLProxyEngine on ProxyPass / https://www.libravatar.org/ ProxyPassReverse / https://www.libravatar.org/ </VirtualHost>
Enable the proxy-related modules for Apache:
a2enmod proxy a2enmod proxy_connect a2enmod proxy_http
Migrating servers
Enable the static file config on the old server (disabling the Django app):
cd /etc/apache2/ mv sites-enabled sites-enabled.django mv sites-enabled.static sites-enabled apache2ctl configtest systemctl restart apache2.service
Disable pgbouncer to ensure that Django cannot access postgres anymore:
systemctl stop pgbouncer.service
Copy the database from the old server and restore it on the new server making sure it's in the UTF8 encoding:
dropdb libravatar createdb -O djangouser -E utf8 libravatar pg_restore -d libravatar libravatar20180812.pg
Copy
/var/lib/libravatar
from the old server to the new one.On the new server:
chmod a+w /var/lib/libravatar/avatar rm -rf /var/lib/libravatar/avatar/* chmod a+w /var/lib/libravatar/user rm -rf /var/lib/libravatar/user/*
From laptop:
rsync -a -H -v old.libravatar.org:/var/lib/libravatar/avatar . rsync -a -H -v old.libravatar.org:/var/lib/libravatar/user . rsync -a -H -v avatar/* new.libravatar.org:/var/lib/libravatar/avatar/ rsync -a -H -v user/* new.libravatar.org:/var/lib/libravatar/user/
On the new server:
chmod go-w /var/lib/libravatar/avatar chmod go-w /var/lib/libravatar/user chown -R root:root /var/lib/libravatar/avatar/* /var/lib/libravatar/user/*
Disable mirror sync
- Log into each mirror and comment out the update cron jobs in
/etc/cron.d/libravatar-slave
. - Make sure mirrors are no longer able to connect to the old server by moving
/var/lib/libravatar/master/.ssh/authorized_keys
to the new server and removing it from the old server.
Testing the main site
Hack my local
/etc/hosts
file to point to the new server's IPv4 address:xxx.xxx.xxx.xxx www.libravatar.org stats.libravatar.org cdn.libravatar.org seccdn.libravatar.org
Test all functionality on the new site.
- Do a basic version of the previous test using IPv6.
If testing is successful, update DNS A and AAAA records (
libravatar.org
andlibravatar.com
) to point to the new server with a short TTL (in case we need to revert).Enable the proxy config on the old server.
cd /etc/apache2/ mv sites-enabled sites-enabled.static mv sites-enabled.proxy/ sites-enabled apache2ctl configtest systemctl restart apache2.service
Hack my local
/etc/hosts
file to point to the old server's IP address.- Test basic functionality going through the proxy.
- Remove local
/etc/hosts
hacks.
Re-enable mirror sync
- Build a new
libravatar-slave
package with an updatedknown_hosts
file for the new server. - Log into each server I control and update that package.
Test the connection to the master (hacking
/etc/hosts
on the mirror if needed):sudo -u libravatar-slave ssh libravatar-master@0.cdn.libravatar.org
Uncomment the sync cron jobs in
/etc/cron.d/libravatar-slave
.- An hour later, make sure that new images are copied over and that the TLS certs are still working.
- Remove
/etc/hosts
hacks from all mirrors.
Post migration steps
- Tweet and dent about the fact that the migration was successful.
Send a test email to the support address included in the tweet/dent.
Take a backup of config files and data on the old server in case I forgot to copy something to the new one.
Get in touch with mirror owners to tell them to update
libravatar-slave
package and test ssh configuration.Add third-party controlled mirrors back to the DNS load-balancer once they are up to date.
A few days later, change the TTL for the main site back to 43200 seconds.
- A week later, kill the proxy on the old server by shutting it down.