Migrate from OSS to Pro

Step-by-step guide for migrating from OSS Password Pusher to Self-Hosted Pro

This article applies to: Pro Self-Hosted

Overview

This guide walks you through migrating your data from the open source Password Pusher to Self-Hosted Pro. The migration process exports all your users, pushes, audit logs, and file attachment references to a JSON file, which is then imported into your Pro instance.

What gets migrated:

  • Users — All user accounts with login credentials preserved
  • Pushes — All push records (text, file, URL, QR) with encrypted payloads
  • Audit Logs — Complete audit trail history
  • File Attachments — Active Storage references (actual files stay in place)

What changes during migration:

  • Push expiration changes from expire_after_days to Pro’s duration-based system
  • Encrypted payloads are re-encrypted with your Pro instance’s master key

What is not migrated:

  • API tokens — Not migrated; users must regenerate API tokens in Pro after migration (Account → API Tokens).

Important: Always create a complete backup before starting the migration. The import runs in a database transaction and can be rolled back, but backups are still essential.

Prerequisites

Before beginning, ensure you have:

  • OSS Password Pusher running version 1.69.0 or later
  • Pro Self-Hosted instance set up and running (fresh installation)
  • OSS encryption key — The Lockbox master key used to encrypt push payloads (see below)
  • Both instances using the same storage backend (local disk, S3, GCS, or Azure)
  • For file attachments:
    • Local disk: Same storage volume accessible to both instances
    • Cloud storage: Same bucket/container accessible with same credentials

Getting Your OSS Encryption Key

The migration requires your OSS instance’s encryption key to decrypt push payloads and re-encrypt them with your Pro instance’s key. Your OSS encryption key is shown in the export output when you run Step 1 — you can copy it from there. This section is for reference if you need to retrieve the key another way.

Retrieve the key using the Rails console:

# Docker
docker exec -it pwpush bin/rails runner "puts Lockbox.master_key"

# Docker Compose
docker compose exec pwpush bin/rails runner "puts Lockbox.master_key"

This will output your 64-character hex key, for example:

e4359d51dba412cc6b292b2a0354c202184bf15921df29f2fa7e149709ad88eb

Save this key — you’ll need it when running the import command.

Migration Steps

Step 1: Export Data from OSS

On your OSS Password Pusher instance, run the export task:

# Docker
docker exec -it pwpush bin/rails pwpush:export

# Docker Compose
docker compose exec pwpush bin/rails pwpush:export

This creates a JSON export file in /opt/PasswordPusher/tmp/:

============================================================
Password Pusher OSS -> Pro Migration Export
============================================================

Gathering data...

Exporting 150 users...
Exporting 5000 pushes...
Exporting 25000 audit logs...
Exporting 200 active storage blobs...
Exporting 200 active storage attachments...

============================================================
Export Complete!
============================================================

Export file: /opt/PasswordPusher/tmp/pwpush_export_20260221_120000.json
Storage backend: amazon

Record counts:
  - users: 150
  - pushes: 5000
  - audit_logs: 25000
  - active_storage_blobs: 200
  - active_storage_attachments: 200

NEXT STEPS:
------------------------------------------------------------
1. Copy this JSON file to your Pro instance

2. Ensure Pro is configured with the same storage backend:
   Storage backend: local
   -> Mount your OSS storage volume to the Pro container
      (e.g., same path as /rails/storage)

3. Run the import task in Pro:
   bin/rails 'pwpush:import[/path/to/export.json,YOUR-OSS-MASTER-KEY]'

   Your OSS master (encryption) key for this instance:
   749b1022e1cb83fb04f3022eacaf3bfef60c6d47f83e6fb41f534a05fc69929f

   Use this value as YOUR-OSS-MASTER-KEY (decrypts and re-encrypts push payloads).

============================================================

Step 2: Copy Export File to Pro Instance

The export file was created inside the OSS container at /opt/PasswordPusher/tmp/. You need to copy it out of the OSS container and then into your Pro container.

Copy the file out of the OSS container

First, copy the export file from inside the OSS container to your local machine:

