Add scheduled and manual backups

Backups are .tar.gz archives of a consistent database snapshot (VACUUM
INTO) plus the images folder. They run on a cron schedule, daily at 3:00
by default, and the newest N scheduled ones are kept (7 by default).
Manual backups are never pruned.

Settings → Backups offers schedule presets or a custom cron expression,
retention, "Back up now", and download/delete for each backup. A small
built-in parser handles standard 5-field cron syntax with names, ranges,
steps and @daily-style shorthands.

Backups go to CANON_BACKUP_DIR (default data/backups). Compose mounts a
separate canon-backups volume at /backups, overridable with
CANON_BACKUP_PATH.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cdnutterandClaude Opus 5.5 committed 2026-09-30 14:30:40 -07:00
1 parent 72b49d709a
commit f3185ba7bd
18 files changed
+940 -10

No files matched your search

+5 -1
View File
@@ -4,6 +4,7 @@ package config
import (
"net"
"os"
"path/filepath"
"strconv"
"strings"
)
@@ -16,6 +17,7 @@ type Config struct {
Host string
Port string
DataDir string
BackupDir string
AdminUsername string
AdminPassword string
SecureCookies bool
@@ -35,11 +37,13 @@ func Load() Config {
// just this machine. Use 127.0.0.1 to keep it local.
host := env("CANON_HOST", "0.0.0.0")
port := env("CANON_PORT", "4242")
dataDir := env("CANON_DATA_DIR", "./data")
return Config{
ListenAddr: env("CANON_LISTEN", net.JoinHostPort(host, port)),
Host: host,
Port: port,
DataDir: env("CANON_DATA_DIR", "./data"),
DataDir: dataDir,
BackupDir: env("CANON_BACKUP_DIR", filepath.Join(dataDir, "backups")),
AdminUsername: env("CANON_ADMIN_USERNAME", ""),
AdminPassword: env("CANON_ADMIN_PASSWORD", ""),
SecureCookies: envBool("CANON_SECURE_COOKIES", false),