A single-user, no-authentication application that backs up local files to an Azure Storage account (Blob only).
- Backend: .NET 10 Minimal API + EF Core (SQLite) + Azure.Storage.Blobs
- Frontend: Vite + React + TypeScript
- Packaging: a single multi-arch Docker image (
linux/amd64+linux/arm64) in which the backend serves both the API and the built frontend. Compression uses 7-Zip (p7zip-full) bundled in the image.
.
├── backend/ # .NET 10 Minimal API
│ └── src/AzureStorageBackup.Api/
│ ├── Endpoints/ # Minimal API endpoint groups (all under /api)
│ ├── Services/ # Business logic (Azure storage / backup engine)
│ ├── Data/ # EF Core DbContext + migrations
│ ├── Models/ # Entities and DTOs
│ └── Program.cs # Composition root
├── frontend/ # Vite + React + TS (src/{api,components,pages})
├── Dockerfile # Multi-stage, multi-arch image
├── docker-compose.yml
└── .github/workflows/docker-publish.yml
Backend (port 5122):
cd backend
dotnet run --project src/AzureStorageBackup.ApiFrontend (port 5173; /api is proxied to the backend by Vite):
cd frontend
npm install
npm run devcd backend && dotnet testIntegration tests that talk to Azure use Azurite; they are skipped automatically when Azurite is not reachable on 127.0.0.1:10000.
The image is self-contained: the backend hosts the API and the compiled SPA on one HTTP port (8080). Rehydration of Archive-tier blobs, 7-Zip compression, restore and repair all run inside this container, so the host directories you want to back up (and restore into) must be mounted.
Build and run locally:
docker build -t azurestoragebackup .
docker run -d --name asb -p 8080:8080 \
-e ConnectionStrings__AzureStorage="<your Azure Storage connection string>" \
-v asb-data:/data -v asb-keys:/keys -v asb-temp:/temp \
-v /path/to/files:/backup-source \
azurestoragebackupThen open http://localhost:8080. Inside the app, set a backup's local root (and any restore target) to a path that exists inside the container, e.g. /backup-source.
Or with Docker Compose (docker compose up --build), after copying .env.example to .env.
ASP.NET Core maps nested config keys with a double underscore (Section__Key). All are optional; defaults shown are the in-container defaults set by the image.
| Variable | Purpose | Default (image) |
|---|---|---|
ConnectionStrings__AzureStorage |
Azure Storage account connection string. If empty, falls back to UseDevelopmentStorage=true (local Azurite) so the process still starts. |
(empty) |
ConnectionStrings__Sqlite |
SQLite connection string (app database). | Data Source=/data/app.db |
DataProtection__KeysPath |
Directory for the Data Protection key ring used to encrypt secrets at rest (account keys, backup passwords). Must be persisted — losing it makes stored secrets undecryptable. | /keys |
Backup__TempPath |
Working area root: compression, staging, restore, check, dead-weight compaction, and verbose logs live under here. Can grow large during a backup/restore. | /temp |
Backup__StagedLimitBytes |
Max bytes kept in the staging area before back-pressure. | 1073741824 (1 GiB) |
Scheduler__Enabled |
Enable the cron scheduler for scheduled backup/check/cleanup tasks. | true |
Scheduler__TimeZone |
IANA time-zone id used to evaluate cron expressions. | UTC |
Cors__AllowedOrigins__0 |
Allowed browser origin. Not needed for the single-image deployment (frontend is same-origin); relevant only when hosting the SPA separately. | http://localhost:5173 |
ASPNETCORE_URLS |
Listen address. | http://+:8080 |
ASPNETCORE_ENVIRONMENT |
ASP.NET environment. | Production |
| Container path | Purpose | Persist? |
|---|---|---|
/data |
SQLite database (app.db). |
Yes |
/keys |
Data Protection key ring. Losing it makes stored account keys/passwords undecryptable. | Yes |
/temp |
Backup/restore working area (compress, staged, restore, check, compact, verbose logs). Safe to discard, but needs free space. | Optional (needs disk space) |
(your choice, e.g. /backup-source) |
Host directories to back up. Mount read-only if you only back up. A backup's local root is set to this in-container path. | Bind mount |
(your choice, e.g. /restore-target) |
Where restores write. Mount read-write. | Bind mount |
GET /api/system/paths returns the resolved absolute paths at runtime (PRD §6 "Directories"), useful when configuring Docker volume mappings.
Multi-arch images are published to the GitHub Container Registry:
ghcr.io/secretnest/azurestoragebackup:latest
Publishing is a manual GitHub Action (.github/workflows/docker-publish.yml, workflow_dispatch) that builds for linux/amd64 and linux/arm64 with Buildx and pushes to GHCR.
Roadmap: docs/roadmap.md. Full requirements: docs/product-requirements.md. Backup engine design: docs/m4-backup-engine-design.md.