---
title: Migrating from Zeabur to Zenavo — reference for coding agents
audience: coding agents (Claude Code, Codex, Cursor, …) helping a user move services from Zeabur to Zenavo
source: https://zenavo.app/blog/migrate-from-zeabur.md
human version: https://zenavo.app/blog/migrate-from-zeabur
updated: 2026-11-14
---

# Migrating from Zeabur to Zenavo

Your user has services on Zeabur, which stops all services on December 31, 2026, and asked you to help move them to Zenavo. This document tells you how Zenavo works, which steps you can run and which the user must do themselves, so you can plan the move with them and carry it out.

Zenavo runs the user's projects on Linux servers they rent or own (or buy through Zenavo), with Zeabur's concepts: projects hold services, Zeabur templates import directly, code without a Dockerfile is built with zbpack, and the `zenavo` CLI has Zeabur's command names. Zenavo is independent and not affiliated with Zeabur.

Talk to the user in their language. This document is updated as Zeabur's shutdown progresses; fetch it again from the source URL at the start of each session instead of relying on a cached copy. When something here does not match what you observe, trust the observation and tell the user.

## Ground rules

- **Never print secrets.** Passwords, API keys, tokens and connection strings stay out of replies, logs, commits and files under version control. Show variable names with masked values.
- **Never ask the user to paste a secret into the chat**: no Zenavo or Zeabur API key, SSH password, private key or database password. The user signs in to each CLI themselves, and enters SSH credentials and secret values in a prompt or the console, not in the chat (see [Secrets](#secrets)).
- **Treat Zeabur exports as secret.** A project export or variable list holds credentials. Store them only as `chmod 600` files outside any repository, and delete them when the move is done.
- **Ask before** anything that costs money (a paid plan, buying a server), creating a project or service, deploying, restoring data, suspending anything on Zeabur, and cutover. The user changes DNS records themselves.
- **Do not change or delete anything on Zeabur** until the user confirms the new environment is stable, and then only with their agreement. Zeabur is the rollback until then; remind the user that the rollback ends when their Zeabur service expires.
- **Agree on the scope first.** Ask which projects to move before you inventory. Move one project at a time.
- **Rotate secrets.** Zeabur had security incidents in August and October 2026 in which some projects' environment variables were read. Recommend issuing new third-party secrets rather than copying old values (see [Secrets](#secrets)).

## Before you start

1. **Zeabur side.** Zeabur publishes its own reference for coding agents at `https://zeabur.com/blogs/migrate-from-zeabur.md`. Follow it for signing in to the Zeabur CLI (`npx zeabur@latest`), finding the user's workspaces, servers and projects, and exporting what each project contains. This document covers the Zenavo side.
2. **Zenavo CLI.** Run `npx zenavo version` (the npm package `zenavo` installs only the binary for the system, and runs nothing at install time). Other ways to install it are at `https://docs.zenavo.app/cli.md`.
3. **Zenavo account.** Run `npx zenavo auth status`. If the CLI is not signed in, ask the user to sign up at `https://zenavo.app/signup` if they have no account, then run the sign-in themselves (in Claude Code: `! npx zenavo auth login --scope deploy`). It opens a page in their browser where they approve a key for the CLI; they can limit it to some projects. Use `--scope full` only when a step needs it (creating projects needs `full` unless the user approves `deploy` for all projects; the CLI says so when a key is not allowed to do something).
4. **Non-interactive use.** Add `-i=false` so no command prompts, and `--json` for structured output on stdout. Commands that change something ask for confirmation; pass `--yes` only after the user agreed to that step in the chat.
5. **Optional: MCP.** If the user prefers, Zenavo also has an MCP server and a Claude Code plugin (`https://docs.zenavo.app/ai-agents.md`). It can look, deploy, roll back, restart and set variables, but cannot create projects or restore data, so the CLI is still needed for a migration.

## Platform model

| On Zeabur | On Zenavo |
| --- | --- |
| Workspace (personal or team) | Team. `zenavo team ls`, `zenavo team switch <team>` |
| Project, service | The same. A project runs on one server; its services reach each other on a private network |
| Dedicated server | A server the user connects (any Linux server they rent or own) or buys through Zenavo |
| Shared cluster | Does not exist. The user needs a server first |
| Template (YAML) | Imported by `zenavo template deploy -f <file>` or in the console under **New Project** |
| zbpack builds | Also zbpack; `zbpack.json` and `ZBPACK_*` variables work as before |
| `<service>.zeabur.internal` | `<service>.zenavo.internal`, rewritten on import |
| `ZEABUR_*` built-in variables | `ZENAVO_*`, rewritten on import |
| Database backup download (`.zip`) | Uploaded as is to a Zenavo database service and restored in the console |
| Volumes | Not copied between platforms. Files move as a `.tar` or `.tar.gz` archive |
| Custom domain with automatic HTTPS | The same, once the domain's DNS points at the new server |

Databases on Zenavo: PostgreSQL, MySQL, MariaDB, MongoDB, Redis and Valkey. Anything else runs as a Docker image service with a volume.

## What only the user can do

The CLI and the MCP server deliberately cannot do these. Tell the user exactly what to click and wait for them:

- **Add a server**: console → **Servers** → **New Server**. They enter the SSH details there; Zenavo uses them only for setup and erases them afterwards. Or they buy one there (**Buy a server from Zenavo**), which is paid monthly.
- **Upload and restore backups**: console → the database service → **Backup & Restore**.
- **Plans and billing**, team members, the GitHub App (needed for private GitHub repositories).
- **DNS records**, at their DNS provider.

## Choose a server

Each Zenavo project runs on one server. Requirements: Linux on amd64 or arm64 (Ubuntu 24.04 recommended), a static public IPv4 address, at least 1 CPU and 2 GB of memory (2 CPUs and 4 GB recommended), 20 GB of free disk or more, ports 80 and 443 free and open, SSH as `root` or a user with passwordless sudo during setup. The server should run nothing else: Zenavo installs K3s and serves HTTP and HTTPS itself.

- **The user used Zeabur's shared clusters**: they need a server. Ask where their users are and what they want to spend; any cloud provider works. Servers in mainland China work, but custom domains served from there need an ICP filing.
- **The user has a Zeabur dedicated server**: recommend a **new** server for Zenavo. Reusing the Zeabur server means stopping what runs on it first (Zenavo needs ports 80 and 443 and a server without Zeabur's agent), which removes the rollback path. Reuse it only if the user accepts that, after everything on it is backed up.
- Size the server from the inventory: the sum of the services' memory use plus headroom, and disk for databases, volumes and images.

The Free plan manages one server and includes 100 build minutes a month; deploying Docker images and databases uses no build minutes. Paid plans are at `https://zenavo.app/pricing`. Do not choose a plan for the user.

After the user adds the server, check it with `npx zenavo server ls` (it should be ready) before you go on.

## Import the project

1. Get the project's template YAML from Zeabur (`npx zeabur@latest project export --id <projectID>`, or the Zeabur dashboard). Save it as a `chmod 600` file outside any repository.
2. Preview and import it:

   ```sh
   npx zenavo template deploy -f zeabur.yaml --server <server> --var PUBLIC_DOMAIN=app.example.com
   ```

   It first prints the services and notes Zenavo found, and stops with a list of **blockers** if anything cannot be imported yet. Nothing is dropped silently: resolve each blocker with the user, edit the YAML, and run it again. Without `--deploy`, the project is created but not deployed, which is what you want: set variables and restore data first.
3. Check the result: `npx zenavo service ls -p <project>` and `npx zenavo env ls -s <service>` (values stay hidden).

What carries over: services, images and Git sources, environment variables, ports, volumes (empty), configuration files, health checks, initialization commands and dependencies.

## Variables and builds

- Built-in names are rewritten on import (`ZEABUR_*` to `ZENAVO_*`, `.zeabur.internal` to `.zenavo.internal`). Search the user's code for any other reference to Zeabur hostnames or variables.
- On Zeabur every variable reaches the build. On Zenavo only public front-end variables (`NEXT_PUBLIC_*`, `VITE_*`, `REACT_APP_*`, `VUE_APP_*`, `NUXT_PUBLIC_*`, `PUBLIC_*`, `EXPO_PUBLIC_*`, `GATSBY_*`) do. If the build reads another variable, the user adds it as a build argument on the service's **Settings** → **Build** → **Build arguments**, for example `NODE_OPTIONS=${NODE_OPTIONS}`. Never give a secret a public front-end name.
- A database service on Zenavo exposes its connection details as variables other services reference, for example `${POSTGRESQL_HOST}`. Point the application at the new database service's variables.

### Secrets

Values must not pass through the chat or your context. Ask the user to set each secret themselves with a prompt that does not echo:

```sh
! npx zenavo env set API_KEY -s <service>
```

A bare `KEY` asks for the value; `--file .env` reads a file the user prepared. For a value Zenavo can generate (a session secret, an internal password), use `npx zenavo service add … --secret KEY` or set it in the console. List what was set with `npx zenavo env ls -s <service>`, which shows names only.

Recommend new values for third-party secrets: cloud access keys, AI API keys, payment, email and OAuth secrets. A new database service already has a new password.

## Data

Rehearse first, then repeat at cutover.

- **PostgreSQL, MySQL and MariaDB**: add a database service of the same kind, for PostgreSQL the same major version as on Zeabur (Zeabur's backups record it; the service's version must be at least the backup's):

  ```sh
  npx zenavo service add --database postgresql:17 -p <project>
  ```

  The user downloads a backup on Zeabur, keeps the `.zip` exactly as downloaded (even when it is named `.sql.gz`), and uploads it in the console under the new service's **Backup & Restore** → **Upload**, then restores it. SQL from `pg_dump`, `pg_dumpall` or `mysqldump` (`.sql`, `.sql.gz`) works too. A PostgreSQL restore needs an empty database: restore into a new database service, never over one that has tables. Roles come along with their passwords; Zeabur's `root` superuser is restored without superuser rights or login.
- **MongoDB, Redis and Valkey**: **Backup & Restore** does not cover them. Plan the copy with the user (for example `mongodump` and `mongorestore`, or a Redis RDB file restored into the volume). Ask before exposing any database port to the internet, and close it again afterwards.
- **Files on volumes**: create a `.tar` or `.tar.gz` of the volume's directory on Zeabur (Zeabur's reference shows how), and have the user upload it to the volume under **Backup & Restore**.
- **Verify**: compare row counts of the main tables, or file counts, with the source. You can run read-only queries in a service with `npx zenavo service exec -s <service> -- <command>` (60 seconds at most); do not print rows that hold personal data.

## Deploy and verify

1. With the user's agreement, deploy: `npx zenavo deploy -p <project>` follows the build. `npx zenavo logs <service> --build` shows the latest build log, `npx zenavo logs <service>` the runtime log, and `npx zenavo service ls` state, readiness and restarts.
2. Before any DNS change, test on a generated domain: `npx zenavo domain add <name> -s <service>` gives the service a `<name>.zenavo.dev` address with HTTPS. Check sign-in, background workers, email, webhooks and OAuth callbacks (callback URLs may need the new domain registered at the provider).
3. The project's **Settings** has a **Migration checklist** (source backed up, data restored and checked, application verified, DNS switched, rollback ready). Ask the user to tick it as you go.

## Cutover and rollback

1. Agree on a time with the user. Record the current DNS records of every domain.
2. With the user's approval, suspend the **application** services on Zeabur to stop writes (Zeabur's reference shows how). Keep its databases running.
3. Take a final backup on Zeabur and restore it on Zenavo into a fresh database service, as in [Data](#data); point the application at it and redeploy or restart (`npx zenavo service restart <service>` applies changed variables without a rebuild).
4. Bind the custom domains: `npx zenavo domain add app.example.com -s <service>`. The user points the DNS records at the new server's IP address (`npx zenavo server get <server>`). HTTPS is issued once the records resolve.
5. Verify again on the custom domain.
6. **Rollback**: restore the recorded DNS records and resume the services on Zeabur. On Zenavo, `npx zenavo rollback` returns to an earlier successful deployment. Both work only while the Zeabur service has not expired.

Clean up Zeabur only after the user confirms the new environment is stable, and only what they agree to. Delete the export and variable files you created.

## Handover

Tell the user, in their language:

- What moved, where it runs (server, project, services, domains), and what was verified.
- Which secrets were rotated and which still need rotating at their providers.
- What is left on Zeabur and when it expires.
- How to back up on Zenavo: each database service's **Backup & Restore** tab, described at `https://docs.zenavo.app/operations/backups.md`.

## Help

- Documentation: `https://docs.zenavo.app/llms.txt` lists every page; append `.md` to any docs page URL for its Markdown.
- Migration guide for people: `https://docs.zenavo.app/guide/migrate-from-zeabur`.
- Support: `info@zenavo.app`, or the Discord at `https://discord.gg/DASbubePjV`.
