13 KiB
| display_name | description | icon | verified | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Restic Backup | Cloud-backed ephemeral workspaces with automatic backup on stop and restore on start using Restic | ../../../../.icons/restic.svg | false |
|
Restic Backup
Automatic cloud backups for Coder workspaces. Backs up on stop, restores on start.
Features
- Auto backup/restore on workspace stop/start
- Works with S3, B2, Azure, GCS, SFTP, local storage
- Encrypted and deduplicated
- Workspace-aware tagging for easy browsing
- Configurable retention policies
- Clone backups between workspaces
Quick Start
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "s3:s3.amazonaws.com/my-workspace-backups"
password = var.restic_password
env = {
AWS_ACCESS_KEY_ID = var.aws_access_key
AWS_SECRET_ACCESS_KEY = var.aws_secret_key
}
}
How It Works
- Workspace stops → automatic backup to cloud
- Workspace starts → automatic restore from backup
- Backups are tagged with
workspace-id,workspace-owner,workspace-name - Auto-restore uses
workspace-idto find the correct backup - Manually restore any backup using
snapshot_id
Storage Backend Configuration
AWS S3
Official Restic S3 Documentation
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "s3:s3.amazonaws.com/my-bucket/workspace-backups"
password = var.restic_password
env = {
AWS_ACCESS_KEY_ID = var.aws_access_key
AWS_SECRET_ACCESS_KEY = var.aws_secret_key
AWS_DEFAULT_REGION = "us-east-1"
}
}
Backblaze B2 (Cost-Effective)
Official Restic B2 Documentation
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "b2:my-bucket:workspace-backups"
password = var.restic_password
env = {
B2_ACCOUNT_ID = var.b2_account_id
B2_ACCOUNT_KEY = var.b2_account_key
}
}
Azure Blob Storage
Official Restic Azure Documentation
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "azure:container-name:/workspace-backups"
password = var.restic_password
env = {
AZURE_ACCOUNT_NAME = var.azure_account_name
AZURE_ACCOUNT_KEY = var.azure_account_key
}
}
Google Cloud Storage
Official Restic GCS Documentation
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "gs:my-bucket:/workspace-backups"
password = var.restic_password
env = {
GOOGLE_PROJECT_ID = var.gcp_project_id
GOOGLE_APPLICATION_CREDENTIALS = "/path/to/service-account.json"
}
}
MinIO or S3-Compatible Storage
Official Restic Minio Documentation | S3-Compatible
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "s3:http://minio.company.com:9000/workspace-backups"
password = var.restic_password
env = {
AWS_ACCESS_KEY_ID = var.minio_access_key
AWS_SECRET_ACCESS_KEY = var.minio_secret_key
}
}
SFTP
Official Restic SFTP Documentation
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "sftp:user@backup-server.com:/backups/restic"
password = var.restic_password
# SSH key should be at ~/.ssh/id_rsa
# Or configure custom SSH command:
env = {
RESTIC_SFTP_COMMAND = "ssh user@host -i /path/to/key -s sftp"
}
}
Local Directory (Testing)
Official Restic Local Documentation
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "/backup/restic-repo"
password = var.restic_password
}
Note: Use persistent storage (Docker volume, PV) for local repositories.
Advanced Configuration
Selective Backup Paths
Only backup specific directories:
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "s3:s3.amazonaws.com/backups"
password = var.restic_password
backup_paths = [
"/home/coder/projects",
"/home/coder/.config",
"/home/coder/data",
]
exclude_patterns = [
"**/.git",
"**/node_modules",
"**/__pycache__",
"**/target",
"**/.venv",
"**/tmp",
]
env = {
AWS_ACCESS_KEY_ID = var.aws_access_key
AWS_SECRET_ACCESS_KEY = var.aws_secret_key
}
}
Periodic Backups While Running
Backup every N minutes while workspace is active:
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "b2:workspace-backups"
password = var.restic_password
# Backup every 30 minutes while workspace is running
backup_interval_minutes = 30
env = {
B2_ACCOUNT_ID = var.b2_account_id
B2_ACCOUNT_KEY = var.b2_account_key
}
}
Custom Stop Script
Run cleanup before backup:
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "s3:s3.amazonaws.com/backups"
password = var.restic_password
custom_stop_script = <<-EOF
#!/bin/bash
echo "Cleaning up before backup..."
rm -rf /tmp/*
docker system prune -f
find /home/coder -name "*.log" -delete
EOF
env = {
AWS_ACCESS_KEY_ID = var.aws_access_key
AWS_SECRET_ACCESS_KEY = var.aws_secret_key
}
}
Clone Another Workspace's Backup
Restore from a specific snapshot:
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "s3:s3.amazonaws.com/backups"
password = var.restic_password
# Restore from specific snapshot (find ID using: restic snapshots)
restore_on_start = true
snapshot_id = "abc123def" # The snapshot ID to restore
env = {
AWS_ACCESS_KEY_ID = var.aws_access_key
AWS_SECRET_ACCESS_KEY = var.aws_secret_key
}
}
To find snapshot IDs from another workspace:
# List all snapshots grouped by workspace
restic snapshots --group-by tags
# Or filter by specific workspace
restic snapshots --tag workspace-owner:john --tag workspace-name:dev-workspace
Custom Retention Policies
Control how many backups to keep:
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "s3:s3.amazonaws.com/backups"
password = var.restic_password
# Keep last 10 backups
retention_keep_last = 10
# Keep daily backups for 14 days
retention_keep_daily = 14
# Keep weekly backups for 8 weeks
retention_keep_weekly = 8
# Keep monthly backups for 6 months
retention_keep_monthly = 6
# Apply retention automatically
auto_forget = true
# Don't prune on stop (too slow)
auto_prune = false
env = {
AWS_ACCESS_KEY_ID = var.aws_access_key
AWS_SECRET_ACCESS_KEY = var.aws_secret_key
}
}
Using HCP Vault Secrets
Store credentials securely:
module "vault_secrets" {
source = "registry.coder.com/coder/hcp-vault-secrets/coder"
version = "1.0.34"
agent_id = coder_agent.main.id
app_name = "workspace-backups"
project_id = var.hcp_project_id
secrets = ["RESTIC_PASSWORD", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"]
}
module "restic" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/restic/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
repository = "s3:s3.amazonaws.com/backups"
password = "" # Will use RESTIC_PASSWORD from vault
depends_on = [module.vault_secrets]
}
Manual Operations
Trigger Manual Backup
Click the "Backup Now" button in the Coder UI, or run from terminal:
restic-backup --tag manual-backup
List Your Workspace's Backups
restic snapshots --tag workspace-id:$RESTIC_WORKSPACE_ID
Or view all snapshots:
restic snapshots
List All Workspace Backups in Repository
restic snapshots --group-by tags
This shows snapshots grouped by workspace, making it easy to see all workspace backups in the repository.
Restore Specific Snapshot
# List snapshots for this workspace
restic snapshots --tag workspace-id:$RESTIC_WORKSPACE_ID
# Restore to temporary location for inspection
restic restore /tmp/restore < snapshot-id > --target
# Or restore to original location
restic restore / < snapshot-id > --target
Check Repository Health
restic check
Manual Cleanup
# Remove old snapshots for this workspace
restic forget --tag workspace-id:$RESTIC_WORKSPACE_ID --keep-last 3
# Reclaim space (removes unreferenced data)
restic prune
Important Considerations
Stop Backup Limitations
Warning
: The
backup_on_stopfeature may not work on all template types if the agent is terminated before backup completes. See coder/coder#6174 for details.
Recommendations:
- Test stop backups with your specific template
- Keep backups fast (use selective paths and exclusions)
- Use
backup_interval_minutesfor important data - Set
auto_prune = falsefor stop backups (prune is slow)
Repository Organization
Single Shared Repository (Recommended):
- All workspaces share one repository
- Backups are tagged with workspace metadata
- Deduplication saves space
- Easy credential management
Per-Workspace Repositories:
- Each workspace uses separate repository
- More isolation but more complex
- No cross-workspace restore
Security
- Repository password encrypts ALL backups
- Use Coder parameters or external secrets for credentials
- Backend credentials should have minimal permissions
- Consider separate repositories for different teams
Performance Tips
- Use exclusions: Skip
.git,node_modules, caches - Selective paths: Only backup what you need
- Interval backups: Balance frequency vs performance
- Retention policies: Keep low retention to save storage costs
- Prune manually: Don't enable
auto_pruneon stop (too slow)
Troubleshooting
Backup Fails on Stop
The workspace might be terminating before backup completes. Try:
- Reducing backup size with selective paths
- Using interval backups instead
- Testing with a local repository first
Restore Blocks Login Too Long
- Reduce restore size with selective backup paths
- Set
start_blocks_login = falseto allow login during restore - Use faster storage backend
Repository Not Found
Ensure:
- Repository URL is correct
- Backend credentials are valid
- Network connectivity to storage backend
- Repository has been initialized (
auto_init_repo = true)
Permission Denied
Check:
- Backend credentials have write permissions
- Local directory (if used) is writable
- SSH key (for SFTP) is accessible
Out of Storage Space
Run cleanup:
restic forget --tag workspace-id:$RESTIC_WORKSPACE_ID --keep-last 2
restic prune