diff --git a/CHANGES b/CHANGES
index 0774a6dd7..a0510fc1d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2851,3 +2851,6 @@
[8.0.6]
* Fix AdGuard resolving dashboard to docker bridge IP
+[8.1.0]
+* backups: add hetzner object storage
+
diff --git a/dashboard/src/js/client.js b/dashboard/src/js/client.js
index 20bd685a8..3d07997ab 100644
--- a/dashboard/src/js/client.js
+++ b/dashboard/src/js/client.js
@@ -167,6 +167,10 @@ const REGIONS_WASABI = [
{ name: 'Virginia (US East 2)', value: 'https://s3.us-east-2.wasabisys.com' }
];
+const REGIONS_HETZNER = [
+ { name: 'Falkenstein (FSN1)', value: 'https://fsn1.your-objectstorage.com' },
+];
+
// https://docs.digitalocean.com/products/platform/availability-matrix/
const REGIONS_DIGITALOCEAN = [
{ name: 'AMS3', value: 'https://ams3.digitaloceanspaces.com' },
@@ -292,6 +296,7 @@ const STORAGE_PROVIDERS = [
{ name: 'Filesystem', value: 'filesystem' },
{ name: 'Filesystem (Mountpoint)', value: 'mountpoint' }, // legacy
{ name: 'Google Cloud Storage', value: 'gcs' },
+ { name: 'Hetzner Object Storage', value: 'hetzner-objectstorage' },
{ name: 'IDrive e2', value: 'idrive-e2' },
{ name: 'IONOS (Profitbricks)', value: 'ionos-objectstorage' },
{ name: 'Linode Object Storage', value: 'linode-objectstorage' },
diff --git a/dashboard/src/js/restore.js b/dashboard/src/js/restore.js
index 2ea6c30a1..5984f9768 100644
--- a/dashboard/src/js/restore.js
+++ b/dashboard/src/js/restore.js
@@ -1,7 +1,7 @@
'use strict';
/* global $, angular, SECRET_PLACEHOLDER, STORAGE_PROVIDERS, BACKUP_FORMATS, window, FileReader, document, redirectIfNeeded */
-/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR, REGIONS_CONTABO */
+/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR, REGIONS_CONTABO, REGIONS_HETZNER */
// create main application module
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'angular-md5', 'ui-notification', 'ui.bootstrap']);
@@ -77,6 +77,7 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
$scope.s3Regions = REGIONS_S3;
$scope.wasabiRegions = REGIONS_WASABI;
$scope.doSpacesRegions = REGIONS_DIGITALOCEAN;
+ $scope.hetznerRegions = REGIONS_HETZNER;
$scope.exoscaleSosRegions = REGIONS_EXOSCALE;
$scope.scalewayRegions = REGIONS_SCALEWAY;
$scope.linodeRegions = REGIONS_LINODE;
@@ -92,7 +93,7 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
$scope.s3like = function (provider) {
return provider === 's3' || provider === 'minio' || provider === 's3-v4-compat' || provider === 'exoscale-sos'
- || provider === 'digitalocean-spaces' || provider === 'wasabi' || provider === 'scaleway-objectstorage'
+ || provider === 'digitalocean-spaces' || provider === 'wasabi' || provider === 'scaleway-objectstorage' || provider === 'hetzner-objectstorage'
|| provider === 'linode-objectstorage' || provider === 'ovh-objectstorage' || provider === 'backblaze-b2' || provider === 'cloudflare-r2'
|| provider === 'ionos-objectstorage' || provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2'
|| provider === 'contabo-objectstorage';
@@ -162,6 +163,9 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
backupConfig.signatureVersion = 'v4';
} else if (backupConfig.provider === 'digitalocean-spaces') {
backupConfig.region = 'us-east-1';
+ } else if (backupConfig.provider === 'hetzner-objectstorage') {
+ backupConfig.region = 'us-east-1';
+ backupConfig.signatureVersion = 'v4';
}
} else if (backupConfig.provider === 'gcs') {
backupConfig.bucket = $scope.bucket;
diff --git a/dashboard/src/restore.html b/dashboard/src/restore.html
index c4c367a3c..45413bfed 100644
--- a/dashboard/src/restore.html
+++ b/dashboard/src/restore.html
@@ -208,6 +208,11 @@
+
+
+
+
+
diff --git a/dashboard/src/views/app.html b/dashboard/src/views/app.html
index a16223bec..7597414e3 100644
--- a/dashboard/src/views/app.html
+++ b/dashboard/src/views/app.html
@@ -421,6 +421,11 @@
+
+
+
+
+
diff --git a/dashboard/src/views/app.js b/dashboard/src/views/app.js
index 142c1d3a9..43e4c4685 100644
--- a/dashboard/src/views/app.js
+++ b/dashboard/src/views/app.js
@@ -10,7 +10,7 @@
/* global Clipboard */
/* global SECRET_PLACEHOLDER */
/* global APP_TYPES, STORAGE_PROVIDERS, BACKUP_FORMATS */
-/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR */
+/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR, REGIONS_HETZNER */
/* global onAppClick */
angular.module('Application').controller('AppController', ['$scope', '$location', '$translate', '$timeout', '$interval', '$route', '$routeParams', 'Client', function ($scope, $location, $translate, $timeout, $interval, $route, $routeParams, Client) {
@@ -25,6 +25,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
$scope.upcloudRegions = REGIONS_UPCLOUD;
$scope.vultrRegions = REGIONS_VULTR;
$scope.contaboRegions = REGIONS_VULTR;
+ $scope.hetznerRegions = REGIONS_HETZNER;
$scope.storageProviders = STORAGE_PROVIDERS;
@@ -1425,7 +1426,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
$scope.s3like = function (provider) {
return provider === 's3' || provider === 'minio' || provider === 's3-v4-compat'
- || provider === 'exoscale-sos' || provider === 'digitalocean-spaces'
+ || provider === 'exoscale-sos' || provider === 'digitalocean-spaces' || provider === 'hetzner-objectstorage'
|| provider === 'scaleway-objectstorage' || provider === 'wasabi' || provider === 'backblaze-b2' || provider === 'cloudflare-r2'
|| provider === 'linode-objectstorage' || provider === 'ovh-objectstorage' || provider === 'ionos-objectstorage'
|| provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2'
@@ -1547,6 +1548,9 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
backupConfig.signatureVersion = 'v4';
} else if (backupConfig.provider === 'digitalocean-spaces') {
backupConfig.region = 'us-east-1';
+ } else if (backupConfig.provider === 'hetzner-objectstorage') {
+ backupConfig.region = 'us-east-1';
+ backupConfig.signatureVersion = 'v4';
}
} else if (backupConfig.provider === 'gcs') {
backupConfig.bucket = $scope.importBackup.bucket;
diff --git a/dashboard/src/views/backups.html b/dashboard/src/views/backups.html
index b6a9ac942..90d711809 100644
--- a/dashboard/src/views/backups.html
+++ b/dashboard/src/views/backups.html
@@ -302,6 +302,11 @@
+
+
+
+
+
diff --git a/dashboard/src/views/backups.js b/dashboard/src/views/backups.js
index 189601167..ba6cfcfd3 100644
--- a/dashboard/src/views/backups.js
+++ b/dashboard/src/views/backups.js
@@ -1,7 +1,7 @@
'use strict';
/* global $, angular, TASK_TYPES, SECRET_PLACEHOLDER, STORAGE_PROVIDERS, BACKUP_FORMATS, APP_TYPES */
-/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR , REGIONS_CONTABO */
+/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR , REGIONS_CONTABO, REGIONS_HETZNER */
/* global document, window, FileReader */
angular.module('Application').controller('BackupsController', ['$scope', '$location', '$rootScope', '$timeout', 'Client', function ($scope, $location, $rootScope, $timeout, Client) {
@@ -34,6 +34,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
$scope.upcloudRegions = REGIONS_UPCLOUD;
$scope.vultrRegions = REGIONS_VULTR;
$scope.contaboRegions = REGIONS_CONTABO;
+ $scope.hetznerRegions = REGIONS_HETZNER;
$scope.storageProviders = STORAGE_PROVIDERS.concat([
{ name: 'No-op (Only for testing)', value: 'noop' }
@@ -270,7 +271,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
$scope.s3like = function (provider) {
return provider === 's3' || provider === 'minio' || provider === 's3-v4-compat'
- || provider === 'exoscale-sos' || provider === 'digitalocean-spaces'
+ || provider === 'exoscale-sos' || provider === 'digitalocean-spaces' || provider === 'hetzner-objectstorage'
|| provider === 'scaleway-objectstorage' || provider === 'wasabi' || provider === 'backblaze-b2' || provider === 'cloudflare-r2'
|| provider === 'linode-objectstorage' || provider === 'ovh-objectstorage' || provider === 'ionos-objectstorage'
|| provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2'
@@ -653,6 +654,9 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
backupConfig.signatureVersion = 'v4';
} else if (backupConfig.provider === 'digitalocean-spaces') {
backupConfig.region = 'us-east-1';
+ } else if (backupConfig.provider === 'hetzner-objectstorage') {
+ backupConfig.region = 'us-east-1';
+ backupConfig.signatureVersion = 'v4';
}
backupConfig.limits.uploadPartSize = parseInt($scope.configureBackup.uploadPartSize);
diff --git a/src/storage.js b/src/storage.js
index 0dc155239..6c0a80351 100644
--- a/src/storage.js
+++ b/src/storage.js
@@ -31,6 +31,7 @@ function api(provider) {
case 'vultr-objectstorage': return require('./storage/s3.js');
case 'upcloud-objectstorage': return require('./storage/s3.js');
case 'contabo-objectstorage': return require('./storage/s3.js');
+ case 'hetzner-objectstorage': return require('./storage/s3.js');
case 'noop': return require('./storage/noop.js');
default: return null;
}