A self-hosted backup management system with a web UI, supporting multiple destinations including local drives, cloud storage, SFTP, and WebDAV.
-
Multiple Backup Destinations
- Local/USB drives with auto-mount support
- AWS S3 and S3-compatible (MinIO, Backblaze B2, DigitalOcean Spaces)
- Google Drive (including shared drives)
- Microsoft OneDrive
- SFTP/SSH servers
- WebDAV (Nextcloud, ownCloud)
-
Job Management
- Create, edit, clone, and delete backup jobs
- Multiple source directories per job
- Cron-based scheduling (daily, weekly, monthly, custom) with timezone support
- Manual and scheduled execution
- Real-time log streaming via WebSocket
-
Directory Compression
- Archive source directories (tar.gz or zip) before uploading
- Optional archive encryption (AES-256-CBC for tar, built-in for zip)
- Timestamped versioning with configurable per-directory retention
- Custom archive name prefixes
- Store-only mode (archive without compression)
-
Customizable Job List
- Show, hide, and reorder table columns
- Drag-to-resize column widths
- Human-readable schedule display ("Daily at 14:30")
- Preferences persisted per browser
-
Security
- Two-factor authentication (TOTP)
- AES-256-GCM encrypted credential storage
- Rate limiting with exponential backoff
- Argon2 password hashing
- Secure httpOnly cookies
-
Lightweight
- Single binary + SQLite
- Runs in ~50MB RAM
- ~80MB Docker image
| Provider | Description | Authentication |
|---|---|---|
| Local/USB | Rsync to local or mounted drives | None |
| AWS S3 | S3 and S3-compatible storage | Access Key + Secret |
| Google Drive | Google Drive folders and shared drives | OAuth2 |
| OneDrive | Microsoft OneDrive personal/business | OAuth2 |
| SFTP | SSH/SFTP servers | Password or SSH Key |
| WebDAV | Nextcloud, ownCloud, generic WebDAV | Username + Password |
# Create a directory for Dynamight
mkdir dynamight && cd dynamight
# Download the example config and docker-compose file
curl -O https://raw.githubusercontent.com/moonwhaler/dynamight/main/dynamight.toml.example
curl -O https://raw.githubusercontent.com/moonwhaler/dynamight/main/docker-compose.yml
# Create your configuration
cp dynamight.toml.example dynamight.toml
# Set a secure JWT secret (required)
NEW_SECRET=$(openssl rand -base64 32)
sed -i "s|CHANGE-ME-generate-with-openssl-rand-base64-32|${NEW_SECRET}|" dynamight.toml
# Start the container
docker compose up -dAccess the UI at http://localhost:8080 and complete the setup wizard to create your admin account.
services:
dynamight:
image: ghcr.io/moonwhaler/dynamight:latest
container_name: dynamight
restart: unless-stopped
cap_add:
- SYS_ADMIN
devices:
- /dev:/dev
ports:
- "8080:8080"
volumes:
- ./dynamight.toml:/app/config/dynamight.toml:ro
- dynamight-data:/app/data
- dynamight-logs:/app/logs
- /mnt:/mnt:rshared
# Add your backup sources (read-only recommended):
# - /home:/source/home:ro
# - /var/www:/source/www:ro
environment:
- TZ=${TZ:-UTC}
- RUST_LOG=${RUST_LOG:-info,dynamight=debug}
security_opt:
- no-new-privileges:true
volumes:
dynamight-data:
dynamight-logs:Configuration is done via a TOML file (dynamight.toml). Environment variables can override any setting.
Copy dynamight.toml.example to dynamight.toml and edit:
[security]
jwt_secret = "your-secret-here" # Generate with: openssl rand -base64 32
secure_cookies = true
allowed_browse_paths = ["/mnt", "/home", "/media"]
[server]
host = "0.0.0.0"
port = 8080
[database]
url = "sqlite:data/dynamight.db"See dynamight.toml.example for all available options with detailed documentation.
- Environment variables (highest priority) - for Docker/CI overrides
- Config file (
dynamight.toml) - Built-in defaults (lowest priority)
DYNAMIGHT_CONFIGenvironment variable (if set)./dynamight.toml(current directory)/etc/dynamight/dynamight.toml(system-wide)
Any setting can be overridden via environment variables using SCREAMING_SNAKE_CASE:
| Setting | Environment Variable |
|---|---|
security.jwt_secret |
JWT_SECRET |
server.host |
HOST |
server.port |
PORT |
database.url |
DATABASE_URL |
security.allowed_browse_paths |
ALLOWED_BROWSE_PATHS (comma-separated) |
| Setting | Default | Description |
|---|---|---|
security.jwt_secret |
required | Secret for JWT signing and credential encryption |
server.host |
0.0.0.0 |
Network interface to bind |
server.port |
8080 |
Port to listen on |
database.url |
sqlite:data/dynamight.db |
SQLite database location |
security.secure_cookies |
true |
Require HTTPS for cookies |
security.allowed_browse_paths |
["/mnt", "/home", "/media"] |
Paths users can browse |
rate_limit.max_attempts |
5 |
Max failed auth attempts before lockout |
- Rust 1.83+ (rustup.rs)
- Node.js 20+ (nodejs.org)
- rsync (usually pre-installed on Linux)
# Start both backend and frontend with one command
./scripts/dev.shThis will:
- Check dependencies
- Create
dynamight.tomlfromdynamight.toml.examplewith a random JWT secret - Install frontend npm packages
- Start backend on http://localhost:3000
- Start frontend dev server on http://localhost:5173 (with hot-reload)
# Create config file in project root
cp dynamight.toml.example dynamight.toml
# Edit dynamight.toml and set jwt_secret
# Or generate one: openssl rand -base64 32
# Create data directory
mkdir -p data
# Run the backend
cd backend
cargo runcd frontend
npm install
npm run dev./scripts/build.shCreates dist/dynamight-<timestamp>.tar.gz containing:
- Compiled binary (release mode)
- Frontend static files
- Migrations
- Configuration templates
- Installation scripts
# Build locally
docker build -t dynamight .
# Or use the build script (builds native package + Docker image)
./scripts/build.sh
# Build and push to registry
./scripts/build.sh --docker-only --push# Extract package
tar -xzf dynamight-*.tar.gz
cd dynamight-*
# Install as system service
sudo ./scripts/install.shThis will:
- Create
dynamightsystem user - Install binary to
/opt/dynamight - Create config at
/etc/dynamight/dynamight.toml(with auto-generated JWT secret) - Set up data directory at
/var/lib/dynamight - Install and configure systemd service
Then configure and start:
# Review/edit configuration (optional - defaults are sensible)
sudo nano /etc/dynamight/dynamight.toml
# Enable and start service
sudo systemctl enable dynamight
sudo systemctl start dynamight
# Check status
sudo systemctl status dynamight
# View logs
journalctl -u dynamight -fsudo ./scripts/install.sh uninstall- Click "New Job" on the Dashboard or Jobs page
- Enter a name and optional description
- Select Provider: Choose your backup destination type
- Configure Destination:
- Local/USB: Set mount point, subdirectory, USB UUID, auto-mount
- S3: Bucket, region, prefix, endpoint (for S3-compatible)
- Google Drive: Folder ID, shared drive ID (optional)
- OneDrive: Folder path, drive ID (optional)
- SFTP: Host, port, username, remote path, auth type
- WebDAV: URL, remote path
- Select Credentials (for cloud providers)
- Source Directories: Browse or type paths to back up
- Compress Directories (optional):
- Enable to archive each source directory before transfer
- Set staging path (temporary directory for archives)
- Choose format (tar.gz or zip) and optionally store-only (no compression)
- Enable timestamp versioning and set max archives to retain
- Optionally set an archive password
- Sync Options:
- Delete extraneous files
- Exclude patterns and directories
- Bandwidth limit (rsync/SFTP)
- Dry run mode
- Click "Create Job"
Credentials for cloud providers are stored encrypted. Manage them in Settings:
- Click Settings (gear icon) in the navbar
- Go to Credentials tab
- Add, edit, or delete credentials
- View which jobs use each credential
Add schedules in the job detail page:
- Open job details
- Click "Add Schedule"
- Choose schedule type:
- Daily: Run every day at specified time
- Weekly: Run on specific day of week
- Monthly: Run on specific day of month
- Custom: Enter cron expression
- Click "Add Schedule"
Enable 2FA for additional security:
- Open Settings (gear icon)
- Go to Security tab
- Click Enable 2FA
- Scan QR code with authenticator app
- Enter verification code
- Save recovery codes
Customise which columns appear in the job list:
- Click the Columns button in the job list header
- Check or uncheck columns to show/hide them (Name and Actions are always visible)
- Use the up/down arrows to reorder optional columns
- Drag column borders in the table to resize them
- Preferences are saved automatically in your browser
Schedules run according to the server's configured timezone (server.timezone in dynamight.toml or the TZ environment variable). Set this to your local timezone (e.g. Europe/Berlin, America/New_York) so that "Daily at 03:00" means 3 AM local time, not UTC.
┌─────────────────┐ ┌─────────────────────────────┐ ┌────────────┐
│ Browser │────▶│ Axum Server │────▶│ SQLite │
│ (Svelte SPA) │◀────│ (Rust) │◀────│ │
└─────────────────┘ └──────────┬──────────────────┘ └────────────┘
│
▼
┌─────────────────────────────┐
│ Provider Layer │
│ ┌─────┐ ┌────┐ ┌──────┐ │
│ │Rsync│ │ S3 │ │GDrive│ │
│ └─────┘ └────┘ └──────┘ │
│ ┌──────┐ ┌────┐ ┌──────┐ │
│ │OneDrv│ │SFTP│ │WebDAV│ │
│ └──────┘ └────┘ └──────┘ │
└─────────────────────────────┘
- Backend: Rust with Axum framework, SQLite databases (main + logs)
- Frontend: Svelte 5 SPA with Tailwind CSS
- Communication: REST API + WebSocket for live logs
- Providers: Trait-based abstraction for multiple destinations
See project-description.md for detailed architecture documentation.
For complete API documentation, see docs/API.md.
| Endpoint | Method | Description |
|---|---|---|
/api/auth/setup-required |
GET | Check if setup needed |
/api/auth/setup |
POST | Initial admin setup |
/api/auth/login |
POST | Authenticate user |
/api/auth/logout |
POST | End session |
/api/auth/me |
GET | Get current user |
/api/auth/change-password |
POST | Change password |
| Endpoint | Method | Description |
|---|---|---|
/api/auth/totp/setup |
POST | Generate TOTP secret |
/api/auth/totp/enable |
POST | Enable 2FA |
/api/auth/totp/disable |
POST | Disable 2FA |
/api/auth/totp/validate |
POST | Validate TOTP code |
/api/auth/totp/recovery |
POST | Use recovery code |
/api/auth/totp/status |
GET | Get 2FA status |
| Endpoint | Method | Description |
|---|---|---|
/api/jobs |
GET | List all jobs |
/api/jobs |
POST | Create job |
/api/jobs/:id |
GET | Get job details |
/api/jobs/:id |
PUT | Update job |
/api/jobs/:id |
DELETE | Delete job |
/api/jobs/:id/run |
POST | Run job |
/api/jobs/:id/cancel |
POST | Cancel running job |
/api/jobs/:id/clone |
POST | Clone job |
| Endpoint | Method | Description |
|---|---|---|
/api/jobs/:id/schedules |
GET | List job schedules |
/api/jobs/:id/schedules |
POST | Create schedule |
/api/schedules/:id |
PUT | Update schedule |
/api/schedules/:id |
DELETE | Delete schedule |
| Endpoint | Method | Description |
|---|---|---|
/api/jobs/:id/runs |
GET | List job runs |
/api/runs/:id |
GET | Get run details |
/api/runs/:id |
DELETE | Delete run |
/api/runs/:id/logs |
GET | Get run logs |
/api/ws/logs/:runId |
WS | Stream live logs |
/api/ws/status |
WS | Global status updates |
| Endpoint | Method | Description |
|---|---|---|
/api/credentials |
GET | List credentials |
/api/credentials |
POST | Create credential |
/api/credentials/:id |
GET | Get credential |
/api/credentials/:id |
PUT | Update credential |
/api/credentials/:id |
DELETE | Delete credential |
/api/credentials/:id/usage |
GET | Get credential usage |
| Endpoint | Method | Description |
|---|---|---|
/api/providers |
GET | List providers |
/api/providers/:type/capabilities |
GET | Get capabilities |
/api/providers/test |
POST | Test connection |
| Endpoint | Method | Description |
|---|---|---|
/api/system/health |
GET | Health check |
/api/system/drives |
GET | List USB drives |
/api/system/mounts |
GET | List mount points |
/api/system/mount |
POST | Mount drive |
/api/system/unmount |
POST | Unmount drive |
/api/system/browse |
GET | Browse filesystem |
/api/system/mkdir |
POST | Create directory |
/api/system/allowed-paths |
GET | Get allowed paths |
/api/settings |
GET/PUT | App settings |
- Container Privileges: Requires
SYS_ADMINcapability for mount operations. Useno-new-privilegessecurity option. - Source Mounts: Mount backup sources as read-only (
:ro) when possible. - HTTPS: Use a reverse proxy (nginx, Caddy) for HTTPS in production.
- 2FA: Enable two-factor authentication for additional security.
- Credentials: All provider credentials are encrypted with AES-256-GCM.
- Rate Limiting: Brute-force protection with exponential backoff.
Ensure the container has proper capabilities:
cap_add:
- SYS_ADMIN
devices:
- /dev:/dev- Verify
/devis mounted in the container - Check the drive has a filesystem with UUID:
sudo blkid - Check container logs:
docker compose logs dynamight
Mount source directories as volumes:
volumes:
- /path/to/source:/source/mydata:ro- Verify credentials are correct
- Use "Test Connection" button in job configuration
- Check firewall allows outbound HTTPS
- For OAuth providers, ensure tokens haven't expired
Wait for lockout to expire (check logs for duration) or restart the application.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- rsync — The backbone of reliable file synchronization
- Axum — Ergonomic Rust web framework
- Svelte — Cybernetically enhanced web apps
- Tailwind CSS — Utility-first CSS framework
- AWS SDK for Rust — S3 integration
- russh — SSH/SFTP client