diff --git a/CHANGES b/CHANGES
index dcc876988..e66cbe1b6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2677,4 +2677,5 @@
* dashboard: disable 2fa setup for external users
* filemanager: Always show app or volume name
* filemanager: fix logs button link
+* backups: add Contabo object storage
diff --git a/dashboard/src/js/client.js b/dashboard/src/js/client.js
index 8ca7e045e..ca9aa5f82 100644
--- a/dashboard/src/js/client.js
+++ b/dashboard/src/js/client.js
@@ -226,11 +226,19 @@ const REGIONS_VULTR = [
{ name: 'Singapore', value: 'https://sgp1.vultrobjects.com', region: 'ap-southeast-1' },
];
+// https://docs.contabo.com/docs/products/Object-Storage/s3-connection-settings
+const REGIONS_CONTABO = [
+ { name: 'European Union (Germany)', value: 'https://eu2.contabostorage.com' , region: 'us-east-1' },
+ { name: 'Singapore', value: 'https://sin1.contabostorage.com' , region: 'us-east-1' },
+ { name: 'United States', value: 'https://usc1.contabostorage.com' , region: 'us-east-1' }
+];
+
const STORAGE_PROVIDERS = [
{ name: 'Amazon S3', value: 's3' },
{ name: 'Backblaze B2 (S3 API)', value: 'backblaze-b2' },
{ name: 'CIFS Mount', value: 'cifs' },
{ name: 'Cloudflare R2', value: 'cloudflare-r2' },
+ { name: 'Contabo Object Storage', value: 'contabo-objectstorage' },
{ name: 'DigitalOcean Spaces', value: 'digitalocean-spaces' },
{ name: 'External/Local Disk (EXT4 or XFS)', value: 'disk' },
{ name: 'EXT4 Disk', value: 'ext4' },
diff --git a/dashboard/src/js/restore.js b/dashboard/src/js/restore.js
index 77bb53035..ea94099cb 100644
--- a/dashboard/src/js/restore.js
+++ b/dashboard/src/js/restore.js
@@ -1,7 +1,7 @@
'use strict';
/* global $, angular, tld, SECRET_PLACEHOLDER, 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_CONTABO */
// create main application module
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'angular-md5', 'ui-notification', 'ui.bootstrap']);
@@ -92,6 +92,7 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
$scope.ionosRegions = REGIONS_IONOS;
$scope.upcloudRegions = REGIONS_UPCLOUD;
$scope.vultrRegions = REGIONS_VULTR;
+ $scope.contaboRegions = REGIONS_CONTABO;
$scope.storageProviders = STORAGE_PROVIDERS;
@@ -101,7 +102,8 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
return provider === 's3' || provider === 'minio' || provider === 's3-v4-compat' || provider === 'exoscale-sos'
|| provider === 'digitalocean-spaces' || provider === 'wasabi' || provider === 'scaleway-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 === 'ionos-objectstorage' || provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2'
+ || provider === 'contabo-objectstorage';
};
$scope.mountlike = function (provider) {
@@ -158,6 +160,10 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
} else if (backupConfig.provider === 'vultr-objectstorage') {
backupConfig.region = $scope.vultrRegions.find(function (x) { return x.value === $scope.endpoint; }).region;
backupConfig.signatureVersion = 'v4';
+ } else if (backupConfig.provider === 'contabo-objectstorage') {
+ backupConfig.region = $scope.contaboRegions.find(function (x) { return x.value === $scope.endpoint; }).region;
+ backupConfig.signatureVersion = 'v4';
+ backupConfig.s3ForcePathStyle = true; // https://docs.contabo.com/docs/products/Object-Storage/technical-description (no virtual buckets)
} else if (backupConfig.provider === 'upcloud-objectstorage') {
var m = /^.*\.(.*)\.upcloudobjects.com$/.exec(backupConfig.endpoint);
backupConfig.region = m ? m[1] : 'us-east-1'; // let it fail in validation phase if m is not valid
diff --git a/dashboard/src/restore.html b/dashboard/src/restore.html
index f16e477a7..632c305ec 100644
--- a/dashboard/src/restore.html
+++ b/dashboard/src/restore.html
@@ -241,6 +241,11 @@
+
+
+
+
+
diff --git a/dashboard/src/views/app.html b/dashboard/src/views/app.html
index c217d5874..d60c69425 100644
--- a/dashboard/src/views/app.html
+++ b/dashboard/src/views/app.html
@@ -368,6 +368,11 @@
+
+
+
+
+
diff --git a/dashboard/src/views/app.js b/dashboard/src/views/app.js
index ee88251d8..b022e99ef 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_CONTABO */
angular.module('Application').controller('AppController', ['$scope', '$location', '$translate', '$timeout', '$interval', '$route', '$routeParams', 'Client', function ($scope, $location, $translate, $timeout, $interval, $route, $routeParams, Client) {
$scope.s3Regions = REGIONS_S3;
@@ -23,6 +23,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
$scope.ionosRegions = REGIONS_IONOS;
$scope.upcloudRegions = REGIONS_UPCLOUD;
$scope.vultrRegions = REGIONS_VULTR;
+ $scope.contaboRegions = REGIONS_VULTR;
$scope.storageProviders = STORAGE_PROVIDERS;
@@ -1307,7 +1308,8 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
|| provider === 'exoscale-sos' || provider === 'digitalocean-spaces'
|| 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';
+ || provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2'
+ || provider === 'contabo-objectstorage';
};
$scope.mountlike = function (provider) {
@@ -1405,6 +1407,10 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
} else if (backupConfig.provider === 'vultr-objectstorage') {
backupConfig.region = $scope.vultrRegions.find(function (x) { return x.value === $scope.importBackup.endpoint; }).region;
backupConfig.signatureVersion = 'v4';
+ } else if (backupConfig.provider === 'contabo-objectstorage') {
+ backupConfig.region = $scope.contaboRegions.find(function (x) { return x.value === $scope.importBackup.endpoint; }).region;
+ backupConfig.signatureVersion = 'v4';
+ backupConfig.s3ForcePathStyle = true; // https://docs.contabo.com/docs/products/Object-Storage/technical-description (no virtual buckets)
} else if (backupConfig.provider === 'upcloud-objectstorage') {
var m = /^.*\.(.*)\.upcloudobjects.com$/.exec(backupConfig.endpoint);
backupConfig.region = m ? m[1] : 'us-east-1'; // let it fail in validation phase if m is not valid
diff --git a/dashboard/src/views/backups.html b/dashboard/src/views/backups.html
index bbbc73ffb..4d1aecd3c 100644
--- a/dashboard/src/views/backups.html
+++ b/dashboard/src/views/backups.html
@@ -331,6 +331,11 @@
+
+
+
+
+
diff --git a/dashboard/src/views/backups.js b/dashboard/src/views/backups.js
index 6ac75afa4..ef6093e2e 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 */
+/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR , REGIONS_CONTABO */
angular.module('Application').controller('BackupsController', ['$scope', '$location', '$rootScope', '$timeout', 'Client', function ($scope, $location, $rootScope, $timeout, Client) {
Client.onReady(function () { if (!Client.getUserInfo().isAtLeastAdmin) $location.path('/'); });
@@ -30,6 +30,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
$scope.ionosRegions = REGIONS_IONOS;
$scope.upcloudRegions = REGIONS_UPCLOUD;
$scope.vultrRegions = REGIONS_VULTR;
+ $scope.contaboRegions = REGIONS_CONTABO;
$scope.storageProviders = STORAGE_PROVIDERS.concat([
{ name: 'No-op (Only for testing)', value: 'noop' }
@@ -269,7 +270,8 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|| provider === 'exoscale-sos' || provider === 'digitalocean-spaces'
|| 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';
+ || provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2'
+ || provider === 'contabo-objectstorage';
};
$scope.mountlike = function (provider) {
@@ -650,6 +652,10 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
} else if (backupConfig.provider === 'vultr-objectstorage') {
backupConfig.region = $scope.vultrRegions.find(function (x) { return x.value === $scope.configureBackup.endpoint; }).region;
backupConfig.signatureVersion = 'v4';
+ } else if (backupConfig.provider === 'contabo-objectstorage') {
+ backupConfig.region = $scope.contaboRegions.find(function (x) { return x.value === $scope.configureBackup.endpoint; }).region;
+ backupConfig.signatureVersion = 'v4';
+ backupConfig.s3ForcePathStyle = true; // https://docs.contabo.com/docs/products/Object-Storage/technical-description (no virtual buckets)
} else if (backupConfig.provider === 'upcloud-objectstorage') { // the UI sets region and endpoint
var m = /^.*\.(.*)\.upcloudobjects.com$/.exec(backupConfig.endpoint);
backupConfig.region = m ? m[1] : 'us-east-1'; // let it fail in validation phase if m is not valid
diff --git a/src/storage.js b/src/storage.js
index 84a2e88ee..0dc155239 100644
--- a/src/storage.js
+++ b/src/storage.js
@@ -30,6 +30,7 @@ function api(provider) {
case 'idrive-e2': return require('./storage/s3.js');
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 'noop': return require('./storage/noop.js');
default: return null;
}