Skip to main content

Migration Guide

This guide covers upgrading from older Cinephage versions with breaking changes.

Current deployment tags:

  • latest = stable
  • dev = preview
  • vX.Y.Z = pinned stable release

Volume Mount Migration (/app/data → /config)

Applies to: Users upgrading from versions before January 2026 that used /app/data mounts.

Why This Change?

The /config consolidation:

  • Prevents accidentally overwriting application code by mounting /app
  • Simplifies volume management and keeps app state under a single root
  • Aligns with Docker best practices
  • Reduces risk of permission issues

Migration Path

The container entrypoint automatically detects and migrates your data.

Step 1: Update docker-compose.yaml

Add the /config mount while keeping the old data mount temporarily:

services:
cinephage:
image: ghcr.io/moldytaint/cinephage:latest
container_name: cinephage
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- '3000:3000'
environment:
- PUID=1000 # Your user ID (run: id -u)
- PGID=1000 # Your group ID (run: id -g)
- TZ=UTC # Your timezone
- ORIGIN=http://localhost:3000 # Trusted app origin / CSRF origin
- BETTER_AUTH_URL=http://localhost:3000 # Auth callback/redirect base URL
volumes:
- ./config:/config # NEW: Add this line
- ./data:/app/data # KEEP temporarily for migration
- /path/to/media:/media # REQUIRED: Your media library
- /path/to/downloads:/downloads # REQUIRED: Download client output folder

Step 2: Start the container

docker compose up -d

The entrypoint will detect both old and new mounts and automatically copy your data:

Migrating data from /app/data to /config/data...

Step 3: Verify migration

Check the logs to ensure success:

docker compose logs cinephage | grep -i "migrat"

Verify your data is present:

# Check database
ls -lh ./config/data/cinephage.db

# Check indexer definitions
ls -lh ./config/data/indexers/definitions/

Step 4: Remove old mounts

Once verified, update docker-compose.yaml to remove the legacy data mount:

services:
cinephage:
image: ghcr.io/moldytaint/cinephage:latest
container_name: cinephage
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- '3000:3000'
environment:
- PUID=1000 # Your user ID (run: id -u)
- PGID=1000 # Your group ID (run: id -g)
- TZ=UTC # Your timezone
- ORIGIN=http://localhost:3000 # Trusted app origin / CSRF origin
- BETTER_AUTH_URL=http://localhost:3000 # Auth callback/redirect base URL
volumes:
- ./config:/config # Keep only this
- /path/to/media:/media # REQUIRED: Your media library
- /path/to/downloads:/downloads # REQUIRED: Download client output folder

Step 5: Restart

docker compose up -d

Step 6: (Optional) Clean up old directories

After confirming everything works:

# Backup first (just in case)
tar -czf cinephage-legacy-backup-$(date +%Y%m%d).tar.gz ./data ./logs

# Then remove
rm -rf ./data ./logs

Option 2: Automatic Migration with Permission Fix

If the automatic migration fails with permission errors, you need to run as root temporarily.

Symptoms:

  • Log shows: ERROR: Failed to migrate data to /config/data
  • Permission denied errors during migration

Solution:

Step 1: Modify docker-compose.yaml to run as root temporarily:

services:
cinephage:
image: ghcr.io/moldytaint/cinephage:latest
container_name: cinephage
restart: unless-stopped
user: '0:0' # Temporarily run as root
security_opt:
- no-new-privileges:true
ports:
- '3000:3000'
environment:
- PUID=1000 # Your user ID (run: id -u)
- PGID=1000 # Your group ID (run: id -g)
- TZ=UTC # Your timezone
- ORIGIN=http://localhost:3000 # Trusted app origin / CSRF origin
- BETTER_AUTH_URL=http://localhost:3000 # Auth callback/redirect base URL
volumes:
- ./config:/config
- ./data:/app/data # Keep for migration
- /path/to/media:/media # REQUIRED: Your media library
- /path/to/downloads:/downloads # REQUIRED: Download client output folder

Step 2: Start and verify migration:

docker compose up -d
docker compose logs cinephage | grep -i "migrat"

Step 3: Revert to normal user mode:

Remove the user: '0:0' line from docker-compose.yaml (container now starts as root, entrypoint drops to PUID/PGID):

services:
cinephage:
image: ghcr.io/moldytaint/cinephage:latest
container_name: cinephage
restart: unless-stopped
# user line removed - entrypoint handles privilege dropping
security_opt:
- no-new-privileges:true
ports:
- '3000:3000'
environment:
- PUID=1000 # Your user ID (run: id -u)
- PGID=1000 # Your group ID (run: id -g)
- TZ=UTC # Your timezone
- ORIGIN=http://localhost:3000 # Trusted app origin / CSRF origin
- BETTER_AUTH_URL=http://localhost:3000 # Auth callback/redirect base URL
volumes:
- ./config:/config
- /path/to/media:/media # REQUIRED: Your media library
- /path/to/downloads:/downloads # REQUIRED: Download client output folder

