Skip to main content

Migrate from Marzban

This guide walks you through migrating your data from a Marzban panel to a Remnawave panel using the Remnawave migration tool.

1. Server Preparation​

1.1. Installing Required Dependencies​

Make sure your server has the necessary tools installed by updating the system packages and installing Git and wget.

# Update system packages
sudo apt-get update

# Install Git and wget
sudo apt-get install -y git wget
tip

Run git --version and wget --version to confirm successful installation.

2. Downloading the Migration Tool​

2.1. Downloading the Latest Release​

Download the precompiled Remnawave migration tool from the GitHub releases page.

# Create and navigate to a working directory
mkdir -p /opt/remnawave && cd /opt/remnawave

# Download the latest version (v1.4.0 as of this guide)
wget https://github.com/remnawave/migrate/releases/download/v1.4.0/remnawave-migrate-v1.4.0-linux-amd64.tar.gz

2.2. Extracting the Tool​

Unpack the downloaded archive to access the binary.

# Extract the tarball
tar -xf remnawave-migrate-v1.4.0-linux-amd64.tar.gz
tip

After extraction, you should see the remnawave-migrate binary in your directory. Use ls -l to verify.

3. Configuration Setup​

3.1. Setting Up Migration Parameters​

The migration tool uses command-line flags for configuration. Below is an example command with all the required parameters. Replace the placeholder values with your actual server details.

./remnawave-migrate \
--panel-type=marzban \
--panel-url="https://your-marzban-server" \
--panel-username="admin" \
--panel-password="your-admin-password" \
--remnawave-url="https://your-remnawave-server" \
--remnawave-token="your-remnawave-token" \
--preserve-status

3.2. Configuration Options​

The tool supports the following flags and their corresponding environment variables:

FlagEnvironment VariableDescriptionDefault
--panel-typePANEL_TYPESource panel type (marzban or marzneshin)marzban
--panel-urlPANEL_URLSource panel URL (e.g., https://marzban.example.com)-
--panel-usernamePANEL_USERNAMESource panel admin username-
--panel-passwordPANEL_PASSWORDSource panel admin password-
--remnawave-urlREMNAWAVE_URLDestination panel URL (e.g., https://remnawave.example.com)-
--remnawave-tokenREMNAWAVE_TOKENDestination panel API token-
--batch-sizeBATCH_SIZENumber of users to process per batch100
--last-usersLAST_USERSMigrate only the last N users (0 = all users)0
--preferred-strategyPREFERRED_STRATEGYTraffic reset strategy for all users-
--source-headersSOURCE_HEADERSAdditional headers for source panel-
--dest-headersDEST_HEADERSAdditional headers for Remnawave (e.g., X-Api-Key)-
--preserve-statusPRESERVE_STATUSPreserve user status from source panelfalse
tip

If you’re using Remnawave with additional security provided by Caddy, you need to follow these steps:

  1. Log in to the Auth Portal and navigate to API Keys
  2. Issue a new API key
  3. Pass this key using the --dest-headers flag in the following format:
    --dest-headers="X-Api-Key:api-key-from-auth-portal"
tip
  • Use --last-users=5 for a test migration with a small subset of users.
  • Obtain your Remnawave API token from the Remnawave panel settings (e.g., under API or Integrations).

4. Post-Migration Verification​

4.1. What to Check​

After migration, verify the following on the Remnawave panel:

  1. User Count: Ensure the number of migrated users matches the source.
  2. Data Integrity:
    • Usernames
    • Passwords
    • Traffic limits
    • Expiration dates
    • User statuses (if --preserve-status was used)
tip

Log in to the Remnawave panel and spot-check a few users to confirm data accuracy.

5. Supporting Legacy Subscription Pages​

After migrating to Remnawave, the only way to ensure support and rendering of legacy Marzban subscription pages is by using the repository at https://github.com/remnawave/subscription-page/.

5.1. Default Docker Compose Configuration​

By default, the docker-compose.yml file for the subscription page service looks like this:

services:
remnawave-subscription-page:
image: remnawave/subscription-page:latest
container_name: remnawave-subscription-page
hostname: remnawave-subscription-page
restart: always
environment:
- APP_PORT=3010
- REMNAWAVE_PANEL_URL=http://remnawave:3000
ports:
- '127.0.0.1:3010:3010'
networks:
- remnawave-network
volumes:
- ./app-config.json:/opt/app/frontend/assets/app-config.json
networks:
remnawave-network:
driver: bridge
external: true

5.2. Adjusting for Marzban Compatibility​

During migration, you need to ensure compatibility with Marzban subscription paths and enable decryption of Marzban subscription links. Replace the environment section in the default configuration with the following:

services:
remnawave-subscription-page:
image: remnawave/subscription-page:latest
container_name: remnawave-subscription-page
hostname: remnawave-subscription-page
restart: always
environment:
- APP_PORT=3010
- REMNAWAVE_PANEL_URL=http://remnawave:3000
- MARZBAN_LEGACY_LINK_ENABLED=true
- MARZBAN_LEGACY_SECRET_KEY=secret
- REMNAWAVE_API_TOKEN=token
- CUSTOM_SUB_PREFIX=sub
ports:
- '127.0.0.1:3010:3010'
networks:
- remnawave-network
volumes:
- ./app-config.json:/opt/app/frontend/assets/app-config.json
networks:
remnawave-network:
driver: bridge
external: true

Configuration Options Explained​

VariableDescriptionExample Value
REMNAWAVE_PANEL_URLRemnawave Panel URL, can be http://remnawave:3000 or https://panel.example.comhttp://remnawave:3000
APP_PORTThe port on which the subscription page service runs.3010
MARZBAN_LEGACY_LINK_ENABLEDEnables support for legacy Marzban subscription links. Must be true to use the options below.true
MARZBAN_LEGACY_SECRET_KEYThe secret key from your Marzban database, required for decrypting legacy links.secret
REMNAWAVE_API_TOKENThe API token generated from your Remnawave panel dashboard (under "API Tokens").token
CUSTOM_SUB_PREFIXA custom prefix for subscription URLs to match your Marzban setup (e.g., sub).sub
tip
  • If MARZBAN_LEGACY_LINK_ENABLED is set to true, all subsequent variables (MARZBAN_LEGACY_SECRET_KEY, REMNAWAVE_API_TOKEN, and CUSTOM_SUB_PREFIX) must be provided.
  • To retrieve the MARZBAN_LEGACY_SECRET_KEY, query your Marzban database with:
    SELECT secret_key FROM jwt LIMIT 1;
    For example, if your Marzban database is in a Docker container named marzban-mysql, connect to it using:
    docker exec -it marzban-mysql mysql -uroot -pPassword
    Replace marzban-mysql and Password with your actual container name and root password.
  • Generate the REMNAWAVE_API_TOKEN from the Remnawave dashboard under the "API Tokens" section.

5.3. Verifying Legacy Support​

After deploying the updated configuration:

  1. Restart the remnawave-subscription-page service:
    docker compose up -d --force-recreate
  2. Test an old Marzban subscription link to ensure it resolves correctly and displays user data on the Remnawave subscription page.