diff --git a/frontend-modern/src/components/Settings/QuickSecuritySetup.tsx b/frontend-modern/src/components/Settings/QuickSecuritySetup.tsx
index 350208e7f..47cbb9e73 100644
--- a/frontend-modern/src/components/Settings/QuickSecuritySetup.tsx
+++ b/frontend-modern/src/components/Settings/QuickSecuritySetup.tsx
@@ -69,12 +69,19 @@ export const QuickSecuritySetup: Component = () => {
setCredentials(newCredentials);
setShowCredentials(true);
- if (result.method === 'systemd' && result.willRestart) {
+ // Store the command if manual action needed
+ if (result.command) {
+ (window as any).securityCommand = result.command;
+ }
+
+ if (result.method === 'systemd' && result.automatic) {
showSuccess('Security enabled! Pulse will restart automatically in 2 seconds...');
// Show countdown
setTimeout(() => {
showSuccess('Restarting now... You will need to log in with your new credentials.');
}, 2000);
+ } else if (result.method === 'systemd' && !result.automatic) {
+ showSuccess('Security configured! Run the command shown below to apply settings.');
} else if (result.method === 'docker') {
showSuccess('Security configured! Please restart your Docker container with the credentials shown.');
} else {
@@ -251,12 +258,32 @@ Important:
-
- ✅ Security has been automatically enabled!
-
-
- Pulse will restart automatically in a few seconds. You'll need to log in with these credentials.
-
+
+
+ ✅ Security configured successfully!
+
+
+ Save your credentials above. Pulse will apply the security settings.
+
+ >
+ }
+ >
+
+ ✅ One more step to enable security:
+
+
+ Run this command in your terminal:
+
+
+ {(window as any).securityCommand}
+
+
+ This will apply the settings and restart Pulse with security enabled.
+
+
diff --git a/internal/api/router.go b/internal/api/router.go
index c750150af..165ee8a3c 100644
--- a/internal/api/router.go
+++ b/internal/api/router.go
@@ -267,16 +267,11 @@ func (r *Router) setupRoutes() {
isDocker := os.Getenv("PULSE_DOCKER") == "true"
if isSystemd {
- // We're running under systemd - create override file
- overridePath := "/etc/systemd/system/pulse-backend.service.d/override.conf"
- overrideDir := filepath.Dir(overridePath)
+ // We're running under systemd but may not have root permissions
+ // Write config to Pulse's data directory and provide a one-liner to apply it
- // Create override directory
- if err := os.MkdirAll(overrideDir, 0755); err != nil {
- log.Error().Err(err).Msg("Failed to create systemd override directory")
- http.Error(w, "Failed to create systemd configuration", http.StatusInternalServerError)
- return
- }
+ configPath := filepath.Join(r.config.DataPath, "security-override.conf")
+ scriptPath := filepath.Join(r.config.DataPath, "apply-security.sh")
// Create override content
overrideContent := fmt.Sprintf(`# Auto-generated by Pulse Quick Security Setup
@@ -288,30 +283,62 @@ Environment="API_TOKEN=%s"
Environment="ENABLE_AUDIT_LOG=true"
`, time.Now().Format(time.RFC3339), setupRequest.Username, setupRequest.Password, setupRequest.APIToken)
- // Write override file
- if err := os.WriteFile(overridePath, []byte(overrideContent), 0644); err != nil {
- log.Error().Err(err).Msg("Failed to write systemd override")
- http.Error(w, "Failed to write systemd configuration", http.StatusInternalServerError)
+ // Write override file to data directory
+ if err := os.WriteFile(configPath, []byte(overrideContent), 0644); err != nil {
+ log.Error().Err(err).Msg("Failed to write security config")
+ http.Error(w, "Failed to write security configuration", http.StatusInternalServerError)
return
}
- // Reload systemd and restart service
- if err := utils.RunCommand("systemctl", "daemon-reload"); err != nil {
- log.Error().Err(err).Msg("Failed to reload systemd")
+ // Create apply script
+ scriptContent := fmt.Sprintf(`#!/bin/bash
+# Auto-generated script to apply Pulse security settings
+echo "Applying security settings to Pulse..."
+sudo mkdir -p /etc/systemd/system/pulse-backend.service.d/
+sudo cp %s /etc/systemd/system/pulse-backend.service.d/override.conf
+sudo systemctl daemon-reload
+sudo systemctl restart pulse-backend
+echo "Security enabled! Pulse is restarting..."
+echo "You will need to log in with your saved credentials."
+`, configPath)
+
+ if err := os.WriteFile(scriptPath, []byte(scriptContent), 0755); err != nil {
+ log.Error().Err(err).Msg("Failed to write apply script")
}
- // Schedule restart after response (so user gets the credentials)
- go func() {
- time.Sleep(2 * time.Second)
- log.Info().Msg("Restarting Pulse to apply security settings...")
- utils.RunCommand("systemctl", "restart", "pulse-backend")
- }()
+ // Try to apply automatically (will only work if we have sudo permissions)
+ if err := utils.RunCommand("sudo", "mkdir", "-p", "/etc/systemd/system/pulse-backend.service.d/"); err == nil {
+ if err := utils.RunCommand("sudo", "cp", configPath, "/etc/systemd/system/pulse-backend.service.d/override.conf"); err == nil {
+ utils.RunCommand("sudo", "systemctl", "daemon-reload")
+ // Schedule restart
+ go func() {
+ time.Sleep(2 * time.Second)
+ log.Info().Msg("Restarting Pulse to apply security settings...")
+ utils.RunCommand("sudo", "systemctl", "restart", "pulse-backend")
+ }()
+
+ response := map[string]interface{}{
+ "success": true,
+ "method": "systemd",
+ "automatic": true,
+ "willRestart": true,
+ "message": "Security enabled! Pulse will restart in 2 seconds to apply settings.",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+ }
+ // If automatic didn't work, provide manual command
response := map[string]interface{}{
"success": true,
"method": "systemd",
- "willRestart": true,
- "message": "Security enabled! Pulse will restart in 2 seconds to apply settings.",
+ "automatic": false,
+ "configPath": configPath,
+ "scriptPath": scriptPath,
+ "command": fmt.Sprintf("sudo bash %s", scriptPath),
+ "message": "Security configured! Run the command shown to apply settings.",
}
w.Header().Set("Content-Type", "application/json")