summaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
authorClaus Lensbøl <claus@tailscale.com>2025-08-07 11:51:15 -0400
committerGitHub <noreply@github.com>2025-08-07 11:51:15 -0400
commit89954fbceb78a2ecff529166da66ebee614e4253 (patch)
tree3910d821fe0743f6ca9dc41ca3dca7a4d4717c3a /client
parent4666d4ca2af5885329a6546d14c890d08e65c82e (diff)
downloadtailscale-89954fbceb78a2ecff529166da66ebee614e4253.tar.xz
tailscale-89954fbceb78a2ecff529166da66ebee614e4253.zip
client/systray: add startup script generator for systemd (#16801)
Updates #1708 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
Diffstat (limited to 'client')
-rw-r--r--client/systray/startup-creator.go76
-rw-r--r--client/systray/tailscale-systray.service10
2 files changed, 86 insertions, 0 deletions
diff --git a/client/systray/startup-creator.go b/client/systray/startup-creator.go
new file mode 100644
index 000000000..cb354856d
--- /dev/null
+++ b/client/systray/startup-creator.go
@@ -0,0 +1,76 @@
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build cgo || !darwin
+
+// Package systray provides a minimal Tailscale systray application.
+package systray
+
+import (
+ "bufio"
+ "bytes"
+ _ "embed"
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+)
+
+//go:embed tailscale-systray.service
+var embedSystemd string
+
+func InstallStartupScript(initSystem string) error {
+ switch initSystem {
+ case "systemd":
+ return installSystemd()
+ default:
+ return fmt.Errorf("unsupported init system '%s'", initSystem)
+ }
+}
+
+func installSystemd() error {
+ // Find the path to tailscale, just in case it's not where the example file
+ // has it placed, and replace that before writing the file.
+ tailscaleBin, err := exec.LookPath("tailscale")
+ if err != nil {
+ return fmt.Errorf("failed to find tailscale binary %w", err)
+ }
+
+ var output bytes.Buffer
+ scanner := bufio.NewScanner(strings.NewReader(embedSystemd))
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.HasPrefix(line, "ExecStart=") {
+ line = fmt.Sprintf("ExecStart=%s systray", tailscaleBin)
+ }
+ output.WriteString(line + "\n")
+ }
+
+ configDir, err := os.UserConfigDir()
+ if err != nil {
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ return fmt.Errorf("unable to locate user home: %w", err)
+ }
+ configDir = filepath.Join(homeDir, ".config")
+ }
+
+ systemdDir := filepath.Join(configDir, "systemd", "user")
+ if err := os.MkdirAll(systemdDir, 0o755); err != nil {
+ return fmt.Errorf("failed creating systemd uuser dir: %w", err)
+ }
+
+ serviceFile := filepath.Join(systemdDir, "tailscale-systray.service")
+
+ if err := os.WriteFile(serviceFile, output.Bytes(), 0o755); err != nil {
+ return fmt.Errorf("failed writing systemd user service: %w", err)
+ }
+
+ fmt.Printf("Successfully installed systemd service to: %s\n", serviceFile)
+ fmt.Println("To enable and start the service, run:")
+ fmt.Println(" systemctl --user daemon-reload")
+ fmt.Println(" systemctl --user enable --now tailscale-systray")
+
+ return nil
+}
diff --git a/client/systray/tailscale-systray.service b/client/systray/tailscale-systray.service
new file mode 100644
index 000000000..a4d987563
--- /dev/null
+++ b/client/systray/tailscale-systray.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Tailscale System Tray
+After=systemd.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/tailscale systray
+
+[Install]
+WantedBy=default.target