Articles · Infrastructure

2027-01-05 12 min EN / FR

Leaving Heroku, Vercel or Netlify for a server you control

Platform-as-a-service hosts are wonderful when you're starting: push your code and it's online. The pain shows up later: bills that grow with traffic or seats, limits on build minutes and bandwidth, restrictions on what you can run, and the sense that your application only works because of the platform's hidden magic.

Moving to a server you control is a normal step. It trades convenience for control and, often, lower and more predictable cost. It also means you take on responsibilities that the platform used to handle.

Step 1: Decide honestly whether to move

Good reasons:

  • The bill is rising faster than your business
  • You need something the platform doesn't allow (custom software, long-running processes, specific regions, private networking)
  • Data location or compliance requirements
  • You want to reduce dependence on one vendor's pricing and policies

Weak reasons: a general wish to "own everything," when nobody on the team is able or willing to operate servers. PaaS exists because operations is work. If you move, someone must do that work, whether it's you, a provider, or a managed service.

Step 2: List what the platform does for you

The platform gives you many things implicitly. Write them down, because you'll have to provide each one:

  • Build and deploy pipeline: how code goes from repository to running application
  • Runtime and process management: restarts, scaling, health checks
  • HTTPS certificates and renewal
  • Domains and routing
  • Environment variables and secrets
  • Databases and add-ons (Postgres, Redis, queues, search)
  • Scheduled jobs
  • Logs and metrics
  • Backups
  • Preview environments for pull requests
  • Edge features: CDN, caching, serverless functions, image optimisation, redirects and headers
  • Scaling during traffic peaks
  • Zero-downtime deploys and rollbacks

For each item, decide how you'll replace it, or whether you can do without.

Step 3: Spot the lock-in points

Where applications depend on the platform:

Heroku:

  • Buildpacks and the Procfile (portable in spirit, but your server needs equivalents)
  • Add-ons with proprietary configuration
  • Ephemeral filesystem assumptions
  • Scheduler and release-phase commands
  • Review apps and pipelines

Vercel / Netlify:

  • Serverless and edge functions with platform-specific APIs
  • Framework features tied to the platform (image optimisation, incremental rendering, middleware at the edge)
  • Form handling, identity and other built-in services
  • Redirect and header configuration formats
  • Build plugins

The more platform-specific features you use, the more rework to expect. Static sites move easily. Applications built around edge functions and platform services need a design decision: rewrite those parts, run an open-source equivalent, or keep that component where it is.

Step 4: Choose the target

  • A virtual server (VPS) at a European or other provider you pick: the simplest, cheapest, and most transparent. You run the application with a process manager or containers, plus a reverse proxy.
  • Containers with a lightweight orchestrator, or a self-hosted PaaS (open source tools exist that reproduce the push-to-deploy experience on your own server): a way to keep convenience while owning the infrastructure.
  • Managed Kubernetes: powerful, but heavy for a small team. Choose it for the needs it addresses, not for fashion.
  • Managed databases at a provider under your account, even if the application runs on your own server. This removes the hardest operations job.

Match the target to your team's skills. A single well-maintained server serves many businesses better than an elaborate cluster nobody understands.

Step 5: Rebuild the pieces

Deployment. Define how code reaches production: a CI pipeline (in your own repository host) that builds an image or an archive, copies it to the server, runs migrations and restarts the service. Include a rollback step: the previous version should be one command away.

Configuration and secrets. Export environment variables, and store them in a proper secrets setup on the server or in a vault, not in a file in the repository. Rotate secrets that were visible in the old platform's dashboard or logs if access was shared.

HTTPS. Use automatic certificate issuance and renewal, and monitor expiry.

Reverse proxy. Configure redirects, headers, compression, caching and rate limits that the platform used to apply for you.

Database. Plan the move carefully (see below), and set up backups immediately (see backups that actually restore).

Scheduled jobs. Recreate them with cron or a job scheduler, with alerts if they fail.

Logs and monitoring. Centralise logs, set up uptime checks and alerts on errors, disk, memory and certificate expiry. On a platform you didn't have to think about these. Now you do.

Security. Harden the server: restrict SSH to keys, a firewall, automatic security updates, no unnecessary open ports, minimal user accounts.

Need a PaaS exit plan?

We map what your platform does today, rebuild deploy and secrets on infrastructure under your accounts, and keep a rollback path.

Step 6: Move the database with care

The database is the part you can't get wrong.

  • Build the new database, same engine and compatible version.
  • Test a dump and restore, and time it.
  • Rehearse the cutover with a copy, verifying counts and application behaviour.
  • At cutover: put the application in maintenance mode, take the final dump, restore it, switch the connection, verify, and reopen. For large databases that can't tolerate downtime, use replication to keep the new one in sync before switching.
  • Keep the old database untouched until you're sure.

If your data is personal data, treat dumps and the test copies with the care described in GDPR and test environments.

Step 7: Switch traffic

Follow the DNS approach from switching hosting without downtime and migrating DNS without breaking email: lower TTLs ahead, test the new environment using a local hosts-file override, then change DNS and watch. Keep the old deployment running until traffic has fully moved, and keep a way back.

Check carefully for:

  • Webhooks and callbacks from third parties pointing at old URLs
  • OAuth redirect URLs registered with external providers
  • Allowlists on other services that restrict by IP (your new server has a different address)
  • Email-sending configuration, if the platform provided it
  • Cookies and sessions, which may log users out at cutover (warn them if it matters)

Step 8: After the move

  • Monitor errors, performance and costs for the first weeks
  • Test a backup restore and a rollback
  • Write the runbook: how to deploy, roll back, rotate secrets, restore, add a server
  • Make sure at least two people can operate it
  • Keep the old platform for a safe period, then export what you need and close it
  • Compare the real total cost, including your time, not only the invoice

The honest cost comparison

PaaS bills look high, but you're paying for operations. Self-hosting bills look low, but you're paying with time. Count:

  • Server and database costs
  • Backup storage and monitoring
  • Time to set up (once) and maintain (monthly)
  • Cost of incidents and on-call
  • Cost of being down while someone learns how to fix it

For small, simple projects, staying on the platform is often cheaper overall. For larger or steady-traffic applications, or ones that need special capabilities, moving usually pays off. A managed support arrangement can close the gap if you don't want to operate things yourself.

Common pitfalls

  • Forgetting the platform's implicit services (certificates, restarts, logs)
  • Assuming a local filesystem is persistent when the code expected the opposite, or the reverse
  • No monitoring, so outages are discovered by customers
  • A single server with no tested backups
  • Webhooks and OAuth redirects still pointing at the old host
  • IP allowlists not updated
  • Secrets copied into the repository during the move
  • Only one person understands the new setup
  • Cancelling the old platform before a full billing cycle of stable operation

Checklist

  • Reason to move confirmed, with a real cost comparison
  • Platform services and lock-in points listed
  • Target chosen to match team skills, accounts in our name
  • Deployment pipeline and rollback working
  • Secrets stored properly, shared ones rotated
  • HTTPS, reverse proxy, firewall and updates configured
  • Logs, monitoring and alerts live
  • Database move rehearsed, backups tested
  • External callbacks, redirects and allowlists updated
  • Runbook written, two people able to operate
  • Old platform kept briefly, then closed

Related

From platform magic to something you can run

If you're outgrowing Heroku, Vercel or Netlify and want the move under your accounts, write us.