# Docker
docker cp pwpush-oss:/opt/PasswordPusher/tmp/pwpush_export_20260221_120000.json ./

# Docker Compose
docker compose cp pwpush:/opt/PasswordPusher/tmp/pwpush_export_20260221_120000.json ./

Replace pwpush_export_20260221_120000.json with the actual filename shown in the export output.

Copy the file into the Pro container

Next, copy the export file into your Pro container:

# Docker
docker cp ./pwpush_export_20260221_120000.json pwpush-pro:/opt/PasswordPusher/tmp/

# Docker Compose
docker compose cp ./pwpush_export_20260221_120000.json pwpush-pro:/opt/PasswordPusher/tmp/

If your OSS and Pro containers are on different servers, transfer the file between servers first using scp or similar:

# Copy from local machine to remote server running Pro
scp ./pwpush_export_20260221_120000.json user@pro-server:~/

Then on the Pro server, copy the file into the container.

Step 3: Configure Storage Backend (If Using File Attachments)

Before importing, ensure your Pro instance can access the same file storage as your OSS instance.

Local Disk Storage

OSS and Pro store uploaded files in different subdirectories:

Edition File Storage Path
OSS /opt/PasswordPusher/storage/
Pro /opt/PasswordPusher/storage/files/

You have two options to migrate your files:

Option 1: Mount OSS storage to Pro’s files directory

Mount your existing OSS storage volume directly to Pro’s storage/files path:

# docker-compose.yml for Pro
services:
  pwpush-pro:
    image: your-pro-image
    volumes:
      # Mount OSS storage to Pro's files subdirectory
      - pwpush-oss-storage:/opt/PasswordPusher/storage/files

Option 2: Copy files manually

If you prefer to keep storage volumes separate, copy the files from your OSS storage into Pro’s files directory:

# Copy files from OSS container to local machine
docker cp pwpush-oss:/opt/PasswordPusher/storage/. ./oss-files/

# Copy files into Pro container's files directory
docker cp ./oss-files/. pwpush-pro:/opt/PasswordPusher/storage/files/

Ensure the files have correct ownership inside the container (Pro uses UID/GID 1000 by default):

docker compose exec pwpush-pro chown -R 1000:1000 /opt/PasswordPusher/storage/files

Cloud Storage (S3, Google Cloud, Azure)

Pro Self-Hosted configures cloud storage through the Administration Center, not environment variables.

To migrate cloud storage:

  1. Log in to your Pro instance as an admin
  2. Navigate to Administration CenterSettingsFile Storage
  3. Configure the same storage provider and credentials used by your OSS instance:
    • Storage Provider: Select the same provider (Amazon S3, Google Cloud Storage, Azure Blob, etc.)
    • Bucket/Container: Use the same bucket or container name
    • Credentials: Enter the same access keys, region, and endpoint

Since the files remain in your existing cloud storage, Pro will be able to access them once configured with the same credentials.

Tip: Review your OSS environment variables or docker-compose.yml to find your current storage configuration. Look for variables like PWP__FILES__STORAGE, PWP__FILES__S3__BUCKET, etc.

Step 4: Import Data to Pro

On your Pro instance, run the import task with the export file path and OSS master key:

# Docker
docker exec -it pwpush-pro bin/rails 'pwpush:import[/opt/PasswordPusher/tmp/pwpush_export_20260221_120000.json,YOUR-OSS-MASTER-KEY]'

# Docker Compose
docker compose exec pwpush-pro bin/rails 'pwpush:import[/opt/PasswordPusher/tmp/pwpush_export_20260221_120000.json,YOUR-OSS-MASTER-KEY]'

Example with actual key:

docker compose exec pwpush-pro bin/rails 'pwpush:import[/opt/PasswordPusher/tmp/pwpush_export_20260221_120000.json,749b1022e1cb83fb04f3022eacaf3bfef60c6d47f83e6fb41f534a05fc69929f]'

You’ll see progress output:

============================================================
Loading export file...
============================================================
Import from OSS Password Pusher
============================================================

