Sign inSign up

marekotulakowski/backupvault

By marekotulakowski

Updated 5 months ago

Chunked backup server with TOTP/passkey admin login and manual TOTP setup support

Image
0

387

marekotulakowski/backupvault repository overview

BackupVault

Docker Ready Self Hosted License

Chunked backup server with admin panel, restore workflow, TOTP or passkey login, and optional VictoriaLogs.

What You Get

  • Chunked uploads with resume and retry
  • Admin panel at /admin
  • Test web client at /client
  • Client token authentication for API uploads
  • First admin login with QR and manual TOTP secret entry
  • Passkey as an alternative second factor
  • Optional VictoriaLogs profile for local or production log inspection

Quick Start

1. Create a Working Directory
mkdir -p backupvault
cd backupvault
mkdir -p data/backups data/tmp data/victoria-logs
2. Generate .env Automatically

Copy and run this block. It creates a ready-to-edit .env with strong random values:

CLIENT_TOKEN=$(openssl rand -hex 24)
ADMIN_PASSWORD=$(openssl rand -base64 18 | tr -d '=+/' | cut -c1-20)
SESSION_COOKIE_KEY=$(openssl rand -hex 32)

cat > .env <<EOF
APP_PORT=8080
SERVICE_NAME=backupvault
BACKUP_ROOT=/data/backups
TEMP_ROOT=/data/tmp
HOST_BACKUP_ROOT=./data/backups
HOST_TEMP_ROOT=./data/tmp
CLIENT_TOKENS=pc-biuro1:${CLIENT_TOKEN}
WEB_CLIENT_DEFAULT_TOKEN=${CLIENT_TOKEN}
ADMIN_USERNAME=admin
ADMIN_PASSWORD=${ADMIN_PASSWORD}
ADMIN_TOTP_SECRET=
SESSION_COOKIE_KEY=${SESSION_COOKIE_KEY}
ADMIN_SESSION_TTL_MINUTES=480
MAX_CHUNK_BYTES=67108864
PUBLIC_BASE_URL=https://backup.example.com
VICTORIA_LOGS_URL=http://victoria-logs:9428/insert/jsonline?_stream_fields=service,level,event
VICTORIA_LOGS_UI_URL=http://localhost:9428/select/vmui/
VICTORIA_LOGS_PORT=9428
HOST_VICTORIA_LOGS_ROOT=./data/victoria-logs
EOF

echo
echo "Created .env"
echo "Admin username: admin"
echo "Admin password: ${ADMIN_PASSWORD}"
echo "Client token: ${CLIENT_TOKEN}"

Notes:

  • ADMIN_TOTP_SECRET may stay empty.
  • On first login the setup screen will still show both the QR code and the manual TOTP secret.
  • Update PUBLIC_BASE_URL before production deployment.
3. Create docker-compose.yml

Copy this file as-is:

services:
  backupvault:
    image: marekotulakowski/backupvault:latest
    container_name: backupvault
    user: "10001:10001"
    read_only: true
    tmpfs:
      - /tmp
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    ports:
      - "${APP_PORT:-8080}:8080"
    environment:
      SERVICE_NAME: "${SERVICE_NAME:-backupvault}"
      LISTEN_ADDR: ":8080"
      BACKUP_ROOT: "${BACKUP_ROOT:-/data/backups}"
      TEMP_ROOT: "${TEMP_ROOT:-/data/tmp}"
      MAX_CHUNK_BYTES: "${MAX_CHUNK_BYTES:-67108864}"
      CLIENT_TOKENS: "${CLIENT_TOKENS}"
      ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}"
      ADMIN_PASSWORD: "${ADMIN_PASSWORD}"
      ADMIN_TOTP_SECRET: "${ADMIN_TOTP_SECRET:-}"
      ADMIN_SESSION_TTL_MINUTES: "${ADMIN_SESSION_TTL_MINUTES:-480}"
      SESSION_COOKIE_KEY: "${SESSION_COOKIE_KEY}"
      PUBLIC_BASE_URL: "${PUBLIC_BASE_URL}"
      WEB_CLIENT_DEFAULT_TOKEN: "${WEB_CLIENT_DEFAULT_TOKEN:-}"
      VICTORIA_LOGS_URL: "${VICTORIA_LOGS_URL:-}"
      VICTORIA_LOGS_UI_URL: "${VICTORIA_LOGS_UI_URL:-}"
    volumes:
      - "${HOST_BACKUP_ROOT:-./data/backups}:${BACKUP_ROOT:-/data/backups}"
      - "${HOST_TEMP_ROOT:-./data/tmp}:${TEMP_ROOT:-/data/tmp}"
    restart: unless-stopped

  victoria-logs:
    image: victoriametrics/victoria-logs:v1.50.0
    container_name: victoria-logs
    profiles: ["victorialogs"]
    read_only: true
    tmpfs:
      - /tmp
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    command:
      - "-storageDataPath=/victoria-logs-data"
    ports:
      - "${VICTORIA_LOGS_PORT:-9428}:9428"
    volumes:
      - "${HOST_VICTORIA_LOGS_ROOT:-./data/victoria-logs}:/victoria-logs-data"
    restart: unless-stopped
4. Start the Stack
docker compose --profile victorialogs up -d
5. Open the Service
  • Admin panel: http://localhost:8080/admin
  • Web test client: http://localhost:8080/client
  • VictoriaLogs UI: http://localhost:9428/select/vmui/

First Admin Login

Login to /admin with:

  • Username: admin
  • Password: the generated ADMIN_PASSWORD from .env

On the first login, BackupVault redirects to the 2FA setup screen.

That screen shows:

  • A QR code for TOTP
  • A manual TOTP secret for copy/paste or manual entry
  • An Add passkey button for biometric or hardware-key registration
Manual TOTP Setup

If you do not want to scan the QR code, enter the secret manually into Google Authenticator, 1Password, Aegis, or another TOTP app using:

  • Account: admin
  • Issuer: backupvault
  • Type: TOTP
  • Digits: 6
  • Period: 30s

After setup, daily login uses:

  1. Basic Auth username and password
  2. TOTP or passkey as the second factor

The TOTP page also supports remembering the current browser for 30 days after successful verification.

Nginx Deployment

Do not expose /admin publicly without TLS and access restriction.

Example Nginx config:

server {
    listen 443 ssl http2;
    server_name backup.example.com;

    ssl_certificate     /etc/letsencrypt/live/backup.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/backup.example.com/privkey.pem;

    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }

    location /admin {
        allow 10.0.0.0/8;
        allow 192.168.0.0/16;
        deny all;

        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Notes

  • Client backups are stored in the folder derived from the client token.
  • The client does not choose a target_path anymore.
  • Health endpoint: http://localhost:8080/healthz
  • Recommended production model: Nginx + HTTPS + IP restriction or VPN for /admin

Tag summary

Content type

Image

Digest

sha256:d473b6b62

Size

19.5 MB

Last updated

5 months ago

docker pull marekotulakowski/backupvault