Skip to content

Backup System

Talos includes a built-in backup system that captures the full state of your installation into portable .tar.gz archives. This page covers the technical details of the backup architecture.

Backup Manager Architecture

The backup system is implemented in internal/backup with three components:

ComponentResponsibility
ManagerOrchestrates backup creation, restoration, deletion, and retention enforcement
SchedulerRuns periodic backups at the configured interval using a ticker
StorePersists backup metadata in the backups SQLite table

Manager

The Manager struct holds references to the database, backup store, data directory, backup directory, retention count, and logger. It provides methods for:

  • CreateFullBackup -- create a new backup
  • Restore -- restore from a backup archive
  • DeleteBackup -- remove a backup and its file
  • ListBackups -- list all backup records
  • StartScheduler -- begin periodic backup execution

Scheduler

The scheduler runs in a goroutine and uses a time.Ticker:

go
func (m *Manager) StartScheduler(ctx context.Context, interval time.Duration) {
    ticker := time.NewTicker(interval)
    defer ticker.Stop()
    for {
        select {
        case <-ctx.Done():
            return
        case <-ticker.C:
            m.CreateFullBackup(ctx)
        }
    }
}

The scheduler is started when TALOS_BACKUP_INTERVAL_MINUTES is greater than zero. The interval is converted from minutes to time.Duration.

Backup Creation Process

  1. A temporary directory is created for the SQLite snapshot.
  2. VACUUM INTO creates an atomic copy of the database in the temp directory.
  3. A .tar.gz archive is created in the backup directory.
  4. The database snapshot is added to the archive as talos.db.
  5. If a services/ directory exists under the data directory, it is walked and added to the archive.
  6. The archive writers are flushed and closed.
  7. File size is recorded.
  8. A backup record is saved to SQLite.
  9. The retention policy is enforced.

VACUUM INTO

SQLite's VACUUM INTO command creates a compact, consistent copy of the database without locking the live database. This means backups can be taken while Talos is running without affecting performance or consistency.

Scheduling Engine

Configure automatic backups with environment variables:

VariableDefaultDescription
TALOS_BACKUP_INTERVAL_MINUTES0 (disabled)Backup interval in minutes
TALOS_BACKUP_RETAIN_COUNT10Maximum number of backups to keep
TALOS_BACKUP_DIRdata/backupsDirectory for backup files
Use CaseIntervalRetention
DevelopmentDisabled (0)--
Production (standard)60 minutes24 (1 day)
Production (conservative)1440 minutes (daily)30 (1 month)
High-traffic30 minutes48 (1 day)

Retention Policy

After each backup creation, the retention policy is enforced:

  1. All backups are listed, ordered by created_at DESC (newest first).
  2. If the count exceeds TALOS_BACKUP_RETAIN_COUNT, backups beyond the limit are deleted.
  3. Both the file on disk and the SQLite record are removed.
go
func (m *Manager) enforceRetentionPolicy(ctx context.Context) error {
    backups, _ := m.store.ListBackups(ctx)
    if len(backups) <= m.retain {
        return nil
    }
    for _, b := range backups[m.retain:] {
        m.deleteBackupFiles(b.Filename)
        m.store.DeleteBackup(ctx, b.ID)
    }
    return nil
}

Event Logging

Backup operations are logged via slog:

  • Created: backup created id=1 filename=talos-backup-20250101-120000.tar.gz size=5242880
  • Deleted: backup deleted id=1 filename=talos-backup-20250101-120000.tar.gz
  • Restored: restore complete -- process must be restarted backup_id=1
  • Scheduler started: backup scheduler started interval=1h0m0s
  • Scheduler error: scheduled backup failed error=...
  • Retention error: retention policy enforcement failed error=...

File Format

Backup files are standard .tar.gz archives:

talos-backup-YYYYMMDD-HHMMSS.tar.gz
  talos.db              # SQLite VACUUM INTO snapshot
  services/             # Service data volumes (if any)
    <service-name>/
      ...               # Volume contents

The archive is created using Go's archive/tar and compress/gzip packages.

API Endpoints

MethodEndpointDescription
GET/api/backupsList all backups
POST/api/backupsCreate a new backup
GET/api/backups/{id}/downloadDownload a backup file
POST/api/backups/{id}/restoreRestore from a backup
DELETE/api/backups/{id}Delete a backup

Create Backup

bash
curl -X POST http://localhost:3000/api/backups \
  -H "Cookie: session=<your-session-cookie>"

Response:

json
{
  "id": 1,
  "filename": "talos-backup-20250101-120000.tar.gz",
  "size_bytes": 5242880,
  "type": "full",
  "status": "completed",
  "created_at": "2025-01-01T12:00:00Z"
}

List Backups

bash
curl http://localhost:3000/api/backups \
  -H "Cookie: session=<your-session-cookie>"

Download Backup

bash
curl -O http://localhost:3000/api/backups/{id}/download \
  -H "Cookie: session=<your-session-cookie>"

Restore Backup

bash
curl -X POST http://localhost:3000/api/backups/{id}/restore \
  -H "Cookie: session=<your-session-cookie>"

WARNING

After restoring, the Talos process must be restarted. The restored database is not loaded until the process starts fresh.

Delete Backup

bash
curl -X DELETE http://localhost:3000/api/backups/{id} \
  -H "Cookie: session=<your-session-cookie>"

What Gets Backed Up

ComponentMethodNotes
SQLite databaseVACUUM INTOAtomic, consistent snapshot
Service volumesFile copyAll files under data/services/
.env configIncluded in volume copyContains TALOS_ENCRYPTION_KEY
Traefik TLS certsIncluded in volume copyUnder data/traefik/data/

Next Steps

Released under the Apache License 2.0.