All settings are configured via environment variables in .env (or in the environment section of docker-compose.yml for Docker).
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
sqlite:///./vibenetbackup.db |
Database connection string |
SECRET_KEY |
change-me |
Encryption key for stored credentials |
AUTH_USERNAME |
admin |
Web UI / API username |
AUTH_PASSWORD |
admin |
Web UI / API password |
HOST |
0.0.0.0 |
Listen address |
PORT |
5005 |
Listen port |
CORS_ORIGINS |
http://localhost:5005,... |
Comma-separated allowed origins |
BACKUP_DIR |
./backups |
Where backup files are stored |
OXIDIZED_URL |
http://localhost:8888 |
Oxidized REST API URL |
LOG_LEVEL |
INFO |
Logging level (DEBUG, INFO, WARNING, ERROR) |
TZ |
America/Chicago |
Container timezone (e.g. America/New_York, Europe/London) |
The SECRET_KEY encrypts credential passwords stored in the database using Fernet symmetric encryption. Any string works — it is derived into a valid key via SHA-256.
Important:
- Use a long, random string in production
- Must remain the same across restarts — changing it makes existing encrypted credentials unreadable
- The install scripts auto-generate a random key if not set
- Docker auto-generates and persists a key in
/app/data/.secret_key
Generate a secure key:
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
# or
openssl rand -base64 32Warning: If you change
SECRET_KEYafter credentials have been saved, all stored passwords become undecryptable. You will need to re-enter them.
- Login — Use credentials from installation output (or defaults for development)
- Credentials — Add SSH credentials for your devices (username + password or SSH key)
- Devices — Add devices manually or import from Oxidized
- Test — Click Test All to verify connectivity
- Destinations — Configure where backups are stored (local, Git, SMB); enable compression if desired
- Schedule — Create backup jobs with cron expressions
- Retention — Configure GFS retention policies per destination
- Notifications — Add Apprise notification channels for backup alerts
VIBENetBackup uses Apprise for notifications. Configure channels at Notifications in the web UI.
Each channel has:
- Apprise URL — encrypted in the database (Fernet)
- On Success / On Failure — choose when to notify
- Test button — verify delivery before relying on it
| Scenario | Apprise URL |
|---|---|
| Gmail (app password) | mailto://user:app-password@gmail.com?to=ops@company.com |
| Outlook / M365 | mailto://user:password@outlook.com?to=ops@company.com |
| Corporate relay (port 25, no auth) | mailto://relay.company.local:25?from=backups@company.com&to=ops@company.com&smtp=relay.company.local |
| SMTP with TLS (port 587) | mailtos://user:pass@smtp.company.com:587?from=backups@company.com&to=ops@company.com |
| Multiple recipients | mailto://user:pass@gmail.com?to=a@co.com,b@co.com&cc=mgr@co.com |
| Service | URL Format |
|---|---|
| Slack | slack://TokenA/TokenB/TokenC/ |
| Discord | discord://WebhookID/WebhookToken/ |
| Telegram | tgram://BotToken/ChatID/ |
| Gotify | gotify://hostname/token |
| Ntfy | ntfy://topic/ |
| Webhook (JSON) | json://hostname/path |
See the Apprise wiki for 100+ supported services.
Local and SMB destinations support optional gzip compression. Enable it in the destination form by checking the Gzip backups checkbox.
When enabled:
- Text config backups are saved as
.cfg.gzinstead of.cfg - Reduces disk usage significantly for large configs
- The
latestsymlink updates to point to the compressed file
A daily maintenance job runs automatically at 3:30 AM (container local time):
| Task | Description |
|---|---|
| Retention sweep | Prunes old backup files per GFS policy |
| Stale cleanup | Marks in_progress backups older than 1 hour as failed |
| Job history purge | Deletes job run records older than 90 days |
| Record purge | Removes pruned backup DB rows older than 90 days |
| SQLite VACUUM | Reclaims disk space from deleted records |
Retention also runs after every backup job.
Manual trigger:
curl -u admin:password -X POST http://localhost:5005/api/v1/maintenance/run- Go to Credentials > Add (or edit an existing credential)
- Click Generate SSH Key — an RSA 4096-bit key pair is created
- Copy the public key from the modal
- Add the public key to your network devices'
authorized_keys - Save the credential
Keys are stored in ssh_keys/ with secure permissions (600 for private, 644 for public).
- Generate an SSH key:
ssh-keygen -t rsa -b 4096 -f ~/.ssh/vibenetbackup - Copy the public key to your devices:
ssh-copy-id -i ~/.ssh/vibenetbackup.pub user@device-ip - Add a credential in VIBENetBackup with the SSH Key Path set to the private key path
- For systemd installs, store the key where the service user can read it:
sudo mkdir -p /opt/vibenetbackup/.ssh sudo cp ~/.ssh/vibenetbackup /opt/vibenetbackup/.ssh/ sudo chown vibenetbackup:vibenetbackup /opt/vibenetbackup/.ssh/vibenetbackup sudo chmod 600 /opt/vibenetbackup/.ssh/vibenetbackup
- Login page at
/loginwith username and password - Remember me for 14 days — HMAC-SHA256 signed session cookie
- HTTP Basic Auth also supported for API / curl access
- Default credentials are auto-generated during install
- Change password: edit
AUTH_PASSWORDin.envand restart, or use./manage.sh set-password
Use a reverse proxy like Nginx:
server {
listen 443 ssl http2;
server_name backup.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:5005;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Or use Let's Encrypt with Certbot for free certificates.
| Access method | CORS_ORIGINS value |
|---|---|
| Same machine | http://localhost:5005 |
| LAN by IP | http://192.168.1.50:5005 |
| Domain + reverse proxy | https://backup.yourdomain.com |
| Multiple origins | http://localhost:5005,http://192.168.1.50:5005 |
| Allow all (development only) | * |
Docker note: The pre-built Docker image defaults to
CORS_ORIGINS=*. For production, restrict it to your actual IP or domain.
The systemd service created by install.sh runs with:
- Dedicated
vibenetbackupuser (no login shell) NoNewPrivileges=true— cannot gain privilegesProtectSystem=strict— read-only system filesProtectHome=true— cannot access user homesPrivateTmp=true— isolated /tmp.envand database:600permissions (owner-only)
- Restrict CORS origins to known IPs/domains
- Bind to localhost if using a reverse proxy:
HOST=127.0.0.1 - Use firewall rules to restrict access:
sudo ufw allow from 198.51.100.0/24 to any port 5005
Service fails to start:
sudo journalctl -u vibenetbackup -fPermission denied on backups:
sudo chown -R vibenetbackup:vibenetbackup /opt/vibenetbackup/backupsShow or change admin password:
cd /opt/vibenetbackup
./manage.sh show-password
./manage.sh set-password
./manage.sh reset-passwordDatabase locked:
sudo lsof /opt/vibenetbackup/vibenetbackup.dbvibenetbackup/
├── app/
│ ├── main.py # FastAPI entry point
│ ├── config.py # Settings management
│ ├── database.py # SQLAlchemy setup
│ ├── models/ # Database models
│ ├── routers/ # API and web routes
│ ├── modules/ # Backup engines, scheduler, retention
│ ├── templates/ # Jinja2 HTML templates
│ └── static/ # CSS, JS, images
├── install.sh # Production installer
├── uninstall.sh # Uninstaller
├── manage.sh # Password and service management
├── run.sh # Development runner
├── Dockerfile
├── docker/
│ ├── build-and-push.sh
│ ├── image/docker-compose.yml
│ └── build/docker-compose.yml
├── docs/ # Documentation
├── requirements.txt
├── pyproject.toml
└── README.md