Migration from Remnawave
XLADA is a fork of Remnawave under AGPL-3.0-only, so the migration comes down to swapping the images: service names, the database volume, and the network stay the same, and PostgreSQL comes up on top of the same data directory. Below is the in-place procedure, on the same server.
What is preservedâ
Only the container images change. Table and column names are deliberately not renamed in the fork, so the live database stays valid:
| Model | Table |
|---|---|
| Users | users |
| Nodes | nodes |
| Hosts | hosts |
| Administrators | admin |
| API tokens | api_tokens |
| HWID devices | hwid_user_devices |
| Config profiles | config_profiles |
| Internal and external squads | internal_squads, external_squads |
| Settings | remnawave_settings |
The .env file is carried over without renaming keys: APP_SECRET,
POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, DATABASE_URL,
PANEL_DOMAIN, FRONT_END_DOMAIN, SUB_PUBLIC_DOMAIN, and the rest are read
the same way. The subscription page still uses variables with the REMNAWAVE_
prefix (REMNAWAVE_PANEL_URL, REMNAWAVE_API_TOKEN).
XLADA migrations are additive only: a table for the administrator action log and second-factor fields are added. So the migration is reversible â it is enough to bring back the previous panel image.
Preparationâ
Before you start, verify the actual names and versions â whether the database comes up depends on them:
docker volume ls
docker ps --format 'table {{.Names}}\t{{.Image}}'
The migration file keeps the volume name of the old installation (in the standard compose
that is remnawave-db-data). If your volume is named differently, do not rename it â
instead bring the name: directive in the compose file to the existing name.
The data directory is incompatible between major versions. The new XLADA compose file
targets PostgreSQL 18, but for the migration you take the same major version that
created your volume â in the ready-made file that is postgres:17.6. Moving to 18
happens later, as a separate step via dump and restore.
Backupâ
Dump the database and save the .env. Keep the dump outside the volume with the
database until the migration is verified.
docker exec remnawave-db pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" \
> ~/remnawave-backup-$(date +%F).sql
tail -n 1 ~/remnawave-backup-*.sql # expected: -- PostgreSQL database dump complete
cp deploy/.env ~/remnawave-env-backup
chmod 600 ~/remnawave-env-backup
Stopping the old stackâ
cd deploy && docker compose down
Stop without the -v flag: it removes volumes together with the database.
Starting XLADA on the same databaseâ
Take the docker-compose.migrate-from-remnawave.yml file from the XLADA repository.
It differs from the regular compose file only in that it keeps the service names and the
volume of the old installation; the regular compose file would have created an empty
database. In .env, add the optional variable with the image tag:
XLADA_VERSION=latest
Start:
docker compose -f docker-compose.migrate-from-remnawave.yml up -d
docker logs -f remnawave
Migrations are applied automatically when the container starts: the entrypoint runs
prisma migrate deploy and prisma db seed. In the log, wait for the lines
Migrations deployed successfully! and Nest application successfully started.
The same steps are performed by the migrate-to-xlada.sh script: it puts the dump,
.env, compose file, and volume lists into backups/<date-time>/, checks the
dump for completeness, stops the stack without -v, and brings up XLADA.
Verificationâ
# the panel responds
curl -s -o /dev/null -w '%{http_code}\n' https://panel.example.com/api/auth/status
# the database sees the users â the count before and after must match
docker exec remnawave-db psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -tAc "SELECT count(*) FROM users;"
# the migrations were applied
docker exec remnawave-db psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c \
'SELECT migration_name FROM _prisma_migrations ORDER BY finished_at DESC LIMIT 5;'
The migration list must contain 20260912120000_add_admin_audit_log and
20260912130000_add_admin_totp. Then log in to the panel with the previous administrator
credentials and check that the nodes on the Nodes page are connected.
What not to doâ
docker compose down -vâ the-vflag removes the volume together with the database. This is the only command that actually destroys users.- Changing
APP_SECRETâ password hashes, the JWT signature, and TOTP secret encryption depend on it. After a change no one will be able to log in to the panel. - Renaming volumes, services, and networks â compose will create new empty ones, and
the old ones will stay hanging next to them.
DATABASE_URLpoints to the hostremnawave-db. - Upgrading the PostgreSQL major version on an existing volume and editing already
applied migrations â Prisma compares checksums in
_prisma_migrations.
Do not delete the dump and the .env backup until you have made sure that login, nodes, and
subscriptions work.
What's nextâ
- Migration from Marzban â when the source panel was different.
- Upgrading â how to roll out new versions after the migration.
- Panel Security â second factor and login attempt limiting.
- Environment Variables â including
AUDIT_LOG_RETENTION_DAYS.