Migration from Marzban
Marzban stores data in MySQL or MariaDB, while XLADA stores it in PostgreSQL. A direct transfer of the database directory between different DBMSs is impossible: users are moved through the panel API, and old subscription links keep working via the subscription page compatibility mode. A "one-command" transfer is possible only for user data; the Xray configuration, nodes, and hosts are set up again in XLADA.
What is transferredâ
| Marzban data | How it is transferred |
|---|---|
| Usernames | username in POST /api/users |
| Trojan and Shadowsocks passwords, VLESS UUID | the trojanPassword, ssPassword, vlessUuid fields |
| Traffic limit and reset period | trafficLimitBytes, trafficLimitStrategy |
| Expiration date | expireAt in ISO 8601 format |
Status (active, disabled, limited, expired) | status |
| Squad assignment | internal-squads or bulk operations |
| Old subscription links | MARZBAN_LEGACY_* mode on the subscription page |
Administrators, traffic history, inbound/outbound, and hosts are not transferred â they are created again in XLADA via config profiles and hosts.
- The user type in Marzban is determined by the protocol:
vlessneedsvlessUuid,trojanneedstrojanPassword,shadowsocksneedsssPassword. If you do not transfer the protocol, the user will need a new key. - A username in XLADA is Latin letters, digits,
_, and-only (in the API, no shorter than three characters). When an old link is parsed, invalid characters are replaced with_, and a name shorter than six characters is padded to six. Create users in this form right away, otherwise the old link will not find its owner. - There is no ready-made importer inside the panel: a separate migration tool lives in
the
xray-panel/migrateorganization repository, and the panel only accepts data through the API.
Legacy link supportâ
The subscription page can accept old Marzban links and match them to XLADA users by name. The mode is turned on by environment variables:
| Variable | Purpose |
|---|---|
MARZBAN_LEGACY_LINK_ENABLED | enables the compatibility module |
MARZBAN_LEGACY_SECRET_KEY | the secret from the Marzban database; several keys â comma-separated |
MARZBAN_LEGACY_SUBSCRIPTION_VALID_FROM | cutoff: links created before the date are not accepted |
MARZBAN_LEGACY_DROP_REVOKED_SUBSCRIPTIONS | drop the connection for revoked subscriptions |
CUSTOM_SUB_PREFIX | subscription link prefix, for example sub |
When the mode is enabled, MARZBAN_LEGACY_SECRET_KEY is required â without it
the subscription page container will not start.
services:
remnawave-subpage:
image: ghcr.io/xray-panel/subscription-page:latest
restart: unless-stopped
environment:
- APP_PORT=3010
- REMNAWAVE_PANEL_URL=http://remnawave:3000
- REMNAWAVE_API_TOKEN=token_from_panel
- MARZBAN_LEGACY_LINK_ENABLED=true
- MARZBAN_LEGACY_SECRET_KEY=secret_from_marzban_db
- CUSTOM_SUB_PREFIX=sub
The secret lives in the jwt table of the Marzban database:
SELECT secret_key FROM jwt LIMIT 1;
Both Marzban schemes are supported: a JWT with the HS256 algorithm and the
access: subscription field, and a base64url token with a SHA-256 signature. If
there is no user with that name in XLADA, the old link will not open.
Step-by-step planâ
- Inventory. Export the list of users from Marzban and save the
secret_keyfrom thejwttable. Count the users â this is the reference for verification. - Installing XLADA. Bring up the panel and nodes following the Panel Installation and Node Installation instructions, create an API token in Settings â API Tokens.
- Transferring users. Create them with
POST /api/users, keeping the name, expiration date, and traffic limit:
curl -sX POST https://panel.example.com/api/users \
-H "Authorization: Bearer $XLADA_API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"username": "john_doe", "expireAt": "2026-01-17T15:38:45.065Z", "trafficLimitBytes": 0, "trafficLimitStrategy": "NO_RESET"}'
- Squads. Distribute the transferred users across internal squads â
one by one or in bulk via
/api/users/bulk/update-squads. - Old links. Deploy the subscription page with
MARZBAN_LEGACY_*from the example above and restart its container. - Verification. Open a couple of old Marzban links: the page must show XLADA user data. Then check fresh links in the Users section.
Transfer 5â10 users first and make sure that both login and the old link work. Do not turn off Marzban until you have compared the user count and made sure the clients connected.
What's nextâ
- Migration from Remnawave â moving the panel on the same database.
- Subscription Page â installation and environment variables.
- Users â limits, statuses, and subscriptions.
- API Specification â creation and bulk operation methods.