TUI and CLI tool for managing Docker Compose service upgrades on remote servers via SSH
Project description
biblio-uplift
TUI and CLI tool for upgrading Docker Compose-based services on remote servers via SSH.
Install
pip install .
Quick Start
# Launch the interactive TUI
biblio-uplift
# Run an upgrade from the CLI
biblio-uplift run itops-vaultwarden
# Run non-interactively (for cron/automation)
biblio-uplift run itops-vaultwarden --non-interactive
# Dry run (simulate without executing)
biblio-uplift run itops-vaultwarden --dry-run
# Run cleanup (prune docker resources, old logs)
biblio-uplift cleanup itops-vaultwarden
# Check server status
biblio-uplift status itops-vaultwarden
# Restore from a backup
biblio-uplift restore itops-vaultwarden
biblio-uplift restore itops-vaultwarden --backup 20260501-030000
# Resume an upgrade after reboot (if session was lost)
biblio-uplift resume
# Run upgrades on all projects sequentially
biblio-uplift run-all --non-interactive
# List available backups
biblio-uplift backup list itops-vaultwarden
# Update a single service (pull repo + recreate)
biblio-uplift service-update my-project haproxy
# Check/upgrade Docker Compose install method
biblio-uplift tool run itops-vaultwarden compose-version
# List available tools
biblio-uplift tool list
# Run a tool against a project
biblio-uplift tool run itops-vaultwarden pending-security-updates
# Manage configs
biblio-uplift config edit itops-vaultwarden
biblio-uplift config validate itops-vaultwarden
biblio-uplift config create my-project --host myhost.example.com --project-dir /opt/docker/my-project
biblio-uplift config delete my-project
# View history
biblio-uplift history --last 10
Screenshots
Dashboard
Upgrade Pipeline
Tools
Configuration
Project configs live in configs/ as YAML files. Each config defines a remote server and its Docker Compose project.
# List configured projects
biblio-uplift config list
# Show a project's config
biblio-uplift config show itops-vaultwarden
Config Fields
| Field | Default | Description |
|---|---|---|
name |
required | Project identifier |
ssh_host |
required | Remote server hostname |
ssh_user |
ansible |
SSH username |
ssh_key |
~/.ssh/id_ed25519 |
Path to SSH private key (must not have a passphrase, or use ssh-agent) |
sudo |
true |
Prefix remote commands with sudo |
project_dir |
required | Path to the Docker Compose project on the remote server |
compose_files |
["docker-compose.yml"] |
Compose file(s) to use |
compose_profile |
null |
Compose profile. Set to hostname to use $(hostname -s) on the remote |
compose_command |
docker compose |
Compose binary |
backup_dir |
/var/backups/itops |
Where to store backups on the remote server (local disk, not NFS) |
backup_retention |
5 |
Number of backups to keep |
volumes |
[] |
Docker volume names to back up |
extra_backup_paths |
[] |
Additional paths to include in file backup |
healthcheck_urls |
[] |
HTTP(S) URLs to check after startup |
healthcheck_timeout |
120 |
Seconds to wait for containers to become healthy |
skip_os_update |
false |
Skip OS package updates by default |
skip_reboot |
false |
Skip reboot by default |
ssh_port |
22 |
SSH port |
git_branch |
main |
Git branch to pull |
maintenance_window |
null |
Allowed time window for runs (e.g. "Sun 02:00-06:00") |
on_failure_cmd |
null |
Shell command to run on failure (e.g. Slack webhook) |
on_success_cmd |
null |
Shell command to run on success |
reboot_timeout |
300 |
Seconds to wait for SSH after reboot |
apt_timeout |
600 |
Seconds to wait for apt operations |
pre_upgrade_hooks |
[] |
Shell commands to run before upgrade (executed as root via sudo) |
post_upgrade_hooks |
[] |
Shell commands to run after upgrade |
Hooks
Pre/post upgrade hooks are arbitrary shell commands executed on the remote server. They run as root (via sudo). Use them for things like:
pre_upgrade_hooks:
- "systemctl stop ci-runner"
- "/opt/scripts/notify-slack.sh 'Starting upgrade'"
post_upgrade_hooks:
- "systemctl start ci-runner"
- "/opt/scripts/notify-slack.sh 'Upgrade complete'"
Upgrade Pipeline
The upgrade runs these steps in order:
- Preflight — SSH connectivity, disk space check, backup size estimation
- Pre-hooks — Custom pre-upgrade commands
- Backup files — Tar project dir + extra paths
- Backup volumes — Export Docker volumes via alpine container
- Backup cleanup — Remove old backups beyond retention count
- Docker down —
docker compose down - Git pull — Pull latest from remote
- Docker pull — Pull latest images
- OS update —
apt-get update && upgrade && autoremove --purge - Reboot — Reboot and wait for SSH to come back
- Docker up —
docker compose up -d - Health check — Wait for containers healthy + HTTP checks
- Post-hooks — Custom post-upgrade commands
On failure, completed steps are rolled back in reverse order (docker down → docker up, git pull → git checkout previous commit).
Cleanup Pipeline
- Preflight — SSH connectivity check
- Docker cleanup — Prune stopped containers, dangling images, unused volumes, build cache
- Log cleanup — Truncate configured log files, vacuum journald
Set aggressive_prune: true in the cleanup config to remove all unused images (not just dangling) during cleanup.
TUI
Running biblio-uplift with no command launches the interactive terminal UI. It has 8 panels:
- Dashboard — Overview of all projects and their last run status
- Upgrade — Run upgrades interactively with live step progress
- Cleanup — Run cleanup pipelines with live output
- Server Status — View remote server health (disk, memory, uptime, containers)
- Backups — Browse and restore backups
- Config Editor — View and edit project configurations
- History — Browse past upgrade runs with filtering
- Tools — Security audits, log rotation, container management tools
CLI Flags
biblio-uplift [--debug] [--version] COMMAND
Global:
--debug Write verbose logs to logs/debug.log
--version Show version and exit
run PROJECT:
--non-interactive Skip confirmation prompts
--skip-reboot Skip the reboot step
--skip-os-update Skip OS package updates
--skip-backup Skip all backup steps
--skip-git Skip git pull
--dry-run Simulate without executing
--no-hooks Skip pre/post hooks
--on-failure TEXT Shell command to run on failure (overrides config)
--start-from TEXT Skip steps before this one (e.g. docker_pull)
cleanup PROJECT:
--non-interactive Skip confirmation prompts
--dry-run Show what would be done
restore PROJECT:
--backup TEXT Backup timestamp to restore (defaults to latest)
--non-interactive Skip confirmation prompts
resume:
Resume an upgrade after reboot if the controlling session was lost.
No options.
status PROJECT:
Show current status of a project's remote server.
No options.
backup list PROJECT:
List available backups for a project.
No options.
service-update PROJECT SERVICE:
Pull repo and recreate a single service.
--non-interactive Skip confirmation prompts
tool list:
List available tools by category.
tool run PROJECT TOOL_NAME:
--dry-run Preview what would happen
--non-interactive Skip confirmation prompts
run-all:
--non-interactive Skip confirmation prompts
--skip-reboot Skip the reboot step
--skip-os-update Skip OS package updates
--dry-run Simulate without executing
--projects TEXT Comma-separated project names (defaults to all)
config:
config list List all project configurations
config show PROJECT Show configuration details for a project
config create NAME Create a new project configuration
--host TEXT SSH hostname (required)
--project-dir TEXT Remote project directory (required)
--ssh-user TEXT SSH username
--ssh-key TEXT Path to SSH key
config edit PROJECT Open config in $EDITOR
config validate PROJECT
Validate config by testing SSH, Docker, and paths
config delete PROJECT
Delete a project configuration
--non-interactive Skip confirmation prompts
history:
--project TEXT Filter by project
--last INTEGER Show last N entries (default: 20)
Audit History
Every run is logged to logs/history.jsonl with timestamp, project, steps, outcomes, and duration. View with:
biblio-uplift history
biblio-uplift history --project my-project --last 5
Concurrent Run Protection
A file lock (/tmp/biblio-uplift-<project>.lock) prevents multiple upgrades of the same project from running simultaneously.
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Pipeline failed or error |
Cron / Unattended Use
# Weekly upgrade of vaultwarden, Sundays at 3am
0 3 * * 0 cd /path/to/biblio-uplift && biblio-uplift run itops-vaultwarden --non-interactive --on-failure "curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK -d '{\"text\": \"Vaultwarden upgrade failed\"}' " >> logs/cron.log 2>&1
For unattended runs:
- Always use
--non-interactiveto skip confirmation prompts - Set
on_failure_cmdin config or use--on-failurefor failure alerts - Set
maintenance_windowin config to prevent accidental runs outside hours - Monitor exit codes and
logs/history.jsonlfor audit trail
Development
pipx install --force .
biblio-uplift --debug run itops-vaultwarden --dry-run
Set ITOPS_UPGRADE_DIR to override the project root directory detection.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file biblio_uplift-0.1.0.tar.gz.
File metadata
- Download URL: biblio_uplift-0.1.0.tar.gz
- Upload date:
- Size: 95.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f237438fa5b3a6bf57683143269015414c23067e25bc16c4646a068f12ed5fc6
|
|
| MD5 |
9cf76f455b5a2f3b74cba038977dcbe6
|
|
| BLAKE2b-256 |
fc47cd20047e0fa39d2bdaa1959867afc0329274a1e2814a38b0f52bda0dafff
|
Provenance
The following attestation bundles were made for biblio_uplift-0.1.0.tar.gz:
Publisher:
publish.yml on cody-bibliocommons/biblio-uplift
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
biblio_uplift-0.1.0.tar.gz -
Subject digest:
f237438fa5b3a6bf57683143269015414c23067e25bc16c4646a068f12ed5fc6 - Sigstore transparency entry: 1484843089
- Sigstore integration time:
-
Permalink:
cody-bibliocommons/biblio-uplift@835a9ba5ff8cae12f2ea2f826762b28e24465011 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/cody-bibliocommons
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@835a9ba5ff8cae12f2ea2f826762b28e24465011 -
Trigger Event:
push
-
Statement type:
File details
Details for the file biblio_uplift-0.1.0-py3-none-any.whl.
File metadata
- Download URL: biblio_uplift-0.1.0-py3-none-any.whl
- Upload date:
- Size: 86.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e36ea5a832a809d491c080f9b9f64d5ac5a74b2c24851d179880f95d83eeed0b
|
|
| MD5 |
5720221388f0fbde1a938eaee473efb4
|
|
| BLAKE2b-256 |
d0ada2cdf96ad78e0d277c67482ab6a01773dd55eada1843131bc60f09fe13ca
|
Provenance
The following attestation bundles were made for biblio_uplift-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on cody-bibliocommons/biblio-uplift
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
biblio_uplift-0.1.0-py3-none-any.whl -
Subject digest:
e36ea5a832a809d491c080f9b9f64d5ac5a74b2c24851d179880f95d83eeed0b - Sigstore transparency entry: 1484843116
- Sigstore integration time:
-
Permalink:
cody-bibliocommons/biblio-uplift@835a9ba5ff8cae12f2ea2f826762b28e24465011 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/cody-bibliocommons
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@835a9ba5ff8cae12f2ea2f826762b28e24465011 -
Trigger Event:
push
-
Statement type: