Skip to content

Migrating from Standalone to Docker Compose

This guide walks you through migrating an existing Calagopus standalone (binary) installation to a Docker Compose stack. The process involves three things: copying your encryption key, exporting your PostgreSQL database and importing it into the new Docker-managed database.

No data transformation is required. The schema is identical between installations.

INFO

This guide covers the standalone panel compose setup only. If you want to migrate to an All-in-One setup instead, follow the Docker installation guide first, then return here for the database migration steps.

Overview

Here's what you'll be doing at a high level:

  • Grab your APP_ENCRYPTION_KEY and database password from your existing installation
  • Create the Docker Compose file and plug in those values
  • Start the database container
  • Dump the existing database and restore it into Docker
  • Start the full stack and verify everything works

Before You Start

Make sure you have:

  • A working standalone Calagopus installation
  • Docker and Docker Compose installed on the target host
  • Access to /etc/calagopus/.env on your standalone system
  • pg_dump available on your standalone system (it should already be there if PostgreSQL is installed)

Collect values from your existing installation

Open your existing configuration file:

bash
cat /etc/calagopus/.env

You need two values from this file:

APP_ENCRYPTION_KEY a 16-character alphanumeric string that was generated during initial setup:

txt
APP_ENCRYPTION_KEY=Ab3xZ9qR2mKp7vLw

The database password found in DATABASE_URL:

txt
DATABASE_URL="postgresql://calagopus:yourPassword@localhost:5432/panel"

The password is the segment between the second : and the @ in the example above, that's yourPassword.

WARNING

The APP_ENCRYPTION_KEY must be copied exactly as-is. It is used to decrypt sensitive data stored in your database. If it is wrong or missing, that data cannot be recovered.

Keep both values handy. You'll need them in the next step.

Set up your Docker directory

Create a directory to hold your Compose file and persistent data:

bash
mkdir -p /opt/calagopus
cd /opt/calagopus

Create the Docker Compose file

Create /opt/calagopus/docker-compose.yml with the following content. Before saving, replace the placeholder values marked with comments:

yaml
services:
  web:
    image: ghcr.io/calagopus/panel:latest
    restart: unless-stopped
    environment:
      - TZ=Europe/Berlin
      - REDIS_URL=redis://cache
      - DATABASE_URL=postgresql://panel:YOUR_DB_PASSWORD@db/panel # enter your db password
      - DATABASE_MIGRATE=true
      - PORT=8000
      - APP_DEBUG=false
      - APP_LOG_DIRECTORY=/var/log/calagopus
      - APP_PRIMARY=true
      - APP_ENABLE_WINGS_PROXY=true
      - APP_ENCRYPTION_KEY=YOUR_ENCRYPTION_KEY  # paste your key from above
      - APP_USE_DECRYPTION_CACHE=true
      - APP_USE_INTERNAL_CACHE=true
    volumes:
      - ./data:/var/lib/calagopus
      - ./logs:/var/log/calagopus
    ports:
      - 8000:8000
    extra_hosts:
      - "host.docker.internal:host-gateway"
    depends_on:
      - db
      - cache

  db:
    image: ghcr.io/calagopus/pgautoupgrade:18-alpine
    restart: unless-stopped
    environment:
      - TZ=Europe/Berlin
      - POSTGRES_USER=panel
      - POSTGRES_PASSWORD=YOUR_DB_PASSWORD  # use the same password as above
      - POSTGRES_DB=panel
      - PGDATA=/data
    volumes:
      - ./postgres:/data

  cache:
    image: ghcr.io/calagopus/valkey:latest
    restart: unless-stopped
    command: --protected-mode no --save 60 1
    environment:
      TZ: Europe/Berlin
    volumes:
      - ./cache:/data

Replace:

  • YOUR_ENCRYPTION_KEY the APP_ENCRYPTION_KEY value collected above
  • YOUR_DB_PASSWORD (both occurrences) you can reuse your old database password, or choose a new one. It just needs to match in both the web and db service definitions.

Start the database and cache

Start only the database and cache containers for now. The web container will fail on first boot if the database isn't populated yet.

bash
docker compose up -d db cache

Wait a few seconds for the database to finish initializing, then confirm it's running:

bash
docker compose ps

Both db and cache should show as running.

Export your existing database

Run this on your standalone system (not inside Docker). Replace yourPassword with the password collected earlier:

bash
PGPASSWORD="yourPassword" pg_dump \
  -h 127.0.0.1 \
  -U calagopus \
  -d panel \
  -F c \
  -f /opt/calagopus/panel.backup

This creates a compressed database dump at /opt/calagopus/panel.backup.

If you're migrating to a different host, copy panel.backup to /opt/calagopus/ on the target machine before continuing.

Import the database into Docker

From /opt/calagopus on your Docker host, run the following:

bash
docker exec -i calagopus-db-1 pg_restore \
  -U panel \
  -d panel \
  --no-owner \
  --clean \
  --if-exists \
  < panel.backup

You may see some harmless notices about dropping objects that don't exist yet - that's normal. The restore is successful as long as the command exits without errors.

Start the full stack

bash
docker compose up -d

The web container will run any pending database migrations automatically on first boot (DATABASE_MIGRATE=true).

Verify the migration

Once the stack is up, open Calagopus in your browser and check:

  • You can log in with your existing credentials
  • Your servers are visible and intact
  • No setup wizard (OOBE) appears (if it does, the database import likely did not work - see below)
  • Wings nodes are still connected

Troubleshooting

Setup wizard (OOBE) appears after starting: The database was not imported correctly, or the wrong database was targeted. Stop the stack, double-check the import command used the right container name (calagopus-db-1), re-run the import, then restart with docker compose restart web.

Login fails / encrypted data appears corrupted: Your APP_ENCRYPTION_KEY in docker-compose.yml probably doesn't match the one from your original installation. Stop the stack, correct the key and run docker compose up -d again.

calagopus-db-1 container not found: The container name is generated from your directory name. Check the actual name with docker compose ps and adjust the import command accordingly.