Migrating the Pagecord Rails app from AWS to Hetzner

Today I migrated Pagecord from AWS to Hetzner because my $1000 free AWS credits are coming to an end. For some reason AWS want $70/mo for a t2.medium instance (2 vCPUs and 4GB RAM) with additional block storage, which is simply outrageous in 2025. I can have a Hetzner CAX31 for €14/month which gives me 8 vCPUs, 16GB RAM and 160GB storage. So that's what I bought. No brainer.

Uploaded image

Note: I use Hatchbox for server/Postgres/Redis management and deployment (it's a wonderful thing).

There were a few gotchas I encountered when doing this switch, so I thought I'd write them up here.
  1. The original Hetzner IP address my server was assigned was blocked by Sentry. I learned you can head over to the Primary IPs section in Hetzner and generate a new one, then assign it to your server. First though, you have to shut down the server, unassign the old IP, assign the new IP then restart the server. 
  2. Cloudflare caching caused havoc with Rails assets, Trix in particular (although this will have been a coincidence). In a slight panic I headed to Caching > Configuration and clicked Purge Everything. This sorted it out.
  3. Some custom domains stopped working 😱 Fortunately they were mine, not those of paying customers. I need to dig into this more but it seems to be to do with Cloudflare SSL settings (on the customer side). For now, I set it to "Flexible" (which probably isn't right, but it has got it working again).
  4. I am using Cloudfront for Rails assets so I ran an invalidation on Cloudfront to refresh this cache. I'm not sure this was 100% necessary but belt and braces and all that.
To do the actually switch, here's the process I followed:
  1. [Prep] Add existing custom domains to new app in Hatchbox (they have an API to do this)
  2. [Prep] Copy over ENV settings to new app in Hatchbox
  3. [Prep] Test a database restore and make sure the new app works (on temporary domain)
  4. Turn on maintenance mode on old server
  5. Turn off background jobs on old server
  6. Export database from old server
  7. Import database to new server (using `pg_restore`)
  8. Restart app for good measure
  9. Change DNS to point to new server
  10. Purge Cloudflare cache
  11. Run Cloudfront invalidation
A few minutes of downtime to export the DB and re-import, but I'll take that.