Export metadata:
  Version:         1.68.1
  Exported at:     2026-02-21T12:00:00Z
  Schema version:  1
  Storage backend: amazon

Record counts:
  - users: 150
  - pushes: 5000
  - audit_logs: 25000
  - active_storage_blobs: 200
  - active_storage_attachments: 200

IMPORTANT: Ensure your Pro instance is configured with storage backend:
           amazon

============================================================
Starting import...

Importing users...
  Users: 150/150 (100.0%)
  -> 150 users imported with personal accounts
Importing pushes...
  Pushes: 5000/5000 (100.0%)
  -> 5000 pushes imported
Importing audit logs...
  Audit logs: 25000/25000 (100.0%)
  -> 25000 audit logs imported
Importing Active Storage records...
  Blobs: 200/200 (100.0%)
  Attachments: 200/200 (100.0%)
  -> 200 blobs, 200 attachments imported
============================================================
Import completed successfully!
============================================================

Summary:
  - Users imported: 150
  - Accounts created: 150
  - Pushes imported: 5000
  - Audit logs imported: 25000
  - Active Storage blobs imported: 200
  - Active Storage attachments imported: 200

Step 5: Verify the Migration

After import completes:

  1. Test user login — Log in with an existing user’s credentials
  2. Check existing pushes — Navigate to the dashboard and verify pushes appear
  3. Test push retrieval — Access an existing secret URL and verify it works
  4. Test file downloads — If you have file pushes, verify files can be downloaded
  5. Create new push — Create a new push to verify the system works end-to-end

Troubleshooting

Error: “Export file not found”

Ensure the file path is correct and accessible from within the container:

# List files in tmp directory
docker compose exec pwpush-pro ls -la /opt/PasswordPusher/tmp/

# Verify file exists
docker compose exec pwpush-pro cat /opt/PasswordPusher/tmp/pwpush_export_*.json | head -20

Error: “Unsupported schema version”

The export file was created with a different version of the export task. Ensure both your OSS and Pro instances are running compatible versions.

Note: “Users already exist with matching email addresses”

This is informational, not an error. When the import finds users in Pro with matching email addresses from the OSS export, it will:

  • Match the OSS user to the existing Pro user
  • Import their pushes, audit logs, and file attachments to the existing user’s account
  • Skip creating duplicate user records

This allows you to import data even if some users already exist in Pro.

Note: “Pushes have URL tokens that already exist”

This is informational, not an error. When the import finds pushes with URL tokens that already exist in Pro, it will skip those pushes to prevent duplicates. This typically happens if you’ve run the import before.

The import will continue with all other pushes that don’t have conflicting tokens.

Error: “Failed to re-key ciphertext”

The OSS master key provided doesn’t match the key used to encrypt the data.

Solutions:

  1. Verify you’re using the correct PWPUSH_MASTER_KEY from your OSS instance
  2. Check if OSS was using the default key
  3. Check if PWPUSH_MASTER_KEY_PREVIOUS was configured (for key rotation)

File Attachments Not Working

Files exist in storage but can’t be accessed after migration.

Checklist:

  1. Verify Pro is configured with the same storage backend as OSS
  2. Check storage credentials are correct
  3. For local storage, ensure the volume is mounted at the same path
  4. For cloud storage, verify bucket/container access
# Check storage configuration
docker compose exec pwpush-pro printenv | grep PWP__FILES

# Test storage access
docker compose exec pwpush-pro bin/rails runner "puts ActiveStorage::Blob.first.url"

Import Fails Partway Through

The import runs in a database transaction. If it fails, all changes are rolled back.

To retry:

  1. Check the error message for the specific issue
  2. Fix the underlying problem
  3. Run the import again — it’s safe to re-run on a clean database

Post-Migration Checklist

After confirming everything works:

  • Verify all user accounts can log in
  • Test creating and viewing pushes
  • Test file uploads and downloads (if using file pushes)
  • Verify audit logs appear in push details
  • Test the admin dashboard
  • Update DNS/load balancer to point to Pro instance
  • Keep OSS instance running as fallback for at least 1 week
  • Decommission OSS instance after extended verification

See Also