Step 4: Remove old mounts and restart:

docker compose up -d

Option 3: Manual Migration

If you prefer to migrate manually or automatic migration doesn't work:

Step 1: Stop the container:

docker compose down

Step 2: Create config directory and copy data:

mkdir -p ./config/data
cp -a ./data/. ./config/data/

Step 3: Fix ownership (replace with your actual UID:GID):

# Find your IDs
id -u # Your UID
id -g # Your GID

# Set ownership
sudo chown -R $(id -u):$(id -g) ./config

Step 4: Update docker-compose.yaml:

services:
cinephage:
image: ghcr.io/moldytaint/cinephage:latest
container_name: cinephage
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- '3000:3000'
environment:
- PUID=1000 # Your user ID (run: id -u)
- PGID=1000 # Your group ID (run: id -g)
- TZ=UTC # Your timezone
- ORIGIN=http://localhost:3000 # Trusted app origin / CSRF origin
- BETTER_AUTH_URL=http://localhost:3000 # Auth callback/redirect base URL
volumes:
- ./config:/config
- /path/to/media:/media # REQUIRED: Your media library
- /path/to/downloads:/downloads # REQUIRED: Download client output folder

Step 5: Start container:

docker compose up -d

Troubleshooting Migration

Migration doesn't run

Symptom: No migration messages in logs

Cause: Entrypoint doesn't detect old mounts

Solution: Ensure old mounts are present in docker-compose.yaml and actually mounted:

# Check if mounts are active
docker inspect cinephage | grep -A 10 Mounts

Permission denied during migration

Symptom: ERROR: Failed to migrate data to /config/data

Cause: Container user can't read old data or write to /config

Solution: Use Option 2 to run as root with PUID/PGID.

Data in wrong location after migration

Symptom: Database or indexers not found

Cause: Data copied to wrong subdirectory

Solution: Verify structure:

# Should look like this:
./config/
├── data/
│ ├── cinephage.db
│ ├── indexers/
│ │ └── definitions/
│ └── nzb_cache/
└── cache/

If structure is wrong, stop container and manually reorganize:

docker compose down
# Fix structure
mv ./config/data/data/* ./config/data/
rmdir ./config/data/data
# Restart
docker compose up -d

Alpine to Debian Image Migration

Applies to: All users upgrading to Camoufox-based Captcha Solver

What Changed

  • Base image: node:22-alpine -> node:24-trixie-slim (Debian)
  • Image size: ~180MB → ~220MB
  • New feature: Camoufox browser support for Cloudflare bypass

Migration Steps

Step 1: Pull new image:

docker compose pull

Step 2: Recreate container:

docker compose up -d --force-recreate

Step 3: First startup downloads Camoufox (~80MB):

docker compose logs -f cinephage

You'll see: Downloading Camoufox (first run only, ~80MB)...

Step 4: Remove old environment variable:

If you have BROWSER_SOLVER_ENABLED in your .env, remove it (no longer used).

Step 5: Configure Captcha Solver:

  1. Open Cinephage UI
  2. Go to Settings > Integrations > Captcha Solver
  3. Enable and configure as needed

Troubleshooting

Image pull fails

# Try with explicit tag
docker pull ghcr.io/moldytaint/cinephage:latest

# Or build locally
git clone https://github.com/MoldyTaint/cinephage.git
cd cinephage
docker compose build

Camoufox download fails

Symptom: Warning: Failed to download Camoufox. Captcha solving will be unavailable.

Cause: Network issues or permission problems

Solution:

# Check container logs for details
docker compose logs cinephage | grep -i camoufox

# Verify cache directory permissions
docker exec cinephage ls -la /config/cache

# If permission issue, recreate with user 0:0 and PUID/PGID

Rolling Back

If you need to revert to an older version:

Step 1: Stop current container:

docker compose down

Step 2: Backup current data:

tar -czf cinephage-backup-$(date +%Y%m%d).tar.gz ./config

Step 3: Update docker-compose.yaml to use old image:

# Find stable image tags at: https://github.com/MoldyTaint/cinephage/pkgs/container/cinephage
image: ghcr.io/moldytaint/cinephage:v1.2.3

Step 4: If rolling back to pre-/config version, restore old data volume mounts:

volumes:
- ./data:/app/data
- /path/to/media:/media
- /path/to/downloads:/downloads

Step 5: Start container:

docker compose up -d

See Also