linting and SFTP volume support
This commit is contained in:
parent
5cdec5cdaa
commit
e4f66de447
3 changed files with 277 additions and 227 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import crypto from "node:crypto";
|
||||
import { eq, or } from "drizzle-orm";
|
||||
import { InternalServerError, NotFoundError } from "http-errors-enhanced";
|
||||
import { ConflictError, InternalServerError, NotFoundError } from "http-errors-enhanced";
|
||||
import { db } from "../../db/db";
|
||||
import { repositoriesTable } from "../../db/schema";
|
||||
import { toMessage } from "../../utils/errors";
|
||||
|
|
@ -74,7 +74,9 @@ const createRepository = async (name: string, config: RepositoryConfig, compress
|
|||
where: eq(repositoriesTable.shortId, shortId),
|
||||
});
|
||||
if (existingByShortId) {
|
||||
throw new ConflictError(`A repository with shortId '${shortId}' already exists. The shortId is used as the subdirectory name for local repositories.`);
|
||||
throw new ConflictError(
|
||||
`A repository with shortId '${shortId}' already exists. The shortId is used as the subdirectory name for local repositories.`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
shortId = generateShortId();
|
||||
|
|
@ -95,13 +97,13 @@ const createRepository = async (name: string, config: RepositoryConfig, compress
|
|||
if (repoExists && !config.isExistingRepository) {
|
||||
throw new ConflictError(
|
||||
`A restic repository already exists at this location. ` +
|
||||
`If you want to use the existing repository, set "isExistingRepository": true in the config.`
|
||||
`If you want to use the existing repository, set "isExistingRepository": true in the config.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!repoExists && config.isExistingRepository) {
|
||||
throw new InternalServerError(
|
||||
`Cannot access existing repository. Verify the path/credentials are correct and the repository exists.`
|
||||
`Cannot access existing repository. Verify the path/credentials are correct and the repository exists.`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -264,6 +264,43 @@ This example is intended to be the primary, copy/paste-friendly reference for co
|
|||
}
|
||||
```
|
||||
|
||||
#### SFTP
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "sftp-volume",
|
||||
"config": {
|
||||
"backend": "sftp",
|
||||
"host": "sftp.example.com",
|
||||
"port": 22,
|
||||
"username": "user",
|
||||
"password": "${SFTP_PASSWORD}",
|
||||
"path": "/data",
|
||||
"readOnly": false,
|
||||
"skipHostKeyCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For key-based authentication:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "sftp-volume-key",
|
||||
"config": {
|
||||
"backend": "sftp",
|
||||
"host": "sftp.example.com",
|
||||
"port": 22,
|
||||
"username": "user",
|
||||
"privateKey": "${SFTP_PRIVATE_KEY}",
|
||||
"path": "/data",
|
||||
"readOnly": false,
|
||||
"skipHostKeyCheck": false,
|
||||
"knownHosts": "sftp.example.com ssh-ed25519 AAAA..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Repository types
|
||||
|
||||
#### Local
|
||||
|
|
|
|||
|
|
@ -1,225 +1,236 @@
|
|||
{
|
||||
"volumes": [
|
||||
{
|
||||
"name": "local-volume",
|
||||
"config": {
|
||||
"backend": "directory",
|
||||
"path": "/mydata",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nfs-volume",
|
||||
"config": {
|
||||
"backend": "nfs",
|
||||
"server": "nfs.example.com",
|
||||
"exportPath": "/data",
|
||||
"port": 2049,
|
||||
"version": "4",
|
||||
"readOnly": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "smb-volume",
|
||||
"config": {
|
||||
"backend": "smb",
|
||||
"server": "smb.example.com",
|
||||
"share": "shared",
|
||||
"username": "user",
|
||||
"password": "${SMB_PASSWORD}",
|
||||
"vers": "3.0",
|
||||
"domain": "WORKGROUP",
|
||||
"port": 445,
|
||||
"readOnly": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "webdav-volume",
|
||||
"config": {
|
||||
"backend": "webdav",
|
||||
"server": "webdav.example.com",
|
||||
"path": "/remote.php/webdav",
|
||||
"username": "user",
|
||||
"password": "${WEBDAV_PASSWORD}",
|
||||
"port": 80,
|
||||
"readOnly": false,
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"repositories": [
|
||||
{
|
||||
"name": "local-repo",
|
||||
"config": {
|
||||
"backend": "local",
|
||||
"path": "/var/lib/zerobyte/repositories"
|
||||
},
|
||||
"compressionMode": "auto"
|
||||
},
|
||||
{
|
||||
"name": "s3-repo",
|
||||
"config": {
|
||||
"backend": "s3",
|
||||
"bucket": "mybucket",
|
||||
"accessKeyId": "${ACCESS_KEY_ID}",
|
||||
"secretAccessKey": "${SECRET_ACCESS_KEY}"
|
||||
},
|
||||
"compressionMode": "auto"
|
||||
},
|
||||
{
|
||||
"name": "gcs-repo",
|
||||
"config": {
|
||||
"backend": "gcs",
|
||||
"bucket": "mybucket",
|
||||
"projectId": "my-gcp-project",
|
||||
"credentialsJson": "${GCS_CREDENTIALS}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "azure-repo",
|
||||
"config": {
|
||||
"backend": "azure",
|
||||
"container": "mycontainer",
|
||||
"accountName": "myaccount",
|
||||
"accountKey": "${AZURE_KEY}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rclone-repo",
|
||||
"config": {
|
||||
"backend": "rclone",
|
||||
"remote": "myremote",
|
||||
"path": "backups/zerobyte"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "webdav-repo",
|
||||
"config": {
|
||||
"backend": "webdav",
|
||||
"server": "webdav.example.com",
|
||||
"path": "/remote.php/webdav",
|
||||
"username": "user",
|
||||
"password": "${WEBDAV_PASSWORD}",
|
||||
"port": 80,
|
||||
"ssl": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sftp-repo",
|
||||
"config": {
|
||||
"backend": "sftp",
|
||||
"host": "sftp.example.com",
|
||||
"port": 22,
|
||||
"user": "sftpuser",
|
||||
"privateKey": "${SFTP_PRIVATE_KEY}",
|
||||
"path": "/backups"
|
||||
}
|
||||
}
|
||||
],
|
||||
"backupSchedules": [
|
||||
{
|
||||
"name": "local-volume-local-repo",
|
||||
"volume": "local-volume",
|
||||
"repository": "local-repo",
|
||||
"cronExpression": "0 2 * * *",
|
||||
"retentionPolicy": { "keepLast": 7, "keepDaily": 7 },
|
||||
"includePatterns": ["important-folder"],
|
||||
"excludePatterns": ["*.tmp", "*.log"],
|
||||
"excludeIfPresent": [".nobackup"],
|
||||
"oneFileSystem": false,
|
||||
"enabled": true,
|
||||
"notifications": ["slack-alerts"],
|
||||
"mirrors": [
|
||||
{ "repository": "s3-repo" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"notificationDestinations": [
|
||||
{
|
||||
"name": "slack-alerts",
|
||||
"config": {
|
||||
"type": "slack",
|
||||
"webhookUrl": "${SLACK_WEBHOOK_URL}",
|
||||
"channel": "#backups",
|
||||
"username": "zerobyte",
|
||||
"iconEmoji": ":floppy_disk:"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "email-admin",
|
||||
"config": {
|
||||
"type": "email",
|
||||
"smtpHost": "smtp.example.com",
|
||||
"smtpPort": 587,
|
||||
"username": "admin@example.com",
|
||||
"password": "${EMAIL_PASSWORD}",
|
||||
"from": "zerobyte@example.com",
|
||||
"to": ["admin@example.com"],
|
||||
"useTLS": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "discord-backups",
|
||||
"config": {
|
||||
"type": "discord",
|
||||
"webhookUrl": "${DISCORD_WEBHOOK_URL}",
|
||||
"username": "zerobyte",
|
||||
"avatarUrl": "https://example.com/avatar.png",
|
||||
"threadId": "1234567890"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gotify-notify",
|
||||
"config": {
|
||||
"type": "gotify",
|
||||
"serverUrl": "https://gotify.example.com",
|
||||
"token": "${GOTIFY_TOKEN}",
|
||||
"path": "/message",
|
||||
"priority": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ntfy-notify",
|
||||
"config": {
|
||||
"type": "ntfy",
|
||||
"serverUrl": "https://ntfy.example.com",
|
||||
"topic": "zerobyte-backups",
|
||||
"priority": "high",
|
||||
"username": "ntfyuser",
|
||||
"password": "${NTFY_PASSWORD}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pushover-notify",
|
||||
"config": {
|
||||
"type": "pushover",
|
||||
"userKey": "${PUSHOVER_USER_KEY}",
|
||||
"apiToken": "${PUSHOVER_API_TOKEN}",
|
||||
"devices": "phone,tablet",
|
||||
"priority": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "telegram-notify",
|
||||
"config": {
|
||||
"type": "telegram",
|
||||
"botToken": "${TELEGRAM_BOT_TOKEN}",
|
||||
"chatId": "123456789"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "custom-shoutrrr",
|
||||
"config": {
|
||||
"type": "custom",
|
||||
"shoutrrrUrl": "${SHOUTRRR_URL}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"recoveryKey": "${RECOVERY_KEY}",
|
||||
"users": [
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "${ADMIN_PASSWORD}"
|
||||
}
|
||||
]
|
||||
"volumes": [
|
||||
{
|
||||
"name": "local-volume",
|
||||
"config": {
|
||||
"backend": "directory",
|
||||
"path": "/mydata",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nfs-volume",
|
||||
"config": {
|
||||
"backend": "nfs",
|
||||
"server": "nfs.example.com",
|
||||
"exportPath": "/data",
|
||||
"port": 2049,
|
||||
"version": "4",
|
||||
"readOnly": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "smb-volume",
|
||||
"config": {
|
||||
"backend": "smb",
|
||||
"server": "smb.example.com",
|
||||
"share": "shared",
|
||||
"username": "user",
|
||||
"password": "${SMB_PASSWORD}",
|
||||
"vers": "3.0",
|
||||
"domain": "WORKGROUP",
|
||||
"port": 445,
|
||||
"readOnly": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "webdav-volume",
|
||||
"config": {
|
||||
"backend": "webdav",
|
||||
"server": "webdav.example.com",
|
||||
"path": "/remote.php/webdav",
|
||||
"username": "user",
|
||||
"password": "${WEBDAV_PASSWORD}",
|
||||
"port": 80,
|
||||
"readOnly": false,
|
||||
"ssl": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sftp-volume",
|
||||
"config": {
|
||||
"backend": "sftp",
|
||||
"host": "sftp.example.com",
|
||||
"port": 22,
|
||||
"username": "user",
|
||||
"password": "${SFTP_PASSWORD}",
|
||||
"path": "/data",
|
||||
"readOnly": false,
|
||||
"skipHostKeyCheck": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"repositories": [
|
||||
{
|
||||
"name": "local-repo",
|
||||
"config": {
|
||||
"backend": "local",
|
||||
"path": "/var/lib/zerobyte/repositories"
|
||||
},
|
||||
"compressionMode": "auto"
|
||||
},
|
||||
{
|
||||
"name": "s3-repo",
|
||||
"config": {
|
||||
"backend": "s3",
|
||||
"bucket": "mybucket",
|
||||
"accessKeyId": "${ACCESS_KEY_ID}",
|
||||
"secretAccessKey": "${SECRET_ACCESS_KEY}"
|
||||
},
|
||||
"compressionMode": "auto"
|
||||
},
|
||||
{
|
||||
"name": "gcs-repo",
|
||||
"config": {
|
||||
"backend": "gcs",
|
||||
"bucket": "mybucket",
|
||||
"projectId": "my-gcp-project",
|
||||
"credentialsJson": "${GCS_CREDENTIALS}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "azure-repo",
|
||||
"config": {
|
||||
"backend": "azure",
|
||||
"container": "mycontainer",
|
||||
"accountName": "myaccount",
|
||||
"accountKey": "${AZURE_KEY}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rclone-repo",
|
||||
"config": {
|
||||
"backend": "rclone",
|
||||
"remote": "myremote",
|
||||
"path": "backups/zerobyte"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "webdav-repo",
|
||||
"config": {
|
||||
"backend": "webdav",
|
||||
"server": "webdav.example.com",
|
||||
"path": "/remote.php/webdav",
|
||||
"username": "user",
|
||||
"password": "${WEBDAV_PASSWORD}",
|
||||
"port": 80,
|
||||
"ssl": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sftp-repo",
|
||||
"config": {
|
||||
"backend": "sftp",
|
||||
"host": "sftp.example.com",
|
||||
"port": 22,
|
||||
"user": "sftpuser",
|
||||
"privateKey": "${SFTP_PRIVATE_KEY}",
|
||||
"path": "/backups"
|
||||
}
|
||||
}
|
||||
],
|
||||
"backupSchedules": [
|
||||
{
|
||||
"name": "local-volume-local-repo",
|
||||
"volume": "local-volume",
|
||||
"repository": "local-repo",
|
||||
"cronExpression": "0 2 * * *",
|
||||
"retentionPolicy": { "keepLast": 7, "keepDaily": 7 },
|
||||
"includePatterns": ["important-folder"],
|
||||
"excludePatterns": ["*.tmp", "*.log"],
|
||||
"excludeIfPresent": [".nobackup"],
|
||||
"oneFileSystem": false,
|
||||
"enabled": true,
|
||||
"notifications": ["slack-alerts"],
|
||||
"mirrors": [{ "repository": "s3-repo" }]
|
||||
}
|
||||
],
|
||||
"notificationDestinations": [
|
||||
{
|
||||
"name": "slack-alerts",
|
||||
"config": {
|
||||
"type": "slack",
|
||||
"webhookUrl": "${SLACK_WEBHOOK_URL}",
|
||||
"channel": "#backups",
|
||||
"username": "zerobyte",
|
||||
"iconEmoji": ":floppy_disk:"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "email-admin",
|
||||
"config": {
|
||||
"type": "email",
|
||||
"smtpHost": "smtp.example.com",
|
||||
"smtpPort": 587,
|
||||
"username": "admin@example.com",
|
||||
"password": "${EMAIL_PASSWORD}",
|
||||
"from": "zerobyte@example.com",
|
||||
"to": ["admin@example.com"],
|
||||
"useTLS": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "discord-backups",
|
||||
"config": {
|
||||
"type": "discord",
|
||||
"webhookUrl": "${DISCORD_WEBHOOK_URL}",
|
||||
"username": "zerobyte",
|
||||
"avatarUrl": "https://example.com/avatar.png",
|
||||
"threadId": "1234567890"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gotify-notify",
|
||||
"config": {
|
||||
"type": "gotify",
|
||||
"serverUrl": "https://gotify.example.com",
|
||||
"token": "${GOTIFY_TOKEN}",
|
||||
"path": "/message",
|
||||
"priority": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ntfy-notify",
|
||||
"config": {
|
||||
"type": "ntfy",
|
||||
"serverUrl": "https://ntfy.example.com",
|
||||
"topic": "zerobyte-backups",
|
||||
"priority": "high",
|
||||
"username": "ntfyuser",
|
||||
"password": "${NTFY_PASSWORD}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pushover-notify",
|
||||
"config": {
|
||||
"type": "pushover",
|
||||
"userKey": "${PUSHOVER_USER_KEY}",
|
||||
"apiToken": "${PUSHOVER_API_TOKEN}",
|
||||
"devices": "phone,tablet",
|
||||
"priority": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "telegram-notify",
|
||||
"config": {
|
||||
"type": "telegram",
|
||||
"botToken": "${TELEGRAM_BOT_TOKEN}",
|
||||
"chatId": "123456789"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "custom-shoutrrr",
|
||||
"config": {
|
||||
"type": "custom",
|
||||
"shoutrrrUrl": "${SHOUTRRR_URL}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"recoveryKey": "${RECOVERY_KEY}",
|
||||
"users": [
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "${ADMIN_PASSWORD}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue