diff --git a/frontend-modern/src/components/Settings/NodeModal.tsx b/frontend-modern/src/components/Settings/NodeModal.tsx
index 09e3cb8c5..089ac6e9b 100644
--- a/frontend-modern/src/components/Settings/NodeModal.tsx
+++ b/frontend-modern/src/components/Settings/NodeModal.tsx
@@ -35,6 +35,7 @@ export const NodeModal: Component = (props) => {
monitorContainers: true,
monitorStorage: true,
monitorBackups: true,
+ enableBackupManagement: true, // New field for backup write permissions
// PBS specific
monitorDatastores: true,
monitorSyncJobs: true,
@@ -62,6 +63,7 @@ export const NodeModal: Component = (props) => {
monitorContainers: (node.type === 'pve' && 'monitorContainers' in node ? node.monitorContainers : true) ?? true,
monitorStorage: (node.type === 'pve' && 'monitorStorage' in node ? node.monitorStorage : true) ?? true,
monitorBackups: (node.type === 'pve' && 'monitorBackups' in node ? node.monitorBackups : true) ?? true,
+ enableBackupManagement: true, // Default to true for existing nodes
monitorDatastores: (node.type === 'pbs' && 'monitorDatastores' in node ? node.monitorDatastores : true) ?? true,
monitorSyncJobs: (node.type === 'pbs' && 'monitorSyncJobs' in node ? node.monitorSyncJobs : true) ?? true,
monitorVerifyJobs: (node.type === 'pbs' && 'monitorVerifyJobs' in node ? node.monitorVerifyJobs : true) ?? true,
@@ -85,6 +87,7 @@ export const NodeModal: Component = (props) => {
monitorContainers: true,
monitorStorage: true,
monitorBackups: true,
+ enableBackupManagement: true,
monitorDatastores: true,
monitorSyncJobs: true,
monitorVerifyJobs: true,
@@ -407,6 +410,26 @@ export const NodeModal: Component = (props) => {
{/* Quick Setup Tab */}
+ {/* Backup Management Checkbox */}
+
+
+ setFormData({ ...formData(), enableBackupManagement: e.currentTarget.checked })}
+ class="rounded border-gray-300 dark:border-gray-600"
+ />
+
+ Enable backup management permissions
+
+
+
+ {formData().enableBackupManagement
+ ? 'Allows Pulse to manage PVE backups (create, delete, etc.) and display them in the Storage tab'
+ : 'Pulse will have read-only access. PVE backups will not appear in the Storage tab'}
+
+
+
Run this single command on your Proxmox VE server:
{/* One-liner command */}
@@ -417,7 +440,8 @@ export const NodeModal: Component = (props) => {
const hostValue = formData().host || '';
const encodedHost = encodeURIComponent(hostValue);
const pulseUrl = encodeURIComponent(window.location.origin);
- const scriptUrl = `${window.location.origin}/api/setup-script?type=pve&host=${encodedHost}&pulse_url=${pulseUrl}`;
+ const backupPerms = formData().enableBackupManagement ? '&backup_perms=true' : '';
+ const scriptUrl = `${window.location.origin}/api/setup-script?type=pve&host=${encodedHost}&pulse_url=${pulseUrl}${backupPerms}`;
const command = `curl -sSL "${scriptUrl}" | bash`;
if (await copyToClipboard(command)) {
showSuccess('Command copied! Run it on your server.');
@@ -437,7 +461,8 @@ export const NodeModal: Component = (props) => {
const hostValue = formData().host || '';
const encodedHost = encodeURIComponent(hostValue);
const pulseUrl = encodeURIComponent(window.location.origin);
- const scriptUrl = `${window.location.origin}/api/setup-script?type=pve&host=${encodedHost}&pulse_url=${pulseUrl}`;
+ const backupPerms = formData().enableBackupManagement ? '&backup_perms=true' : '';
+ const scriptUrl = `${window.location.origin}/api/setup-script?type=pve&host=${encodedHost}&pulse_url=${pulseUrl}${backupPerms}`;
const command = `curl -sSL "${scriptUrl}" | bash`;
return (
<>
@@ -462,7 +487,8 @@ export const NodeModal: Component = (props) => {
✨ New: The script now automatically configures Pulse - no manual token copying needed!
- Permissions granted: PVEAuditor (read-only) on root + PVEDatastoreAdmin (read/write for backups) on /storage
+ Permissions granted: PVEAuditor (read-only) on root
+ {formData().enableBackupManagement && ' + PVEDatastoreAdmin (read/write for backups) on /storage'}
diff --git a/internal/api/config_handlers.go b/internal/api/config_handlers.go
index e0495b4e4..7e7cbaaae 100644
--- a/internal/api/config_handlers.go
+++ b/internal/api/config_handlers.go
@@ -1484,6 +1484,7 @@ func (h *ConfigHandlers) HandleSetupScript(w http.ResponseWriter, r *http.Reques
serverType := query.Get("type") // "pve" or "pbs"
serverHost := query.Get("host")
pulseURL := query.Get("pulse_url") // URL of the Pulse server for auto-registration
+ backupPerms := query.Get("backup_perms") == "true" // Whether to add backup management permissions
// Default to PVE if not specified
if serverType == "" {
@@ -1518,6 +1519,12 @@ func (h *ConfigHandlers) HandleSetupScript(w http.ResponseWriter, r *http.Reques
var script string
if serverType == "pve" {
+ // Build storage permissions command if needed
+ storagePerms := ""
+ if backupPerms {
+ storagePerms = "\npveum aclmod /storage -user pulse-monitor@pam -role PVEDatastoreAdmin"
+ }
+
script = fmt.Sprintf(`#!/bin/bash
# Pulse Monitoring Setup Script for %s
# Generated: %s
@@ -1619,8 +1626,7 @@ fi
# Set up permissions
echo "Setting up permissions..."
-pveum aclmod / -user pulse-monitor@pam -role PVEAuditor
-pveum aclmod /storage -user pulse-monitor@pam -role PVEDatastoreAdmin
+pveum aclmod / -user pulse-monitor@pam -role PVEAuditor%s
echo ""
echo "✅ Setup complete!"
@@ -1634,7 +1640,7 @@ else
fi
echo " Host URL: %s"
echo ""
-`, serverName, time.Now().Format("2006-01-02 15:04:05"), pulseURL, serverHost, serverHost)
+`, serverName, time.Now().Format("2006-01-02 15:04:05"), pulseURL, serverHost, storagePerms, serverHost)
} else { // PBS
script = fmt.Sprintf(`#!/bin/bash