Skip to main content

Migration Guide from Marzban to Remnawave

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

Ensure 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.3.0 as of this guide)
wget https://github.com/remnawave/migrate/releases/download/v1.3.0/remnawave-migrate-v1.3.0-linux-amd64.tar.gz

2.2. Extracting the Tool

Unpack the downloaded archive to access the migration binary.

# Extract the tarball
tar -xf remnawave-migrate-v1.3.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 to configure the migration. Below is an example command with all 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-
--preserve-statusPRESERVE_STATUSPreserve user status from source panelfalse
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:
- REMNAWAVE_PLAIN_DOMAIN=domain.com
- SUBSCRIPTION_PAGE_PORT=3010
ports:
- '127.0.0.1:3010:3010'
networks:
- remnawave-network

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:
- REMNAWAVE_PLAIN_DOMAIN=domain.com
- SUBSCRIPTION_PAGE_PORT=3010
- MARZBAN_LEGACY_LINK_ENABLED=true
- MARZBAN_LEGACY_SECRET_KEY=secret
- REMNAWAVE_API_TOKEN=token
- CUSTOM_SUB_PREFIX=custom
ports:
- '127.0.0.1:3010:3010'
networks:
- remnawave-network

networks:
remnawave-network:
driver: bridge
external: true

Configuration Options Explained

VariableDescriptionExample Value
REMNAWAVE_PLAIN_DOMAINThe address of your Remnawave panel (without https://).panel.domain.com
SUBSCRIPTION_PAGE_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.