- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| LICENSE | ||
| portainer-recover.py | ||
| README.md | ||
portainer-recover
Recover Docker Compose stacks into Portainer from running containers.
When Portainer loses its data (When AI wipe's your portainer instance), this tool discovers your running compose-based containers, extracts their full configuration, and re-creates them as Portainer stacks via API — with minimal downtime.
Requirements
- Python 3.8+
- Docker CLI (must be on the host running the tool)
- Access to Portainer API (API key or JWT token)
No pip packages. Pure Python standard library.
Installation
# Download the script
curl -O https://raw.githubusercontent.com/YOUR_ORG/portainer-recover/main/portainer-recover.py
chmod +x portainer-recover.py
# Or just run it directly
python3 portainer-recover.py --help
Usage
# Set credentials (optional, can use --key and --url flags)
export PORTAINER_URL=https://localhost:9443
export PORTAINER_API_KEY=ptr_your_api_key_here=
# List all compose projects and their Portainer status
python3 portainer-recover.py list --endpoint 1
# Snapshot: save compose configs to files (no changes to containers)
python3 portainer-recover.py snapshot --output ./backups
# Recover all orphaned stacks into Portainer
python3 portainer-recover.py recover --endpoint 1
# Recover specific stacks
python3 portainer-recover.py recover --endpoint 1 -p myapp otherapp
# Force re-recover (delete existing Portainer stack and recreate)
python3 portainer-recover.py recover --endpoint 1 -p myapp --force
# Skip confirmation
python3 portainer-recover.py recover --endpoint 1 --yes
# Save a safety snapshot before recovering
python3 portainer-recover.py recover --endpoint 1 --snapshot
How It Works
- Discover: Scans running Docker containers for compose labels (
com.docker.compose.project) to identify compose projects - Extract: For each container, extracts image, environment, volumes, ports, networks, restart policy, depends_on, entrypoint, and command
- Generate: Produces a
docker-compose.ymlfrom the extracted data, pinning images by SHA256 digest to avoid fresh pulls - Recover: Stops containers, creates the stack via Portainer API (
POST /api/stacks/create/standalone/string), and verifies they're running again
Image Pinning
By default, images are pinned by their SHA256 digest. This means Portainer will use the exact image already on disk rather than pulling a new one. This is critical for images built locally (Dockerfiles with build: directives) — there's no registry to pull from.
Named Volumes vs Bind Mounts
The tool distinguishes between named Docker volumes (declared in compose volumes:) and bind mounts (host path mounts). Named volumes are preserved with their original names.
Cross-Stack Networks
If a stack's nginx config references containers from another stack (e.g., Nextcloud referencing Talk signaling), those containers may need to be manually connected to the new network. The tool doesn't handle this automatically — yet.
Portainer API Key Setup
- Log into Portainer
- Go to My Account (top-right user icon)
- Click API keys
- Click Add API key
- Copy the key (starts with
ptr_)
Endpoint ID
The endpoint ID is the Portainer environment ID. Default is 1 (local Docker). For remote agents, check the endpoint ID in Portainer's environment list via the API:
curl -sk https://localhost:9443/api/endpoints \
-H "X-API-Key: ptr_your_key" | python3 -m json.tool
Limitations
- Portainer CE 2.x only — not tested with BE/Enterprise
- Standalone stacks only — swarm stacks have a different API and aren't supported
- Build contexts are lost — containers built from Dockerfiles will use the current image digest. To update, you'll need to set up the build context in Portainer or via docker compose on the CLI
- Cross-stack network references — containers that reference services from other compose projects via shared networks may need manual
docker network connectafter recovery - Compose file
env_filedirectives — these are expanded at deploy time and the tool captures the resulting environment variables, not the original file references
License
MIT