Pagecord originated in AWS London simply because I had a grand’s worth of free credits. Once they'd been gobbled up, I moved it over to Hetzner where I got better value and I didn't have to rely on the big tech leviathan.
I’ve been really happy with how things have worked out, but I've just moved Pagecord to its third home in three years. I thought I'd write about why, and how, I did the move.
Pagecord is still hosted by Hetzner, but it's now running in the Falkenstein data centre (DC).
Why move?
The move was driven by a migration to a new managed database (DB) system. Until now I’ve been managing Postgres myself, running it on the same server as the application. This might sound unusual in 2026, but this approach wasn't as cavalier as it might sound. It was pretty resilient because I had set up WAL replication to Cloudflare R2 to provide point-in-time backups, plus there was a tested restore process should the proverbial ever hit the fan.
This DIY approach was very cost-effective and it offered great performance, but since Pagecord has started turning a small profit (I still don't take any payment, btw), I decided to reinvest these funds into the infrastructure, to make it more resilient and less hassle for me. The truth is Pagecord’s server was turning into something of a pet, which is not good. As any good DevOps engineer will tell you, you want cattle, not pets.
The primary pet problem was the locally managed database, so I've now removed all that complexity by switching to a fully managed set up. Managed databases are more expensive, but you trade that cost for the peace of mind that someone else will look after it for you.
One downside to using a managed database is that they can introduce undesirable latency to a web application if you’re not locating your app in the same DC as the managed DB. With the database on the same server as the application, queries run over a Unix socket in around 0.2ms – super fast. Given that a web page can easily run to a dozen or more queries, keeping the app and database in the same DC can make a big difference. Hetzner don't offer a managed DB option, but I discovered Ubicloud in my research. They're a new kid on the managed DB block, but they offer good value for money, have a slick product, and they support Hetzner as a provider! Sold.
The sticking point was that Ubicloud only support Hetzner's Falkenstein DC, not Nuremberg, so to get that sweet low latency I'd need to move the application server as well. This was actually a good opportunity to spin up a new app server in Falkenstein and test the cattle approach. I’m glad I did, as it exposed a few issues with the current set up.
How I approached the switch
The first move was to spin up a Ubicloud DB in Falkenstein ("standard-2"), as well as a new application server in Falkenstein. This was super easy, thanks to Ubicloud and Hatchbox (the fantastic deployment platform I use).
I pointed the new application instance back to the Nuremberg database, then used DNS to direct a test blog to this instance. I ran some tests and the latency between Nuremberg to Falkenstein was only around 3.5ms – over 15x slower than running on the same machine, but still low enough to allow me to run the DB in Nuremberg and the application in Falkenstein for a short while.
I scheduled a maintenance period and made the database switch. This made all the blogs unavailable for a short period (😱) but visitors got a helpful maintenance page – it's not like the lights went out entirely.
It only took a couple of minutes to dump the DB from Nuremberg and reload it into the Ubicloud Falkenstein DB, then I brought the blogs back online. Despite the increased latency, there was very little noticeable difference in performance since there's so much caching going on between a browser and a Pagecord blog.
Still, I wanted to reduce this latency to a minimum and run the DB and the app in the same DC, so once I was happy that everything was running in Ubicloud without a hitch (it's great, and arguably I have too much DB power now!), I looked at switching over the application from Nuremberg to Falkenstein. This is rather trivial technically – just point the Pagecord floating IP from one DC to the other – however most paying customers also have custom domains, and with this came a few issues.
The custom domain problem
Most customers point their DNS to proxy.pagecord.com so a server change is transparent. Those that can't do this point their DNS to a floating IP address – again, a transparent change. However, there were a couple of customers who had DNS set up in a different way, which meant that I couldn't switch them over without their blogs going offline.
These customers had put their own CDN or proxy (Bunny, Cloudflare) in front of their custom domain, and aspects of their specific configuration meant that the HTTP challenge required to generate a TLS certificate couldn't reach the Pagecord server that generates the certs! I could have worked around this by copying certs over from the old server, but that would have put the new server in pet territory again.
Instead, I emailed the customers and asked them to tweak their DNS set up such that these challenge requests would reach Pagecord correctly. They did this quickly (thank you!) which allowed me to redirect all traffic to the new server.
As far as I can tell, things have been running without a hitch for a few days now!
A more resilient Pagecord
Pagecord is now running happily on a new application cluster in Falkenstein, using a managed database sitting right alongside it which is managed by Ubicloud. The app/DB latency is only 0.8ms.
The server is more cattle than pet, and if/when I need to spin up more servers, or move entirely, it should be much more seamless.
The cost has increased (for both the managed database, and a more expensive app server – Hetzner costs get hiked recently), but Pagecord is still profitable and – crucially – more resilient than it's ever been.
I can rest a little easier knowing the database is somebody else's pet now.