Previously _load_registry silently dropped dead PIDs, so jobs that completed in the background were invisible on restart. Now dead PIDs are loaded as 'success' status so the user sees they completed. The registry is cleaned up after loading. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gniza - Linux Backup Manager
A generic Linux backup tool with a Python Textual TUI, web GUI, and CLI interface. Define named backup targets (sets of directories), configure remote destinations (SSH, local, S3, Google Drive), and run incremental backups with rsync --link-dest deduplication.
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓
▓▓
Features
- Target-based backups - Define named profiles with sets of directories to back up
- Include/exclude filters - Rsync include or exclude patterns per target (comma-separated)
- MySQL backup - Dump all or selected databases alongside directory backups
- Multiple remote types - SSH, local (USB/NFS), S3, Google Drive
- Incremental snapshots - rsync
--link-destfor space-efficient deduplication - Disk space safety - Abort backup if remote disk usage exceeds configurable threshold (default 95%)
- Textual TUI - Beautiful terminal UI powered by Textual
- Web dashboard - Access the full TUI from any browser with HTTP Basic Auth
- CLI interface - Scriptable commands for automation and cron
- Atomic snapshots -
.partialdirectory during backup, renamed on success - Retention policies - Automatic pruning of old snapshots
- Pre/post hooks - Run custom commands before/after backups
- Email notifications - SMTP or system mail on success/failure
- Root and user mode - Works as root (system-wide) or regular user (per-user)
- Cron scheduling - Manage cron jobs through TUI or CLI
Installation
One-liner (root)
curl -sSL https://git.linux-hosting.co.il/shukivaknin/gniza4linux/raw/branch/main/scripts/install.sh | sudo bash
One-liner (user mode)
curl -sSL https://git.linux-hosting.co.il/shukivaknin/gniza4linux/raw/branch/main/scripts/install.sh | bash
From source
git clone https://git.linux-hosting.co.il/shukivaknin/gniza4linux.git
cd gniza4linux
sudo bash scripts/install.sh # root mode
# or
bash scripts/install.sh # user mode
Root mode installs to /usr/local/gniza. User mode installs to ~/.local/share/gniza.
Dependencies
- Required: bash 4+, rsync
- Optional: ssh, curl (SMTP notifications), rclone (S3/GDrive)
- TUI/Web: python3, textual, textual-serve (installed automatically)
Quick Start
# Launch TUI
gniza
# Or use CLI
gniza targets add --name=mysite --folders=/var/www,/etc/nginx
gniza remotes add --name=backup-server # (edit config manually)
gniza --cli backup --target=mysite
gniza --cli backup --all
Usage
gniza [OPTIONS] [COMMAND]
Options:
--cli Force CLI mode (no TUI)
--debug Enable debug logging
--config=FILE Override config file path
--help Show help
--version Show version
Commands:
backup [--target=NAME] [--remote=NAME] [--all]
restore --target=NAME [--snapshot=TS] [--remote=NAME] [--dest=DIR]
targets list|add|delete|show [--name=NAME] [--folders=PATHS]
remotes list|add|delete|show|test|disk-info-short [--name=NAME]
snapshots list [--target=NAME] [--remote=NAME]
retention [--target=NAME] [--remote=NAME] [--all]
schedule install|show|remove
logs [--last] [--tail=N]
Configuration
| Mode | Config | Logs | Lock |
|---|---|---|---|
| Root | /etc/gniza/ |
/var/log/gniza/ |
/var/run/gniza.lock |
| User | ~/.config/gniza/ |
~/.local/state/gniza/log/ |
$XDG_RUNTIME_DIR/gniza-$UID.lock |
Config subdirectories: targets.d/*.conf, remotes.d/*.conf, schedules.d/*.conf
Target Config (targets.d/mysite.conf)
TARGET_NAME="mysite"
TARGET_FOLDERS="/var/www,/etc/nginx"
TARGET_EXCLUDE="*.log,*.tmp,.cache"
TARGET_INCLUDE=""
TARGET_REMOTE=""
TARGET_RETENTION=""
TARGET_PRE_HOOK=""
TARGET_POST_HOOK=""
TARGET_ENABLED="yes"
# MySQL backup (optional)
TARGET_MYSQL_ENABLED="no"
TARGET_MYSQL_MODE="all"
TARGET_MYSQL_DATABASES=""
TARGET_MYSQL_EXCLUDE=""
TARGET_MYSQL_USER=""
TARGET_MYSQL_PASSWORD=""
TARGET_MYSQL_HOST="localhost"
TARGET_MYSQL_PORT="3306"
TARGET_MYSQL_EXTRA_OPTS="--single-transaction --routines --triggers"
Include vs Exclude: Set TARGET_INCLUDE to back up only matching files (e.g. *.conf,*.sh). When include is set, everything else is excluded. If only TARGET_EXCLUDE is set, matching files are skipped. Patterns are comma-separated and support rsync glob syntax.
Remote Config (remotes.d/backup-server.conf)
REMOTE_TYPE="ssh"
REMOTE_HOST="backup.example.com"
REMOTE_PORT=22
REMOTE_USER="root"
REMOTE_AUTH_METHOD="key"
REMOTE_KEY="/root/.ssh/backup_key"
REMOTE_BASE="/backups"
BWLIMIT=0
RETENTION_COUNT=30
For local remotes (USB/NFS):
REMOTE_TYPE="local"
REMOTE_BASE="/mnt/backup-drive"
Snapshot Structure
$BASE/<hostname>/targets/<target>/snapshots/<YYYY-MM-DDTHHMMSS>/
├── meta.json
├── manifest.txt
├── var/www/
├── etc/nginx/
└── _mysql/ # MySQL dumps (if enabled)
├── dbname.sql.gz
└── _grants.sql.gz
Web Dashboard
The TUI can be served in a browser via textual-serve with HTTP Basic Auth:
# Enable during install (generates admin password)
curl -sSL .../install.sh | sudo bash
# Answer "y" to "Enable web dashboard?"
# Or manually
gniza web install-service # Install systemd service (port 2323)
gniza web start # Start the service
gniza web stop # Stop the service
Access at http://<server-ip>:2323. Credentials are stored in gniza.conf as WEB_USER and WEB_API_KEY.
Testing
bash tests/test_utils.sh
bash tests/test_config.sh
bash tests/test_targets.sh
License
MIT License - see LICENSE for details.