A modern, user-friendly web interface for Borg Backup management. Zero-configuration deployment - just run docker compose up and you're done!
📚 Full Documentation | 🐳 Docker Hub
I love Borg Backup - it's powerful, efficient, and reliable. But let's be honest: the terminal interface is complicated.
Every time I wanted to:
- Create a backup → Remember the exact
borg createsyntax with all the flags - Browse archives → Parse verbose terminal output to find what I need
- Restore files → Navigate complex paths and remember extraction commands
- Schedule backups → Write and debug cron jobs manually
- Manage SSH keys → Deal with permissions and deployment across servers
It was exhausting. I found myself constantly referring to documentation, copy-pasting commands from notes, and making mistakes that could have been avoided with a simple UI.
So I built Borg Web UI - not to replace Borg's power, but to make it accessible. A web interface that handles the complexity while you focus on what matters: keeping your data safe.
- 🎯 Simplicity First - If you can click it, you shouldn't have to type it
- 🚀 Zero Configuration - No manual setup, no environment files to edit, just
docker compose up - 🔒 Secure by Default - Auto-generated secrets, JWT authentication, permission controls
- 📱 Works Everywhere - Desktop, tablet, mobile, Raspberry Pi, NAS, cloud servers
- 🌐 Real-time Feedback - Live backup progress, instant logs, responsive dashboards
- 💾 Data Safety - Never lose your backups or configuration, everything persists
This project solves my personal backup management headaches, and I hope it solves yours too.
Real-time system monitoring with Borg status, CPU, memory, and disk usage metrics, plus recent backup job history
Live backup progress tracking showing current file being processed, files count, original size, compressed size, and deduplicated data
Repository overview showing SSH connection details, compression settings, archive count, and configured source paths
Intuitive repository creation with command preview, encryption options, compression settings, and source directory configuration
# Borg Web UI
- Features
- Installation Methods
- Mounting Host Filesystem
- Configuration
- Data Persistence
- Troubleshooting
- Documentation
- License
- Support
- 🎯 Intuitive Dashboard - Real-time backup status and system metrics
- 📁 Backup Management - Create, schedule, and monitor backups with ease
- 🔍 Archive Browser - Browse and restore files from any backup
- 🗂️ Repository Management - Support for local, SSH, and SFTP repositories
- 🔐 SSH Key Management - Generate, import, and deploy SSH keys securely
- ⏰ Scheduling - Visual cron job builder with execution history
- 📊 Health Monitoring - System health checks and performance analytics
- 📝 Log Management - Real-time log streaming with search and filtering
- ⚡ Zero Configuration - No manual SECRET_KEY generation or environment setup required!
- 🔒 Auto-Secured - SECRET_KEY automatically generated and persisted on first run
- 📱 Responsive Design - Works seamlessly on desktop, tablet, and mobile
- 🌐 Multi-platform - Supports amd64, arm64, and armv7 architectures
- 🚀 Production Ready - Battle-tested on Raspberry Pi, NAS, and cloud servers
- Docker installed on your system
- 512MB RAM minimum (1GB recommended)
- Network access to backup destinations
After installation, access the web interface at http://localhost:8081
On first login, you'll need to use the default credentials:
- Username:
admin - Password:
admin123(or custom password if you setINITIAL_ADMIN_PASSWORDenvironment variable)
🔒 Security Feature: You will be automatically prompted to change your password on first login. The system requires a new password before you can access other features.
Portainer is the easiest way to deploy with a visual interface.
- Go to Stacks > Add Stack
- Name your stack:
borg-ui - Paste the following:
version: '3.8'
services:
borg-ui:
image: ainullcode/borg-ui:latest
container_name: borg-web-ui
restart: unless-stopped
ports:
- "8081:8081"
volumes:
- borg_data:/data
- borg_cache:/home/borg/.cache/borg
- ${LOCAL_STORAGE_PATH:-/}:/local:rw
environment:
- PUID=1000 # Optional: Your user ID (run: id -u)
- PGID=1000 # Optional: Your group ID (run: id -g)
volumes:
borg_data:
name: borg_data
borg_cache:
name: borg_cacheClick Deploy the stack and wait 30-60 seconds. That's it!
Open http://your-server-ip:8081 and login with default credentials.
For quick deployment using Docker CLI.
docker volume create borg_data
docker volume create borg_cachedocker run -d \
--name borg-web-ui \
--restart unless-stopped \
-p 8081:8081 \
-e PUID=1000 \
-e PGID=1000 \
-v borg_data:/data \
-v borg_cache:/home/borg/.cache/borg \
-v /:/local:rw \
ainullcode/borg-ui:latestNote: Replace 1000 with your user/group ID. Find yours with id -u && id -g
docker ps | grep borg-web-ui
docker logs borg-web-uiOpen http://localhost:8081 and login.
For infrastructure-as-code deployments.
mkdir borg-ui && cd borg-uiversion: '3.8'
services:
app:
image: ainullcode/borg-ui:latest
container_name: borg-web-ui
restart: unless-stopped
ports:
- "${PORT:-8081}:8081"
volumes:
- borg_data:/data
- borg_cache:/home/borg/.cache/borg
- ${LOCAL_STORAGE_PATH:-/}:/local:rw
environment:
- PUID=${PUID:-1001} # Your user ID (run: id -u)
- PGID=${PGID:-1001} # Your group ID (run: id -g)
# Optional: Override defaults (create .env file)
# - PORT=8082
# - LOG_LEVEL=DEBUG
volumes:
borg_data:
name: borg_data
borg_cache:
name: borg_cachedocker compose up -ddocker compose logs -f appOpen http://localhost:8081 and login.
The container automatically mounts your host filesystem at /local to:
- Access external drives, NAS mounts, or network storage for repositories
- Keep repositories outside the container (survive container rebuilds)
- Better performance for local/LAN storage vs SSH
- Simpler setup than SSH for local storage
By default, the container mounts:
- All Systems:
/(root filesystem) →/localin container with read-write access - Custom: Any directory via
LOCAL_STORAGE_PATHenvironment variable
Instead of mounting the entire filesystem, you can restrict access to specific directories:
Step 1: Customize the mount in your docker-compose.yml:
volumes:
# Option 1: Mount specific backup source and destination directories
- /home/user/my/source/repo:/source:ro # Source: read-only
- /home/user/my/destination:/destination:rw # Destination: read-write
# Option 2: Mount only user directories (Linux)
- /home:/local:rw
# Option 3: Mount only user directories (macOS)
- /Users:/local:rw
# Option 4: Mount only NAS or external storage
- /mnt/nas:/local:rw
# Option 5: Mount specific backup directories
- /mnt/backup-storage:/local:rwOr use the LOCAL_STORAGE_PATH environment variable in .env:
# Only mount specific directories you need for backups
LOCAL_STORAGE_PATH=/home/user/backups
# Examples for different use cases:
# LOCAL_STORAGE_PATH=/Users # Only user directories (macOS)
# LOCAL_STORAGE_PATH=/home # Only user directories (Linux)
# LOCAL_STORAGE_PATH=/mnt/nas # Only NAS mount point
# LOCAL_STORAGE_PATH=/mnt/backups # Only backup storage locationStep 2: Update repository paths in the UI based on your mount configuration
Examples with customized mounts:
| Mount Configuration | Repository Path in UI |
|---|---|
/home:/local:rw |
/local/username/backups/my-repo |
/Users:/local:rw |
/local/username/backups/my-repo |
/mnt/nas:/local:rw |
/local/borg-backups/my-repo |
/home/user/my/destination:/destination:rw |
/destination/my-repo |
Examples with default / mount:
- macOS:
/local/Users/your-username/backups/my-repo - Linux:
/local/home/your-username/backups/my-repo - External Drive:
/local/mnt/external-drive/backups/important-data - NAS:
/local/mnt/nas-mount/borg-backups/project-repo
- Principle of Least Privilege: Only mount directories that are necessary for your backup operations
- Use Read-Only Mounts for Source Data: When backing up data, mount source directories as read-only (
:ro) to prevent accidental modifications:volumes: - /home/user/documents:/source:ro - /mnt/backup-drive:/destination:rw
- Separate Source and Destination: Keep backup sources and backup destinations on separate mounts with appropriate permissions
- Audit Your Setup: Before deploying to production, review what directories are mounted and whether the container truly needs access to them
- Container Runs as Non-Root: The container runs as user
borg(configurable via PUID/PGID) which provides an additional security layer
The default configuration (/:/local:rw) is designed for:
- Quick Start Experience: Works out-of-the-box without configuration
- Maximum Flexibility: Access any directory for backups without reconfiguration
- Docker Container Isolation: The container itself provides isolation from the host
However, for production deployments or security-conscious environments, we strongly recommend customizing the volume mounts to restrict access to only the directories you need.
If your remote storage is already mounted on your host machine via NFS/CIFS/SMB:
# Example: Mount Raspberry Pi via NFS (on host machine)
sudo mount -t nfs 192.168.1.250:/home/pi /mnt/raspberry-pi
# Or mount via SMB/CIFS
sudo mount -t cifs //192.168.1.250/share /mnt/raspberry-pi -o username=piThen set in .env:
LOCAL_STORAGE_PATH=/mnt/raspberry-piRepositories created at /local/backups/repo-name will be stored on your Raspberry Pi!
The following are automatically configured on first run:
| Setting | Auto-Configuration |
|---|---|
| SECRET_KEY | Randomly generated (32 bytes), persisted to /data/.secret_key |
| DATABASE_URL | Auto-derived as sqlite:///data/borg.db |
| LOG_FILE | Auto-derived as /data/logs/borg-ui.log |
| SSH_KEYS_DIR | Auto-derived as /data/ssh_keys |
You can override defaults if needed:
| Variable | Description | Default |
|---|---|---|
PORT |
Application port | 8081 |
ENVIRONMENT |
Environment mode | production |
LOG_LEVEL |
Logging level | INFO |
Example with overrides:
environment:
- PORT=8082
- LOG_LEVEL=DEBUGImportant: You configure backup repositories directly through the web UI, not via Docker volumes!
Repositories can be:
- Local paths:
/local/mnt/backup,/local/external-drive/backups(see Mounting Host Filesystem) - SSH/SFTP:
user@host:/path/to/repo - Cloud storage: S3, Azure, Google Cloud (via rclone)
No need for a separate borg_backups volume!
Two volumes are used for persistent data:
borg_data - Contains:
- SQLite database (
borg.db) - Auto-generated SECRET_KEY (
.secret_key) - SSH keys
- Application logs
borg_cache - Contains:
- Borg repository caches
- Persists across container updates/rebuilds
- Improves performance by avoiding cache regeneration
# View application data
docker run --rm -v borg_data:/data alpine ls -la /data
# View borg cache
docker run --rm -v borg_cache:/cache alpine ls -la /cache# Backup borg_data to tar file
docker run --rm -v borg_data:/data -v $(pwd):/backup alpine tar czf /backup/borg_data_backup.tar.gz -C /data .
# Backup borg_cache to tar file (optional, can be regenerated)
docker run --rm -v borg_cache:/cache -v $(pwd):/backup alpine tar czf /backup/borg_cache_backup.tar.gz -C /cache .
# Restore borg_data from tar file
docker run --rm -v borg_data:/data -v $(pwd):/backup alpine tar xzf /backup/borg_data_backup.tar.gz -C /data
# Restore borg_cache from tar file
docker run --rm -v borg_cache:/cache -v $(pwd):/backup alpine tar xzf /backup/borg_cache_backup.tar.gz -C /cachevolumes:
borg_data:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/storage/borg-data
borg_cache:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/storage/borg-cache📚 Full Documentation Site - Complete guides, tutorials, and references
- System Design - Architecture and workflow design
- Implementation Tasks - Development progress
- Security Guide - Security best practices
- API Documentation - Interactive API docs (after installation)
Check logs:
docker logs borg-web-uiChange the port:
environment:
- PORT=8082Ensure you're using a Docker volume (not bind mount). The database must be at /data/borg.db inside the volume.
The container runs as user borg with configurable UID/GID (default: 1001:1001).
Set PUID/PGID environment variables to match your host user:
-
Find your UID/GID:
id -u && id -g -
Set environment variables in your deployment:
Portainer:
environment:
- PUID=1000 # Your user ID
- PGID=1000 # Your group IDDocker Compose (.env file):
# Raspberry Pi / Linux (usually 1000:1000)
PUID=1000
PGID=1000Docker Run:
docker run -d \
-e PUID=1000 \
-e PGID=1000 \
ainullcode/borg-ui:latest- Restart container:
docker-compose down && docker-compose up -d # or for Portainer: Update Stack
The container will automatically update the internal user's UID/GID on startup!
- Borg often needs access to system files (owned by root or other users)
- Container user must match host user for
/localmount permissions - Wrong UID/GID = "Permission denied" errors when creating repositories
If you need to back up files owned by multiple users or root:
- Run container with matching UID (recommended above)
- Use SSH repositories to backup remote systems
- Grant sudo access to container user on specific borg commands (already configured)
To rotate the SECRET_KEY:
docker exec borg-web-ui rm /data/.secret_key
docker restart borg-web-uiA new SECRET_KEY will be generated automatically. Note: This will invalidate all existing user sessions.
For developers who want to contribute or modify the code.
- Docker and Docker Compose
- Node.js 18+ (for frontend development)
- Python 3.9+ (for backend development)
-
Clone the repository:
git clone https://github.com/karanhudia/borg-ui.git cd borg-ui -
Copy environment file (optional for local dev):
cp .env.example .env
-
Start development environment:
docker compose up -d --build
-
Access the application:
- Frontend:
http://localhost:8081 - API Docs:
http://localhost:8081/api/docs
- Frontend:
Backend Development:
# View backend logs
docker compose logs -f app
# Run backend tests
docker compose exec app pytest
# Access Python shell
docker compose exec app pythonFrontend Development:
# Install dependencies
cd frontend && npm install
# Start dev server (with hot reload)
npm run dev
# Build for production
npm run build
# Run tests
npm testBorg UI has a comprehensive test suite covering backend API, integration tests, and end-to-end workflows.
Quick Start:
# Install test dependencies
pip install -r requirements.txt
# Run all tests with coverage
pytest
# Run only unit tests (fast)
pytest -m "not requires_ui"
# Run integration tests (requires Borg UI running)
pytest -m integrationTest Categories:
-
Unit Tests (
tests/) - Fast, no external dependencies- Archive browsing logic
- Directory navigation
- Multiple source directories
-
Integration Tests (
test_app.py) - Requires running server- API endpoints
- Authentication
- Repository operations
- Config validation
- Health checks
-
End-to-End Tests - Full workflow testing
- Backup operations
- Archive contents validation
- Restore operations
Coverage Reports:
View coverage locally:
pytest --cov=app --cov-report=html
open htmlcov/index.htmlCI/CD:
Tests run automatically on every push and pull request via GitHub Actions:
- Backend unit tests with coverage
- Integration tests with real Borg repositories
- Frontend build verification
- Coverage reports uploaded to Codecov
See tests/README.md for detailed testing documentation.
borg-ui/
├── app/ # Backend (FastAPI)
│ ├── api/ # API endpoints
│ ├── database/ # Database models
│ ├── services/ # Business logic
│ ├── config.py # Auto-configuration logic
│ └── main.py # Application entry point
├── frontend/ # Frontend (React + TypeScript)
│ ├── src/
│ │ ├── components/ # Reusable components
│ │ ├── pages/ # Page components
│ │ ├── services/ # API clients
│ │ └── App.tsx # Root component
│ └── package.json
├── docker-compose.yml # Simplified Docker Compose
├── Dockerfile # Multi-stage Docker build
└── .env.example # Development-only template
See CONTRIBUTING.md for guidelines.
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
- 📖 Documentation: Full Documentation Site
- 🐛 Bug Reports: GitHub Issues
- 💬 Discussions: GitHub Discussions
- 📧 Contact: Open an issue for support
- Official Repository: https://github.com/karanhudia/borg-ui
- Documentation Site: https://karanhudia.github.io/borg-ui
- Docker Hub: https://hub.docker.com/r/ainullcode/borg-ui
- Borg Backup Docs: https://borgbackup.readthedocs.io/
Built with:
- Borg Backup - Deduplication backup program
- FastAPI - Backend framework
- React - Frontend framework
- Material-UI - UI components
Made with ❤️ by Karan Hudia (ainullcode)
© 2025 Karan Hudia. All Rights Reserved.