{"slug": "i-moved-my-whole-server-off-easypanel-with-one-command-and-five-things-broke", "title": "I moved my whole server off Easypanel with one command, and five things broke", "summary": "A developer moved a production Hetzner server running 14 projects and 57 services from Easypanel to Tugport, a self-hosted deploy panel they built, using a single `tugport migrate easypanel` command. The migration completed with 54 services running and surfaced five bugs, including unexpanded Easypanel environment variables, imported wildcard health checks, and database health checks that timed out under load; the first three were fixed and released the next day. The developer also pinned all database images after a floating `mysql:9` tag silently upgraded MySQL and took a blog down for three minutes.", "body_md": "On October 24 I moved my main server from Easypanel to [Tugport](https://tugport.com), the deploy panel I've been building. It's the Hetzner box that runs most of what I make: Telegram bots, my Forgejo and its CI runner, two Ghost blogs (including this one), a game server, and the Postgres, MySQL and Mongo databases behind all of them. That's 14 projects and 57 services, and the move was one command. Five things broke along the way, and I'll go through each of them below.\n\nTugport is a single Rust binary that runs next to Docker on a server you own. It builds every git push, switches traffic once the new version is healthy, serves it over HTTPS, and keeps logs, charts and backups. AI agents get their own scoped API keys instead of root. It's MIT-licensed, and moving off Easypanel or Coolify is built in, which is the part this post is about.\n\nFirst the dry run, which changes nothing and never prints secrets:\n\n```\ntugport migrate easypanel --dry-run\n```\n\nIt prints every service, how it maps, what needs attention and what won't move. Then the real thing:\n\n```\ntugport migrate easypanel\n```\n\nHere's what happens under the hood, in order:\n\nEvery step goes into a journal, so a rerun resumes where the last one stopped, and `tugport migrate rollback` undoes it in reverse. Volumes and bind mounts stay where they are, so no data is copied, and certificates are imported rather than re-issued.\n\nWhen it finished, 54 services were running on Tugport. The other three had already been scaled to zero in Easypanel, and they came over stopped.\n\nThis was the first production server the migrator moved, and it found five bugs:\n\n`$(PROJECT_NAME)` and `$(PRIMARY_DOMAIN)` in their environment, and Tugport passed them through as text. I set them by hand that night, and the migrator now fills them in.`*.easypanel.host` address. Tugport imported those too, so a bot with no web server got a health check waiting on port 80 forever. The migrator skips them now.\nThe first three were fixed and released the next day.\n\nThe next night the panel lit up with \"unhealthy\" databases. Load on the server hit 99: four CI jobs were running at once, and Voicy was doing its first build on Tugport, which took about 20 minutes. The database health checks ran every 5 seconds with a 5-second timeout, so they timed out under that load. Nothing restarted, because health checks only mark a service, but I didn't love seeing a wall of red. Databases are now checked every 30 seconds with a 15-second timeout.\n\nThen I made my own mistake. Redeploying the databases to pick up the new health checks pulled the floating `mysql:9` tag, and this blog's MySQL quietly went from 9.7.0 to 9.7.4. The blog was down for about three minutes while it upgraded itself. It upgraded cleanly, but now every database image on the server is pinned to an exact version, and the migrator pins moved databases to the exact image they ran under Easypanel. Pin your database images.\n\nOnce everything had run on Tugport for a day, I removed Easypanel for good: 63 swarm services, its networks and its stopped containers. Pruning unused images and build cache freed 21 GB of disk.\n\nEasypanel's backup schedules don't move, so I set up new ones in Tugport: every night, restic backs up 12 databases, 15 volumes and a handful of host folders to S3 Glacier Deep Archive, Amazon's cheapest storage class. The first runs all passed, and so did the test restores.\n\nDeploys now come straight from my Forgejo. Tugport added signed webhooks to 24 repositories, and it honors watch paths, so a service in a monorepo only rebuilds when its own files change. Putting `[skip deploy]` in a commit message skips the deploy.\n\nThe migrator doesn't move everything, and the dry run lists what it leaves behind: backup schedules, users, notification channels, Easypanel's Box and WordPress services, wildcard domains, and hand-written Traefik routes. If your setup leans on those, plan for them.\n\nTugport is also young. It has a handful of GitHub stars, and most of the bugs I've fixed so far were found on my own server. Since the move I've shipped twenty releases, and many of them fix things that only a real server full of services could find. That's the honest state of it.\n\nIf you run Easypanel or Coolify, install Tugport and run `tugport migrate easypanel --dry-run` (or `tugport migrate coolify --dry-run`). It reads the old panel and prints the plan without changing anything. The [migration guide](https://tugport.com/docs/migration/) covers what maps to what, and if you'd rather hand the whole move to an AI agent, point it at [tugport.com/agents.md](https://tugport.com/agents.md). The source is on [GitHub](https://github.com/backmeupplz/tugport).", "url": "https://wpnews.pro/news/i-moved-my-whole-server-off-easypanel-with-one-command-and-five-things-broke", "canonical_source": "https://dev.to/backmeupplz/i-moved-my-whole-server-off-easypanel-with-one-command-and-five-things-broke-1o62", "published_at": "2026-10-27 16:00:07+00:00", "updated_at": "2026-10-27 16:12:16.032275+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-tools"], "entities": ["Tugport", "Easypanel", "Hetzner", "Forgejo", "Ghost", "Coolify", "Amazon S3 Glacier Deep Archive", "MySQL"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/i-moved-my-whole-server-off-easypanel-with-one-command-and-five-things-broke", "markdown": "https://wpnews.pro/news/i-moved-my-whole-server-off-easypanel-with-one-command-and-five-things-broke.md", "text": "https://wpnews.pro/news/i-moved-my-whole-server-off-easypanel-with-one-command-and-five-things-broke.txt", "jsonld": "https://wpnews.pro/news/i-moved-my-whole-server-off-easypanel-with-one-command-and-five-things-broke.jsonld"}}