From bc9cbb36277f2fcc1a694c117ce6c53dd3d7279e Mon Sep 17 00:00:00 2001 From: anonpenguin23 Date: Sat, 14 Feb 2026 14:33:38 +0200 Subject: [PATCH] Moved everything to root user and to /opt/orama from home/orama/.orama --- README.md | 4 +- docs/CLEAN_NODE.md | 17 +- docs/COMMON_PROBLEMS.md | 8 +- docs/DEPLOYMENT_GUIDE.md | 4 +- docs/DEV_DEPLOY.md | 4 +- pkg/cli/production/install/orchestrator.go | 4 +- pkg/cli/production/install/remote.go | 7 +- pkg/cli/production/invite/command.go | 2 +- pkg/cli/production/lifecycle/pre_upgrade.go | 4 +- pkg/cli/production/migrate/command.go | 2 +- pkg/cli/production/status/command.go | 2 +- pkg/cli/production/uninstall/command.go | 6 +- pkg/cli/production/upgrade/orchestrator.go | 6 +- pkg/cli/utils/systemd.go | 2 +- pkg/deployments/process/manager.go | 27 +-- pkg/deployments/process/manager_test.go | 2 +- pkg/environments/production/config.go | 6 - pkg/environments/production/installers.go | 2 +- .../production/installers/caddy.go | 5 - .../production/installers/gateway.go | 4 +- .../production/installers/ipfs.go | 5 - .../production/installers/ipfs_cluster.go | 10 - .../production/installers/rqlite.go | 3 - pkg/environments/production/orchestrator.go | 67 +----- pkg/environments/production/paths.go | 14 ++ pkg/environments/production/provisioner.go | 217 ------------------ pkg/environments/production/services.go | 89 ------- pkg/environments/production/services_test.go | 8 +- pkg/environments/production/wireguard.go | 10 +- pkg/environments/templates/render_test.go | 2 +- .../templates/systemd_gateway.service | 9 - .../templates/systemd_ipfs.service | 6 - .../templates/systemd_ipfs_cluster.service | 6 - .../templates/systemd_node.service | 6 - .../templates/systemd_olric.service | 6 - pkg/gateway/handlers/join/handler.go | 6 +- pkg/gateway/https.go | 2 +- pkg/inspector/collector.go | 2 +- pkg/node/wireguard_sync.go | 4 +- pkg/rqlite/util.go | 2 +- pkg/systemd/manager.go | 18 +- scripts/check-node-health.sh | 2 +- scripts/clean-testnet.sh | 7 +- scripts/extract-deploy.sh | 17 +- scripts/migrate-to-opt.sh | 93 ++++++++ scripts/patches/fix-anyone-relay.sh | 2 +- scripts/recover-rqlite.sh | 4 +- systemd/orama-namespace-gateway@.service | 17 +- systemd/orama-namespace-olric@.service | 17 +- systemd/orama-namespace-rqlite@.service | 17 +- 50 files changed, 210 insertions(+), 576 deletions(-) create mode 100644 pkg/environments/production/paths.go create mode 100755 scripts/migrate-to-opt.sh diff --git a/README.md b/README.md index 5891492..61fa656 100644 --- a/README.md +++ b/README.md @@ -366,7 +366,7 @@ systemctl status orama-node journalctl -u orama-node -f # Check log files -tail -f /home/orama/.orama/logs/node.log +tail -f /opt/orama/.orama/logs/node.log ``` ### Port Conflicts @@ -398,7 +398,7 @@ rqlite -H localhost -p 5001 ```bash # Production reset (⚠️ DESTROYS DATA) sudo orama uninstall -sudo rm -rf /home/orama/.orama +sudo rm -rf /opt/orama/.orama sudo orama install ``` diff --git a/docs/CLEAN_NODE.md b/docs/CLEAN_NODE.md index 7484de9..d61f518 100644 --- a/docs/CLEAN_NODE.md +++ b/docs/CLEAN_NODE.md @@ -31,11 +31,12 @@ sudo ufw --force reset sudo ufw allow 22/tcp sudo ufw --force enable -# 5. Remove orama user and home directory +# 5. Remove orama data directory +sudo rm -rf /opt/orama + +# 6. Remove legacy orama user (if exists from old installs) sudo userdel -r orama 2>/dev/null sudo rm -rf /home/orama - -# 6. Remove sudoers files sudo rm -f /etc/sudoers.d/orama-access sudo rm -f /etc/sudoers.d/orama-deployments sudo rm -f /etc/sudoers.d/orama-wireguard @@ -62,14 +63,13 @@ echo "Node cleaned. Ready for fresh install." | Category | Paths | |----------|-------| -| **User** | `orama` system user and `/home/orama/` | -| **App data** | `/home/orama/.orama/` (configs, secrets, logs, IPFS, RQLite, Olric) | -| **Source code** | `/home/orama/src/` | -| **Binaries** | `/home/orama/bin/orama-node`, `/home/orama/bin/gateway` | +| **App data** | `/opt/orama/.orama/` (configs, secrets, logs, IPFS, RQLite, Olric) | +| **Source code** | `/opt/orama/src/` | +| **Binaries** | `/opt/orama/bin/orama-node`, `/opt/orama/bin/gateway` | | **Systemd** | `orama-*.service`, `coredns.service`, `caddy.service`, `orama-deploy-*.service` | | **WireGuard** | `/etc/wireguard/wg0.conf`, `wg-quick@wg0` systemd unit | | **Firewall** | All UFW rules (reset to default + SSH only) | -| **Sudoers** | `/etc/sudoers.d/orama-*` | +| **Legacy** | `orama` user, `/etc/sudoers.d/orama-*` (old installs only) | | **CoreDNS** | `/etc/coredns/Corefile` | | **Caddy** | `/etc/caddy/Caddyfile`, `/var/lib/caddy/` (TLS certs) | | **Anyone Relay** | `orama-anyone-relay.service`, `orama-anyone-client.service` | @@ -130,6 +130,7 @@ sudo wg-quick down wg0 2>/dev/null sudo systemctl disable wg-quick@wg0 2>/dev/null sudo rm -f /etc/wireguard/wg0.conf sudo ufw --force reset && sudo ufw allow 22/tcp && sudo ufw --force enable +sudo rm -rf /opt/orama sudo userdel -r orama 2>/dev/null sudo rm -rf /home/orama sudo rm -f /etc/sudoers.d/orama-access /etc/sudoers.d/orama-deployments /etc/sudoers.d/orama-wireguard diff --git a/docs/COMMON_PROBLEMS.md b/docs/COMMON_PROBLEMS.md index fadd44d..f54c938 100644 --- a/docs/COMMON_PROBLEMS.md +++ b/docs/COMMON_PROBLEMS.md @@ -41,7 +41,7 @@ You can find peer public keys with `wg show wg0`. Check the Olric config on each node: ```bash -cat /home/orama/.orama/data/namespaces//configs/olric-*.yaml +cat /opt/orama/.orama/data/namespaces//configs/olric-*.yaml ``` If `bindAddr` is `0.0.0.0`, the node will try to bind to IPv6 on dual-stack hosts, breaking memberlist gossip. @@ -69,7 +69,7 @@ If every UDP ping fails but TCP stream connections succeed, it's the WireGuard p **Fix:** Edit the gateway config manually: ```bash -vim /home/orama/.orama/data/namespaces//configs/gateway-*.yaml +vim /opt/orama/.orama/data/namespaces//configs/gateway-*.yaml ``` Add/fix: @@ -95,7 +95,7 @@ This was fixed in code, so new namespaces get the correct config. **Check:** ```bash -ls /home/orama/.orama/data/namespaces//cluster-state.json +ls /opt/orama/.orama/data/namespaces//cluster-state.json ``` If the file doesn't exist, the node can't restore the namespace. @@ -153,7 +153,7 @@ ssh -n user@host 'command' ## General Debugging Tips - **Always use `sudo orama prod restart`** instead of raw `systemctl` commands -- **Namespace data lives at:** `/home/orama/.orama/data/namespaces//` +- **Namespace data lives at:** `/opt/orama/.orama/data/namespaces//` - **Check service logs:** `journalctl -u orama-namespace-olric@.service --no-pager -n 50` - **Check WireGuard:** `wg show wg0` — look for recent handshakes and transfer bytes - **Check gateway health:** `curl http://localhost:/v1/health` from the node itself diff --git a/docs/DEPLOYMENT_GUIDE.md b/docs/DEPLOYMENT_GUIDE.md index 730f0eb..b7bf88b 100644 --- a/docs/DEPLOYMENT_GUIDE.md +++ b/docs/DEPLOYMENT_GUIDE.md @@ -369,7 +369,7 @@ orama db create my-database # Output: # ✅ Database created: my-database # Home Node: node-abc123 -# File Path: /home/orama/.orama/data/sqlite/your-namespace/my-database.db +# File Path: /opt/orama/.orama/data/sqlite/your-namespace/my-database.db ``` ### Executing Queries @@ -588,7 +588,7 @@ func main() { // DATABASE_NAME env var is automatically set by Orama dbPath := os.Getenv("DATABASE_PATH") if dbPath == "" { - dbPath = "/home/orama/.orama/data/sqlite/" + os.Getenv("NAMESPACE") + "/myapp-db.db" + dbPath = "/opt/orama/.orama/data/sqlite/" + os.Getenv("NAMESPACE") + "/myapp-db.db" } var err error diff --git a/docs/DEV_DEPLOY.md b/docs/DEV_DEPLOY.md index 61aff75..0eb380b 100644 --- a/docs/DEV_DEPLOY.md +++ b/docs/DEV_DEPLOY.md @@ -48,7 +48,7 @@ make build-linux The `orama install` command automatically: 1. Uploads the source archive via SCP -2. Extracts source to `/home/orama/src` and installs the CLI to `/usr/local/bin/orama` +2. Extracts source to `/opt/orama/src` and installs the CLI to `/usr/local/bin/orama` 3. Runs `orama install` on the VPS which builds all binaries from source (Go, CoreDNS, Caddy, Olric, etc.) ### Upgrading a Multi-Node Cluster (CRITICAL) @@ -112,7 +112,7 @@ If nodes get stuck in "Candidate" state or show "leader not found" errors: 3. On each other node, clear RQLite data and restart: ```bash sudo orama prod stop - sudo rm -rf /home/orama/.orama/data/rqlite + sudo rm -rf /opt/orama/.orama/data/rqlite sudo systemctl start orama-node ``` 4. The node should automatically rejoin using its configured `rqlite_join_address` diff --git a/pkg/cli/production/install/orchestrator.go b/pkg/cli/production/install/orchestrator.go index ce3e90b..17e1b92 100644 --- a/pkg/cli/production/install/orchestrator.go +++ b/pkg/cli/production/install/orchestrator.go @@ -30,8 +30,8 @@ type Orchestrator struct { // NewOrchestrator creates a new install orchestrator func NewOrchestrator(flags *Flags) (*Orchestrator, error) { - oramaHome := "/home/orama" - oramaDir := oramaHome + "/.orama" + oramaHome := production.OramaBase + oramaDir := production.OramaDir // Normalize peers peers, err := utils.NormalizePeers(flags.PeersStr) diff --git a/pkg/cli/production/install/remote.go b/pkg/cli/production/install/remote.go index 6c31705..09bc5c4 100644 --- a/pkg/cli/production/install/remote.go +++ b/pkg/cli/production/install/remote.go @@ -81,17 +81,14 @@ func (r *RemoteOrchestrator) extractOnVPS() error { // All other binaries are built from source on the VPS during install. extractCmd := r.sudoPrefix() + "bash -c '" + `ARCHIVE="/tmp/network-source.tar.gz" && ` + - `SRC_DIR="/home/orama/src" && ` + - `BIN_DIR="/home/orama/bin" && ` + - `id -u orama &>/dev/null || useradd -m -s /bin/bash orama && ` + + `SRC_DIR="/opt/orama/src" && ` + + `BIN_DIR="/opt/orama/bin" && ` + `rm -rf "$SRC_DIR" && mkdir -p "$SRC_DIR" "$BIN_DIR" && ` + `tar xzf "$ARCHIVE" -C "$SRC_DIR" && ` + - `chown -R orama:orama "$SRC_DIR" && ` + // Install pre-built CLI binary (only binary cross-compiled locally) `if [ -f "$SRC_DIR/bin-linux/orama" ]; then ` + `cp "$SRC_DIR/bin-linux/orama" /usr/local/bin/orama && ` + `chmod +x /usr/local/bin/orama; fi && ` + - `chown -R orama:orama "$BIN_DIR" && ` + `echo "Extract complete."` + "'" diff --git a/pkg/cli/production/invite/command.go b/pkg/cli/production/invite/command.go index 61da2ec..9234a02 100644 --- a/pkg/cli/production/invite/command.go +++ b/pkg/cli/production/invite/command.go @@ -68,7 +68,7 @@ func Handle(args []string) { // readNodeDomain reads the domain from the node config file func readNodeDomain() (string, error) { - configPath := "/home/orama/.orama/configs/node.yaml" + configPath := "/opt/orama/.orama/configs/node.yaml" data, err := os.ReadFile(configPath) if err != nil { return "", fmt.Errorf("read config: %w", err) diff --git a/pkg/cli/production/lifecycle/pre_upgrade.go b/pkg/cli/production/lifecycle/pre_upgrade.go index 16baf8e..0c81fe1 100644 --- a/pkg/cli/production/lifecycle/pre_upgrade.go +++ b/pkg/cli/production/lifecycle/pre_upgrade.go @@ -14,7 +14,7 @@ import ( ) const ( - maintenanceFlagPath = "/home/orama/.orama/maintenance.flag" + maintenanceFlagPath = "/opt/orama/.orama/maintenance.flag" ) // HandlePreUpgrade prepares the node for a safe rolling upgrade: @@ -83,7 +83,7 @@ func HandlePreUpgrade() { // getNamespaceRQLitePorts scans namespace env files to find RQLite HTTP ports. // Returns map of namespace_name → HTTP port. func getNamespaceRQLitePorts() map[string]int { - namespacesDir := "/home/orama/.orama/data/namespaces" + namespacesDir := "/opt/orama/.orama/data/namespaces" ports := make(map[string]int) entries, err := os.ReadDir(namespacesDir) diff --git a/pkg/cli/production/migrate/command.go b/pkg/cli/production/migrate/command.go index 6543b51..0c12eb3 100644 --- a/pkg/cli/production/migrate/command.go +++ b/pkg/cli/production/migrate/command.go @@ -28,7 +28,7 @@ func Handle(args []string) { os.Exit(1) } - oramaDir := "/home/orama/.orama" + oramaDir := "/opt/orama/.orama" fmt.Printf("🔄 Checking for installations to migrate...\n\n") diff --git a/pkg/cli/production/status/command.go b/pkg/cli/production/status/command.go index 40883ce..b3046d9 100644 --- a/pkg/cli/production/status/command.go +++ b/pkg/cli/production/status/command.go @@ -47,7 +47,7 @@ func Handle() { } fmt.Printf("\nDirectories:\n") - oramaDir := "/home/orama/.orama" + oramaDir := "/opt/orama/.orama" if _, err := os.Stat(oramaDir); err == nil { fmt.Printf(" ✅ %s exists\n", oramaDir) } else { diff --git a/pkg/cli/production/uninstall/command.go b/pkg/cli/production/uninstall/command.go index 3ab0253..463335c 100644 --- a/pkg/cli/production/uninstall/command.go +++ b/pkg/cli/production/uninstall/command.go @@ -17,7 +17,7 @@ func Handle() { } fmt.Printf("⚠️ This will stop and remove all Orama production services\n") - fmt.Printf("⚠️ Configuration and data will be preserved in /home/orama/.orama\n\n") + fmt.Printf("⚠️ Configuration and data will be preserved in /opt/orama/.orama\n\n") fmt.Printf("Continue? (yes/no): ") reader := bufio.NewReader(os.Stdin) @@ -48,6 +48,6 @@ func Handle() { exec.Command("systemctl", "daemon-reload").Run() fmt.Printf("✅ Services uninstalled\n") - fmt.Printf(" Configuration and data preserved in /home/orama/.orama\n") - fmt.Printf(" To remove all data: rm -rf /home/orama/.orama\n\n") + fmt.Printf(" Configuration and data preserved in /opt/orama/.orama\n") + fmt.Printf(" To remove all data: rm -rf /opt/orama/.orama\n\n") } diff --git a/pkg/cli/production/upgrade/orchestrator.go b/pkg/cli/production/upgrade/orchestrator.go index 70c2845..b2baec9 100644 --- a/pkg/cli/production/upgrade/orchestrator.go +++ b/pkg/cli/production/upgrade/orchestrator.go @@ -26,8 +26,8 @@ type Orchestrator struct { // NewOrchestrator creates a new upgrade orchestrator func NewOrchestrator(flags *Flags) *Orchestrator { - oramaHome := "/home/orama" - oramaDir := oramaHome + "/.orama" + oramaHome := production.OramaBase + oramaDir := production.OramaDir // Load existing preferences prefs := production.LoadPreferences(oramaDir) @@ -341,7 +341,7 @@ func (o *Orchestrator) writePeersJSONFromState(state ClusterState) error { } // Write to RQLite's raft directory - raftDir := filepath.Join(o.oramaHome, ".orama", "data", "rqlite", "raft") + raftDir := filepath.Join(production.OramaData, "rqlite", "raft") if err := os.MkdirAll(raftDir, 0755); err != nil { return err } diff --git a/pkg/cli/utils/systemd.go b/pkg/cli/utils/systemd.go index e35a2ff..1799a69 100644 --- a/pkg/cli/utils/systemd.go +++ b/pkg/cli/utils/systemd.go @@ -182,7 +182,7 @@ func GetProductionServices() []string { // template files (e.g. orama-namespace-gateway@.service) with no instance name. // Restarting a template without an instance is a no-op. // Instead, scan the data directory where each subdirectory is a provisioned namespace. - namespacesDir := "/home/orama/.orama/data/namespaces" + namespacesDir := "/opt/orama/.orama/data/namespaces" nsEntries, err := os.ReadDir(namespacesDir) if err == nil { serviceTypes := []string{"rqlite", "olric", "gateway"} diff --git a/pkg/deployments/process/manager.go b/pkg/deployments/process/manager.go index cea60cd..7e81744 100644 --- a/pkg/deployments/process/manager.go +++ b/pkg/deployments/process/manager.go @@ -178,9 +178,9 @@ func (m *Manager) Stop(ctx context.Context, deployment *deployments.Deployment) m.logger.Warn("Failed to disable service", zap.Error(err)) } - // Remove service file using sudo + // Remove service file serviceFile := filepath.Join("/etc/systemd/system", serviceName+".service") - cmd := exec.Command("sudo", "rm", "-f", serviceFile) + cmd := exec.Command("rm", "-f", serviceFile) if err := cmd.Run(); err != nil { m.logger.Warn("Failed to remove service file", zap.Error(err)) } @@ -310,8 +310,6 @@ After=network.target [Service] Type=simple -User=orama -Group=orama WorkingDirectory={{.WorkDir}} {{range .Env}}Environment="{{.}}" @@ -328,9 +326,6 @@ CPUQuota={{.CPULimitPercent}}% # Security - minimal restrictions for deployments in home directory PrivateTmp=true -ProtectSystem=full -ProtectHome=read-only -ReadWritePaths={{.WorkDir}} StandardOutput=journal StandardError=journal @@ -373,8 +368,8 @@ WantedBy=multi-user.target return err } - // Use sudo tee to write to systemd directory (orama user needs sudo access) - cmd := exec.Command("sudo", "tee", serviceFile) + // Use tee to write to systemd directory + cmd := exec.Command("tee", serviceFile) cmd.Stdin = &buf output, err := cmd.CombinedOutput() if err != nil { @@ -436,34 +431,34 @@ func (m *Manager) getServiceName(deployment *deployments.Deployment) string { return fmt.Sprintf("orama-deploy-%s-%s", namespace, name) } -// systemd helper methods (use sudo for non-root execution) +// systemd helper methods func (m *Manager) systemdReload() error { - cmd := exec.Command("sudo", "systemctl", "daemon-reload") + cmd := exec.Command("systemctl", "daemon-reload") return cmd.Run() } func (m *Manager) systemdEnable(serviceName string) error { - cmd := exec.Command("sudo", "systemctl", "enable", serviceName) + cmd := exec.Command("systemctl", "enable", serviceName) return cmd.Run() } func (m *Manager) systemdDisable(serviceName string) error { - cmd := exec.Command("sudo", "systemctl", "disable", serviceName) + cmd := exec.Command("systemctl", "disable", serviceName) return cmd.Run() } func (m *Manager) systemdStart(serviceName string) error { - cmd := exec.Command("sudo", "systemctl", "start", serviceName) + cmd := exec.Command("systemctl", "start", serviceName) return cmd.Run() } func (m *Manager) systemdStop(serviceName string) error { - cmd := exec.Command("sudo", "systemctl", "stop", serviceName) + cmd := exec.Command("systemctl", "stop", serviceName) return cmd.Run() } func (m *Manager) systemdRestart(serviceName string) error { - cmd := exec.Command("sudo", "systemctl", "restart", serviceName) + cmd := exec.Command("systemctl", "restart", serviceName) return cmd.Run() } diff --git a/pkg/deployments/process/manager_test.go b/pkg/deployments/process/manager_test.go index 9f9ba4b..285c781 100644 --- a/pkg/deployments/process/manager_test.go +++ b/pkg/deployments/process/manager_test.go @@ -91,7 +91,7 @@ func TestGetStartCommand(t *testing.T) { // On macOS (test environment), useSystemd will be false, so node/npm use short paths. // We explicitly set it to test both modes. - workDir := "/home/orama/deployments/alice/myapp" + workDir := "/opt/orama/deployments/alice/myapp" tests := []struct { name string diff --git a/pkg/environments/production/config.go b/pkg/environments/production/config.go index 7c601ea..786ab2b 100644 --- a/pkg/environments/production/config.go +++ b/pkg/environments/production/config.go @@ -6,7 +6,6 @@ import ( "fmt" "net" "os" - "os/exec" "os/user" "path/filepath" "strconv" @@ -438,10 +437,5 @@ func (sg *SecretGenerator) SaveConfig(filename string, content string) error { return fmt.Errorf("failed to write config %s: %w", filename, err) } - // Fix ownership - if err := exec.Command("chown", "orama:orama", configPath).Run(); err != nil { - fmt.Printf("Warning: failed to chown %s to orama:orama: %v\n", configPath, err) - } - return nil } diff --git a/pkg/environments/production/installers.go b/pkg/environments/production/installers.go index 032c3e7..a1b72d6 100644 --- a/pkg/environments/production/installers.go +++ b/pkg/environments/production/installers.go @@ -27,7 +27,7 @@ type BinaryInstaller struct { // NewBinaryInstaller creates a new binary installer func NewBinaryInstaller(arch string, logWriter io.Writer) *BinaryInstaller { - oramaHome := "/home/orama" + oramaHome := OramaBase return &BinaryInstaller{ arch: arch, logWriter: logWriter, diff --git a/pkg/environments/production/installers/caddy.go b/pkg/environments/production/installers/caddy.go index ac9f5e0..88eb7f2 100644 --- a/pkg/environments/production/installers/caddy.go +++ b/pkg/environments/production/installers/caddy.go @@ -150,11 +150,6 @@ func (ci *CaddyInstaller) Install() error { return fmt.Errorf("failed to install binary: %w", err) } - // Grant CAP_NET_BIND_SERVICE to allow binding to ports 80/443 - if err := exec.Command("setcap", "cap_net_bind_service=+ep", dstBinary).Run(); err != nil { - fmt.Fprintf(ci.logWriter, " ⚠️ Warning: failed to setcap on caddy: %v\n", err) - } - fmt.Fprintf(ci.logWriter, " ✓ Caddy with orama DNS module installed\n") return nil } diff --git a/pkg/environments/production/installers/gateway.go b/pkg/environments/production/installers/gateway.go index 2c9c2a6..a98fd36 100644 --- a/pkg/environments/production/installers/gateway.go +++ b/pkg/environments/production/installers/gateway.go @@ -39,7 +39,7 @@ func (gi *GatewayInstaller) Configure() error { return nil } -// InstallDeBrosBinaries builds Orama binaries from source at /home/orama/src. +// InstallDeBrosBinaries builds Orama binaries from source at /opt/orama/src. // Source must already be present (uploaded via SCP archive). func (gi *GatewayInstaller) InstallDeBrosBinaries(oramaHome string) error { fmt.Fprintf(gi.logWriter, " Building Orama binaries...\n") @@ -217,7 +217,7 @@ func (gi *GatewayInstaller) InstallAnyoneClient() error { fmt.Fprintf(gi.logWriter, " Initializing NPM cache...\n") // Create nested cache directories with proper permissions - oramaHome := "/home/orama" + oramaHome := "/opt/orama" npmCacheDirs := []string{ filepath.Join(oramaHome, ".npm"), filepath.Join(oramaHome, ".npm", "_cacache"), diff --git a/pkg/environments/production/installers/ipfs.go b/pkg/environments/production/installers/ipfs.go index 1520e3c..f1c32c6 100644 --- a/pkg/environments/production/installers/ipfs.go +++ b/pkg/environments/production/installers/ipfs.go @@ -216,11 +216,6 @@ func (ii *IPFSInstaller) InitializeRepo(ipfsRepoPath string, swarmKeyPath string } } - // Fix ownership (best-effort, don't fail if it doesn't work) - if err := exec.Command("chown", "-R", "orama:orama", ipfsRepoPath).Run(); err != nil { - fmt.Fprintf(ii.logWriter, " ⚠️ Warning: failed to chown IPFS repo: %v\n", err) - } - return nil } diff --git a/pkg/environments/production/installers/ipfs_cluster.go b/pkg/environments/production/installers/ipfs_cluster.go index 3dfaef9..23f695b 100644 --- a/pkg/environments/production/installers/ipfs_cluster.go +++ b/pkg/environments/production/installers/ipfs_cluster.go @@ -76,11 +76,6 @@ func (ici *IPFSClusterInstaller) InitializeConfig(clusterPath, clusterSecret str return fmt.Errorf("failed to create IPFS Cluster directory: %w", err) } - // Fix ownership before running init (best-effort) - if err := exec.Command("chown", "-R", "orama:orama", clusterPath).Run(); err != nil { - fmt.Fprintf(ici.logWriter, " ⚠️ Warning: failed to chown cluster path before init: %v\n", err) - } - // Resolve ipfs-cluster-service binary path clusterBinary, err := ResolveBinaryPath("ipfs-cluster-service", "/usr/local/bin/ipfs-cluster-service", "/usr/bin/ipfs-cluster-service") if err != nil { @@ -119,11 +114,6 @@ func (ici *IPFSClusterInstaller) InitializeConfig(clusterPath, clusterSecret str fmt.Fprintf(ici.logWriter, " ✓ Cluster secret verified\n") } - // Fix ownership again after updates (best-effort) - if err := exec.Command("chown", "-R", "orama:orama", clusterPath).Run(); err != nil { - fmt.Fprintf(ici.logWriter, " ⚠️ Warning: failed to chown cluster path after updates: %v\n", err) - } - return nil } diff --git a/pkg/environments/production/installers/rqlite.go b/pkg/environments/production/installers/rqlite.go index 82747c4..ea2bed6 100644 --- a/pkg/environments/production/installers/rqlite.go +++ b/pkg/environments/production/installers/rqlite.go @@ -79,8 +79,5 @@ func (ri *RQLiteInstaller) InitializeDataDir(dataDir string) error { return fmt.Errorf("failed to create RQLite data directory: %w", err) } - if err := exec.Command("chown", "-R", "orama:orama", dataDir).Run(); err != nil { - fmt.Fprintf(ri.logWriter, " ⚠️ Warning: failed to chown RQLite data dir: %v\n", err) - } return nil } diff --git a/pkg/environments/production/orchestrator.go b/pkg/environments/production/orchestrator.go index 96ea0c3..8c212ca 100644 --- a/pkg/environments/production/orchestrator.go +++ b/pkg/environments/production/orchestrator.go @@ -45,7 +45,6 @@ type ProductionSetup struct { resourceChecker *ResourceChecker portChecker *PortChecker fsProvisioner *FilesystemProvisioner - userProvisioner *UserProvisioner stateDetector *StateDetector configGenerator *ConfigGenerator secretGenerator *SecretGenerator @@ -78,7 +77,6 @@ func SaveBranchPreference(oramaDir, branch string) error { if err := os.WriteFile(branchFile, []byte(branch), 0644); err != nil { return fmt.Errorf("failed to save branch preference: %w", err) } - exec.Command("chown", "orama:orama", branchFile).Run() return nil } @@ -100,7 +98,6 @@ func NewProductionSetup(oramaHome string, logWriter io.Writer, forceReconfigure resourceChecker: NewResourceChecker(), portChecker: NewPortChecker(), fsProvisioner: NewFilesystemProvisioner(oramaHome), - userProvisioner: NewUserProvisioner("orama", oramaHome, "/bin/bash"), stateDetector: NewStateDetector(oramaDir), configGenerator: NewConfigGenerator(oramaDir), secretGenerator: NewSecretGenerator(oramaDir), @@ -227,63 +224,16 @@ func (ps *ProductionSetup) Phase1CheckPrerequisites() error { return nil } -// Phase2ProvisionEnvironment sets up users and filesystems +// Phase2ProvisionEnvironment sets up filesystems func (ps *ProductionSetup) Phase2ProvisionEnvironment() error { ps.logf("Phase 2: Provisioning environment...") - // Create orama user - if !ps.userProvisioner.UserExists() { - if err := ps.userProvisioner.CreateUser(); err != nil { - return fmt.Errorf("failed to create orama user: %w", err) - } - ps.logf(" ✓ Created 'orama' user") - } else { - ps.logf(" ✓ 'orama' user already exists") - } - - // Set up sudoers access if invoked via sudo - sudoUser := os.Getenv("SUDO_USER") - if sudoUser != "" { - if err := ps.userProvisioner.SetupSudoersAccess(sudoUser); err != nil { - ps.logf(" ⚠️ Failed to setup sudoers: %v", err) - } else { - ps.logf(" ✓ Sudoers access configured") - } - } - - // Set up deployment sudoers (allows orama user to manage orama-deploy-* services) - if err := ps.userProvisioner.SetupDeploymentSudoers(); err != nil { - ps.logf(" ⚠️ Failed to setup deployment sudoers: %v", err) - } else { - ps.logf(" ✓ Deployment sudoers configured") - } - - // Set up namespace sudoers (allows orama user to manage orama-namespace-* services) - if err := ps.userProvisioner.SetupNamespaceSudoers(); err != nil { - ps.logf(" ⚠️ Failed to setup namespace sudoers: %v", err) - } else { - ps.logf(" ✓ Namespace sudoers configured") - } - - // Set up WireGuard sudoers (allows orama user to manage WG peers) - if err := ps.userProvisioner.SetupWireGuardSudoers(); err != nil { - ps.logf(" ⚠️ Failed to setup wireguard sudoers: %v", err) - } else { - ps.logf(" ✓ WireGuard sudoers configured") - } - // Create directory structure (unified structure) if err := ps.fsProvisioner.EnsureDirectoryStructure(); err != nil { return fmt.Errorf("failed to create directory structure: %w", err) } ps.logf(" ✓ Directory structure created") - // Fix ownership - if err := ps.fsProvisioner.FixOwnership(); err != nil { - return fmt.Errorf("failed to fix ownership: %w", err) - } - ps.logf(" ✓ Ownership fixed") - return nil } @@ -305,7 +255,7 @@ func (ps *ProductionSetup) Phase2bInstallBinaries() error { ps.logf(" ⚠️ Olric install warning: %v", err) } - // Install Orama binaries (source must be at /home/orama/src via SCP) + // Install Orama binaries (source must be at /opt/orama/src via SCP) if err := ps.binaryInstaller.InstallDeBrosBinaries(ps.oramaHome); err != nil { return fmt.Errorf("failed to install Orama binaries: %w", err) } @@ -470,12 +420,6 @@ func (ps *ProductionSetup) Phase2cInitializeServices(peerAddresses []string, vps ps.logf(" ⚠️ RQLite initialization warning: %v", err) } - // Ensure all directories and files created during service initialization have correct ownership - // This is critical because directories/files created as root need to be owned by orama user - if err := ps.fsProvisioner.FixOwnership(); err != nil { - return fmt.Errorf("failed to fix ownership after service initialization: %w", err) - } - ps.logf(" ✓ Services initialized") return nil } @@ -564,7 +508,6 @@ func (ps *ProductionSetup) Phase4GenerateConfigs(peerAddresses []string, vpsIP s if err := os.WriteFile(olricConfigPath, []byte(olricConfig), 0644); err != nil { return fmt.Errorf("failed to save olric config: %w", err) } - exec.Command("chown", "orama:orama", olricConfigPath).Run() ps.logf(" ✓ Olric config generated") // Configure CoreDNS (if baseDomain is provided - this is the zone name) @@ -690,12 +633,8 @@ func (ps *ProductionSetup) Phase5CreateSystemdServices(enableHTTPS bool) error { // Caddy service on ALL nodes (any node may host namespaces and need TLS) if _, err := os.Stat("/usr/bin/caddy"); err == nil { - // Create caddy user if it doesn't exist - exec.Command("useradd", "-r", "-m", "-d", "/home/caddy", "-s", "/sbin/nologin", "caddy").Run() + // Create caddy data directory exec.Command("mkdir", "-p", "/var/lib/caddy").Run() - exec.Command("chown", "caddy:caddy", "/var/lib/caddy").Run() - exec.Command("mkdir", "-p", "/home/caddy").Run() - exec.Command("chown", "caddy:caddy", "/home/caddy").Run() caddyUnit := ps.serviceGenerator.GenerateCaddyService() if err := ps.serviceController.WriteServiceUnit("caddy.service", caddyUnit); err != nil { diff --git a/pkg/environments/production/paths.go b/pkg/environments/production/paths.go new file mode 100644 index 0000000..07e38a9 --- /dev/null +++ b/pkg/environments/production/paths.go @@ -0,0 +1,14 @@ +package production + +// Central path constants for the Orama Network production environment. +// All services run as root with /opt/orama as the base directory. +const ( + OramaBase = "/opt/orama" + OramaBinDir = "/opt/orama/bin" + OramaSrcDir = "/opt/orama/src" + OramaDir = "/opt/orama/.orama" + OramaConfigs = "/opt/orama/.orama/configs" + OramaSecrets = "/opt/orama/.orama/secrets" + OramaData = "/opt/orama/.orama/data" + OramaLogs = "/opt/orama/.orama/logs" +) diff --git a/pkg/environments/production/provisioner.go b/pkg/environments/production/provisioner.go index 6b54ed9..259e213 100644 --- a/pkg/environments/production/provisioner.go +++ b/pkg/environments/production/provisioner.go @@ -81,223 +81,6 @@ func (fp *FilesystemProvisioner) EnsureDirectoryStructure() error { return nil } -// FixOwnership changes ownership of .orama directory to orama user -func (fp *FilesystemProvisioner) FixOwnership() error { - // Fix entire .orama directory recursively (includes all data, configs, logs, etc.) - cmd := exec.Command("chown", "-R", "orama:orama", fp.oramaDir) - if output, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("failed to set ownership for %s: %w\nOutput: %s", fp.oramaDir, err, string(output)) - } - - // Also fix home directory ownership - cmd = exec.Command("chown", "orama:orama", fp.oramaHome) - if output, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("failed to set ownership for %s: %w\nOutput: %s", fp.oramaHome, err, string(output)) - } - - // Fix bin directory - binDir := filepath.Join(fp.oramaHome, "bin") - cmd = exec.Command("chown", "-R", "orama:orama", binDir) - if output, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("failed to set ownership for %s: %w\nOutput: %s", binDir, err, string(output)) - } - - // Fix npm cache directory - npmDir := filepath.Join(fp.oramaHome, ".npm") - cmd = exec.Command("chown", "-R", "orama:orama", npmDir) - if output, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("failed to set ownership for %s: %w\nOutput: %s", npmDir, err, string(output)) - } - - return nil -} - -// UserProvisioner manages system user creation and sudoers setup -type UserProvisioner struct { - username string - home string - shell string -} - -// NewUserProvisioner creates a new user provisioner -func NewUserProvisioner(username, home, shell string) *UserProvisioner { - if shell == "" { - shell = "/bin/bash" - } - return &UserProvisioner{ - username: username, - home: home, - shell: shell, - } -} - -// UserExists checks if the system user exists -func (up *UserProvisioner) UserExists() bool { - cmd := exec.Command("id", up.username) - return cmd.Run() == nil -} - -// CreateUser creates the system user -func (up *UserProvisioner) CreateUser() error { - if up.UserExists() { - return nil // User already exists - } - - cmd := exec.Command("useradd", "-r", "-m", "-s", up.shell, "-d", up.home, up.username) - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to create user %s: %w", up.username, err) - } - - return nil -} - -// SetupSudoersAccess creates sudoers rule for the invoking user -func (up *UserProvisioner) SetupSudoersAccess(invokerUser string) error { - if invokerUser == "" { - return nil // Skip if no invoker - } - - sudoersRule := fmt.Sprintf("%s ALL=(orama) NOPASSWD: ALL\n", invokerUser) - sudoersFile := "/etc/sudoers.d/orama-access" - - // Check if rule already exists - if existing, err := os.ReadFile(sudoersFile); err == nil { - if strings.Contains(string(existing), invokerUser) { - return nil // Rule already set - } - } - - // Write sudoers rule - if err := os.WriteFile(sudoersFile, []byte(sudoersRule), 0440); err != nil { - return fmt.Errorf("failed to create sudoers rule: %w", err) - } - - // Validate sudoers file - cmd := exec.Command("visudo", "-c", "-f", sudoersFile) - if err := cmd.Run(); err != nil { - os.Remove(sudoersFile) // Clean up on validation failure - return fmt.Errorf("sudoers rule validation failed: %w", err) - } - - return nil -} - -// SetupDeploymentSudoers configures the orama user with permissions needed for -// managing user deployments via systemd services. -func (up *UserProvisioner) SetupDeploymentSudoers() error { - sudoersFile := "/etc/sudoers.d/orama-deployments" - - // Check if already configured - if _, err := os.Stat(sudoersFile); err == nil { - return nil // Already configured - } - - sudoersContent := `# Orama Network - Deployment Management Permissions -# Allows orama user to manage systemd services for user deployments - -# Systemd service management for orama-deploy-* services -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl daemon-reload -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl start orama-deploy-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop orama-deploy-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart orama-deploy-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl enable orama-deploy-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl disable orama-deploy-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl status orama-deploy-* - -# Service file management (tee to write, rm to remove) -orama ALL=(ALL) NOPASSWD: /usr/bin/tee /etc/systemd/system/orama-deploy-*.service -orama ALL=(ALL) NOPASSWD: /bin/rm -f /etc/systemd/system/orama-deploy-*.service -` - - // Write sudoers rule - if err := os.WriteFile(sudoersFile, []byte(sudoersContent), 0440); err != nil { - return fmt.Errorf("failed to create deployment sudoers rule: %w", err) - } - - // Validate sudoers file - cmd := exec.Command("visudo", "-c", "-f", sudoersFile) - if err := cmd.Run(); err != nil { - os.Remove(sudoersFile) // Clean up on validation failure - return fmt.Errorf("deployment sudoers rule validation failed: %w", err) - } - - return nil -} - -// SetupNamespaceSudoers configures the orama user with permissions needed for -// managing namespace cluster services via systemd. -func (up *UserProvisioner) SetupNamespaceSudoers() error { - sudoersFile := "/etc/sudoers.d/orama-namespaces" - - // Check if already configured - if _, err := os.Stat(sudoersFile); err == nil { - return nil // Already configured - } - - sudoersContent := `# Orama Network - Namespace Cluster Management Permissions -# Allows orama user to manage systemd services for namespace clusters - -# Systemd service management for orama-namespace-* services -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl daemon-reload -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl start orama-namespace-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop orama-namespace-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart orama-namespace-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl enable orama-namespace-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl disable orama-namespace-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl status orama-namespace-* -orama ALL=(ALL) NOPASSWD: /usr/bin/systemctl is-active orama-namespace-* - -# Service file management (tee to write, rm to remove) -orama ALL=(ALL) NOPASSWD: /usr/bin/tee /etc/systemd/system/orama-namespace-*.service -orama ALL=(ALL) NOPASSWD: /bin/rm -f /etc/systemd/system/orama-namespace-*.service - -# Environment file management for namespace services -orama ALL=(ALL) NOPASSWD: /usr/bin/tee /home/orama/.orama/namespace/*/env/* -orama ALL=(ALL) NOPASSWD: /usr/bin/mkdir -p /home/orama/.orama/namespace/*/env -` - - // Write sudoers rule - if err := os.WriteFile(sudoersFile, []byte(sudoersContent), 0440); err != nil { - return fmt.Errorf("failed to create namespace sudoers rule: %w", err) - } - - // Validate sudoers file - cmd := exec.Command("visudo", "-c", "-f", sudoersFile) - if err := cmd.Run(); err != nil { - os.Remove(sudoersFile) // Clean up on validation failure - return fmt.Errorf("namespace sudoers rule validation failed: %w", err) - } - - return nil -} - -// SetupWireGuardSudoers configures the orama user with permissions to manage WireGuard -func (up *UserProvisioner) SetupWireGuardSudoers() error { - sudoersFile := "/etc/sudoers.d/orama-wireguard" - - sudoersContent := `# Orama Network - WireGuard Management Permissions -# Allows orama user to manage WireGuard peers - -orama ALL=(ALL) NOPASSWD: /usr/bin/wg set wg0 * -orama ALL=(ALL) NOPASSWD: /usr/bin/wg show wg0 -orama ALL=(ALL) NOPASSWD: /usr/bin/wg showconf wg0 -orama ALL=(ALL) NOPASSWD: /usr/bin/tee /etc/wireguard/wg0.conf -` - - // Write sudoers rule (always overwrite to ensure latest) - if err := os.WriteFile(sudoersFile, []byte(sudoersContent), 0440); err != nil { - return fmt.Errorf("failed to create wireguard sudoers rule: %w", err) - } - - // Validate sudoers file - cmd := exec.Command("visudo", "-c", "-f", sudoersFile) - if err := cmd.Run(); err != nil { - os.Remove(sudoersFile) - return fmt.Errorf("wireguard sudoers rule validation failed: %w", err) - } - - return nil -} // StateDetector checks for existing production state type StateDetector struct { diff --git a/pkg/environments/production/services.go b/pkg/environments/production/services.go index 5de197f..0defaf8 100644 --- a/pkg/environments/production/services.go +++ b/pkg/environments/production/services.go @@ -34,8 +34,6 @@ Wants=network-online.target [Service] Type=simple -User=orama -Group=orama Environment=HOME=%[1]s Environment=IPFS_PATH=%[2]s ExecStartPre=/bin/bash -c 'if [ -f %[3]s/secrets/swarm.key ] && [ ! -f %[2]s/swarm.key ]; then cp %[3]s/secrets/swarm.key %[2]s/swarm.key && chmod 600 %[2]s/swarm.key; fi' @@ -46,16 +44,7 @@ StandardOutput=append:%[4]s StandardError=append:%[4]s SyslogIdentifier=orama-ipfs -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ProtectHome=read-only -ProtectKernelTunables=yes -ProtectKernelModules=yes -ProtectControlGroups=yes -RestrictRealtime=yes -RestrictSUIDSGID=yes -ReadWritePaths=%[3]s LimitNOFILE=65536 TimeoutStopSec=30 KillMode=mixed @@ -86,8 +75,6 @@ Requires=orama-ipfs.service [Service] Type=simple -User=orama -Group=orama WorkingDirectory=%[1]s Environment=HOME=%[1]s Environment=IPFS_CLUSTER_PATH=%[2]s @@ -101,16 +88,7 @@ StandardOutput=append:%[3]s StandardError=append:%[3]s SyslogIdentifier=orama-ipfs-cluster -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ProtectHome=read-only -ProtectKernelTunables=yes -ProtectKernelModules=yes -ProtectControlGroups=yes -RestrictRealtime=yes -RestrictSUIDSGID=yes -ReadWritePaths=%[1]s LimitNOFILE=65536 TimeoutStopSec=30 KillMode=mixed @@ -150,8 +128,6 @@ Wants=network-online.target [Service] Type=simple -User=orama -Group=orama Environment=HOME=%[1]s ExecStart=%[5]s %[2]s Restart=always @@ -160,16 +136,7 @@ StandardOutput=append:%[3]s StandardError=append:%[3]s SyslogIdentifier=orama-rqlite -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ProtectHome=read-only -ProtectKernelTunables=yes -ProtectKernelModules=yes -ProtectControlGroups=yes -RestrictRealtime=yes -RestrictSUIDSGID=yes -ReadWritePaths=%[4]s LimitNOFILE=65536 TimeoutStopSec=30 KillMode=mixed @@ -191,8 +158,6 @@ Wants=network-online.target [Service] Type=simple -User=orama -Group=orama Environment=HOME=%[1]s Environment=OLRIC_SERVER_CONFIG=%[2]s ExecStart=%[5]s @@ -202,16 +167,7 @@ StandardOutput=append:%[3]s StandardError=append:%[3]s SyslogIdentifier=olric -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ProtectHome=read-only -ProtectKernelTunables=yes -ProtectKernelModules=yes -ProtectControlGroups=yes -RestrictRealtime=yes -RestrictSUIDSGID=yes -ReadWritePaths=%[4]s LimitNOFILE=65536 TimeoutStopSec=30 KillMode=mixed @@ -237,8 +193,6 @@ Requires=wg-quick@wg0.service [Service] Type=simple -User=orama -Group=orama WorkingDirectory=%[1]s Environment=HOME=%[1]s ExecStart=%[1]s/bin/orama-node --config %[2]s/configs/%[3]s @@ -248,16 +202,7 @@ StandardOutput=append:%[4]s StandardError=append:%[4]s SyslogIdentifier=orama-node -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ProtectHome=read-only -ProtectKernelTunables=yes -ProtectKernelModules=yes -ProtectControlGroups=yes -RestrictRealtime=yes -RestrictSUIDSGID=yes -ReadWritePaths=%[2]s /etc/systemd/system LimitNOFILE=65536 TimeoutStopSec=30 KillMode=mixed @@ -279,8 +224,6 @@ Wants=orama-node.service orama-olric.service [Service] Type=simple -User=orama -Group=orama WorkingDirectory=%[1]s Environment=HOME=%[1]s ExecStart=%[1]s/bin/gateway --config %[2]s/data/gateway.yaml @@ -290,20 +233,7 @@ StandardOutput=append:%[3]s StandardError=append:%[3]s SyslogIdentifier=orama-gateway -AmbientCapabilities=CAP_NET_BIND_SERVICE -CapabilityBoundingSet=CAP_NET_BIND_SERVICE - -# Note: NoNewPrivileges is omitted because it conflicts with AmbientCapabilities -# The service needs CAP_NET_BIND_SERVICE to bind to privileged ports (80, 443) PrivateTmp=yes -ProtectSystem=strict -ProtectHome=read-only -ProtectKernelTunables=yes -ProtectKernelModules=yes -ProtectControlGroups=yes -RestrictRealtime=yes -RestrictSUIDSGID=yes -ReadWritePaths=%[2]s LimitNOFILE=65536 TimeoutStopSec=30 KillMode=mixed @@ -325,8 +255,6 @@ Wants=network-online.target [Service] Type=simple -User=orama -Group=orama Environment=HOME=%[1]s Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/lib/node_modules/.bin WorkingDirectory=%[1]s @@ -337,16 +265,7 @@ StandardOutput=append:%[2]s StandardError=append:%[2]s SyslogIdentifier=anyone-client -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ProtectHome=no -ProtectKernelTunables=yes -ProtectKernelModules=yes -ProtectControlGroups=yes -RestrictRealtime=yes -RestrictSUIDSGID=yes -ReadWritePaths=%[3]s LimitNOFILE=65536 TimeoutStopSec=30 KillMode=mixed @@ -405,15 +324,11 @@ Wants=network-online.target orama-node.service [Service] Type=simple -User=root ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile Restart=on-failure RestartSec=5 SyslogIdentifier=coredns -NoNewPrivileges=true -ProtectSystem=full -ProtectHome=true LimitNOFILE=65536 TimeoutStopSec=30 KillMode=mixed @@ -435,16 +350,12 @@ Wants=orama-node.service [Service] Type=simple -User=caddy -Group=caddy ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile TimeoutStopSec=5s LimitNOFILE=1048576 LimitNPROC=512 PrivateTmp=true -ProtectSystem=full -AmbientCapabilities=CAP_NET_BIND_SERVICE Restart=on-failure RestartSec=5 SyslogIdentifier=caddy diff --git a/pkg/environments/production/services_test.go b/pkg/environments/production/services_test.go index 70cc372..db38b11 100644 --- a/pkg/environments/production/services_test.go +++ b/pkg/environments/production/services_test.go @@ -47,8 +47,8 @@ func TestGenerateRQLiteService(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ssg := &SystemdServiceGenerator{ - oramaHome: "/home/orama", - oramaDir: "/home/orama/.orama", + oramaHome: "/opt/orama", + oramaDir: "/opt/orama/.orama", } unit := ssg.GenerateRQLiteService("/usr/local/bin/rqlited", 5001, 7001, tt.joinAddr, tt.advertiseIP) @@ -81,8 +81,8 @@ func TestGenerateRQLiteService(t *testing.T) { // TestGenerateRQLiteServiceArgs verifies the ExecStart command arguments func TestGenerateRQLiteServiceArgs(t *testing.T) { ssg := &SystemdServiceGenerator{ - oramaHome: "/home/orama", - oramaDir: "/home/orama/.orama", + oramaHome: "/opt/orama", + oramaDir: "/opt/orama/.orama", } unit := ssg.GenerateRQLiteService("/usr/local/bin/rqlited", 5001, 7001, "10.0.0.1:7001", "10.0.0.2") diff --git a/pkg/environments/production/wireguard.go b/pkg/environments/production/wireguard.go index fb2a646..08292e9 100644 --- a/pkg/environments/production/wireguard.go +++ b/pkg/environments/production/wireguard.go @@ -145,11 +145,11 @@ func (wp *WireGuardProvisioner) WriteConfig() error { } } - // Fallback to sudo tee (for non-root, e.g. orama user) - cmd := exec.Command("sudo", "tee", confPath) + // Fallback to tee (for non-root, e.g. orama user) + cmd := exec.Command("tee", confPath) cmd.Stdin = strings.NewReader(content) if output, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("failed to write wg0.conf via sudo: %w\n%s", err, string(output)) + return fmt.Errorf("failed to write wg0.conf via tee: %w\n%s", err, string(output)) } return nil @@ -198,7 +198,7 @@ func (wp *WireGuardProvisioner) AddPeer(peer WireGuardPeer) error { args = append(args, "endpoint", peer.Endpoint) } - cmd := exec.Command("sudo", args...) + cmd := exec.Command(args[0], args[1:]...) if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("failed to add peer %s: %w\n%s", peer.AllowedIP, err, string(output)) } @@ -210,7 +210,7 @@ func (wp *WireGuardProvisioner) AddPeer(peer WireGuardPeer) error { // RemovePeer removes a peer from the running WireGuard interface func (wp *WireGuardProvisioner) RemovePeer(publicKey string) error { - cmd := exec.Command("sudo", "wg", "set", "wg0", "peer", publicKey, "remove") + cmd := exec.Command("wg", "set", "wg0", "peer", publicKey, "remove") if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("failed to remove peer: %w\n%s", err, string(output)) } diff --git a/pkg/environments/templates/render_test.go b/pkg/environments/templates/render_test.go index e82c832..8b84b58 100644 --- a/pkg/environments/templates/render_test.go +++ b/pkg/environments/templates/render_test.go @@ -10,7 +10,7 @@ func TestRenderNodeConfig(t *testing.T) { data := NodeConfigData{ NodeID: "node2", P2PPort: 4002, - DataDir: "/home/orama/.orama/node2", + DataDir: "/opt/orama/.orama/node2", RQLiteHTTPPort: 5002, RQLiteRaftPort: 7002, RQLiteJoinAddress: "localhost:5001", diff --git a/pkg/environments/templates/systemd_gateway.service b/pkg/environments/templates/systemd_gateway.service index ee62d54..8cbc716 100644 --- a/pkg/environments/templates/systemd_gateway.service +++ b/pkg/environments/templates/systemd_gateway.service @@ -5,8 +5,6 @@ Wants=orama-node.service [Service] Type=simple -User=orama -Group=orama WorkingDirectory={{.HomeDir}} Environment=HOME={{.HomeDir}} ExecStart={{.HomeDir}}/bin/gateway --config {{.OramaDir}}/data/gateway.yaml @@ -16,14 +14,7 @@ StandardOutput=journal StandardError=journal SyslogIdentifier=orama-gateway -AmbientCapabilities=CAP_NET_BIND_SERVICE -CapabilityBoundingSet=CAP_NET_BIND_SERVICE - -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ReadWritePaths={{.OramaDir}} [Install] WantedBy=multi-user.target - diff --git a/pkg/environments/templates/systemd_ipfs.service b/pkg/environments/templates/systemd_ipfs.service index ab61bbc..1436a27 100644 --- a/pkg/environments/templates/systemd_ipfs.service +++ b/pkg/environments/templates/systemd_ipfs.service @@ -5,8 +5,6 @@ Wants=network-online.target [Service] Type=simple -User=orama -Group=orama Environment=HOME={{.HomeDir}} Environment=IPFS_PATH={{.IPFSRepoPath}} ExecStartPre=/bin/bash -c 'if [ -f {{.SecretsDir}}/swarm.key ] && [ ! -f {{.IPFSRepoPath}}/swarm.key ]; then cp {{.SecretsDir}}/swarm.key {{.IPFSRepoPath}}/swarm.key && chmod 600 {{.IPFSRepoPath}}/swarm.key; fi' @@ -17,11 +15,7 @@ StandardOutput=journal StandardError=journal SyslogIdentifier=ipfs-{{.NodeType}} -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ReadWritePaths={{.OramaDir}} [Install] WantedBy=multi-user.target - diff --git a/pkg/environments/templates/systemd_ipfs_cluster.service b/pkg/environments/templates/systemd_ipfs_cluster.service index 5701ea9..7f31b75 100644 --- a/pkg/environments/templates/systemd_ipfs_cluster.service +++ b/pkg/environments/templates/systemd_ipfs_cluster.service @@ -6,8 +6,6 @@ Requires=orama-ipfs-{{.NodeType}}.service [Service] Type=simple -User=orama -Group=orama WorkingDirectory={{.HomeDir}} Environment=HOME={{.HomeDir}} Environment=CLUSTER_PATH={{.ClusterPath}} @@ -18,11 +16,7 @@ StandardOutput=journal StandardError=journal SyslogIdentifier=ipfs-cluster-{{.NodeType}} -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ReadWritePaths={{.OramaDir}} [Install] WantedBy=multi-user.target - diff --git a/pkg/environments/templates/systemd_node.service b/pkg/environments/templates/systemd_node.service index b20f8f5..edbcab6 100644 --- a/pkg/environments/templates/systemd_node.service +++ b/pkg/environments/templates/systemd_node.service @@ -6,8 +6,6 @@ Requires=orama-ipfs-cluster-{{.NodeType}}.service [Service] Type=simple -User=orama -Group=orama WorkingDirectory={{.HomeDir}} Environment=HOME={{.HomeDir}} ExecStart={{.HomeDir}}/bin/orama-node --config {{.OramaDir}}/configs/{{.ConfigFile}} @@ -17,11 +15,7 @@ StandardOutput=journal StandardError=journal SyslogIdentifier=orama-node-{{.NodeType}} -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ReadWritePaths={{.OramaDir}} [Install] WantedBy=multi-user.target - diff --git a/pkg/environments/templates/systemd_olric.service b/pkg/environments/templates/systemd_olric.service index df12456..b85961b 100644 --- a/pkg/environments/templates/systemd_olric.service +++ b/pkg/environments/templates/systemd_olric.service @@ -5,8 +5,6 @@ Wants=network-online.target [Service] Type=simple -User=orama -Group=orama Environment=HOME={{.HomeDir}} Environment=OLRIC_SERVER_CONFIG={{.ConfigPath}} ExecStart=/usr/local/bin/olric-server @@ -16,11 +14,7 @@ StandardOutput=journal StandardError=journal SyslogIdentifier=olric -NoNewPrivileges=yes PrivateTmp=yes -ProtectSystem=strict -ReadWritePaths={{.OramaDir}} [Install] WantedBy=multi-user.target - diff --git a/pkg/gateway/handlers/join/handler.go b/pkg/gateway/handlers/join/handler.go index fb7272b..6d218a2 100644 --- a/pkg/gateway/handlers/join/handler.go +++ b/pkg/gateway/handlers/join/handler.go @@ -65,7 +65,7 @@ type PeerInfo struct { type Handler struct { logger *zap.Logger rqliteClient rqlite.Client - oramaDir string // e.g., /home/orama/.orama + oramaDir string // e.g., /opt/orama/.orama } // NewHandler creates a new join handler @@ -271,7 +271,7 @@ func (h *Handler) assignWGIP(ctx context.Context) (string, error) { // addWGPeerLocally adds a peer to the local wg0 interface and persists to config func (h *Handler) addWGPeerLocally(pubKey, publicIP, wgIP string) error { // Add to running interface with persistent-keepalive - cmd := exec.Command("sudo", "wg", "set", "wg0", + cmd := exec.Command("wg", "set", "wg0", "peer", pubKey, "endpoint", fmt.Sprintf("%s:51820", publicIP), "allowed-ips", fmt.Sprintf("%s/32", wgIP), @@ -298,7 +298,7 @@ func (h *Handler) addWGPeerLocally(pubKey, publicIP, wgIP string) error { pubKey, publicIP, wgIP) newConf := string(data) + peerSection - writeCmd := exec.Command("sudo", "tee", confPath) + writeCmd := exec.Command("tee", confPath) writeCmd.Stdin = strings.NewReader(newConf) if output, err := writeCmd.CombinedOutput(); err != nil { h.logger.Warn("could not persist peer to wg0.conf", zap.Error(err), zap.String("output", string(output))) diff --git a/pkg/gateway/https.go b/pkg/gateway/https.go index 0eefa8c..ba03602 100644 --- a/pkg/gateway/https.go +++ b/pkg/gateway/https.go @@ -59,7 +59,7 @@ func NewHTTPSGateway(logger *logging.ColoredLogger, cfg *config.HTTPGatewayConfi // Use Let's Encrypt STAGING (consistent with SNI gateway) cacheDir := cfg.HTTPS.CacheDir if cacheDir == "" { - cacheDir = "/home/orama/.orama/tls-cache" + cacheDir = "/opt/orama/.orama/tls-cache" } // Use Let's Encrypt STAGING - provides higher rate limits for testing/development diff --git a/pkg/inspector/collector.go b/pkg/inspector/collector.go index a42f2f2..e5ea49f 100644 --- a/pkg/inspector/collector.go +++ b/pkg/inspector/collector.go @@ -625,7 +625,7 @@ curl -sf -X POST 'http://localhost:4501/api/v0/version' 2>/dev/null | python3 -c echo "$SEP" curl -sf 'http://localhost:9094/id' 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('version',''))" 2>/dev/null || echo unknown echo "$SEP" -sudo test -f /home/orama/.orama/data/ipfs/repo/swarm.key && echo yes || echo no +test -f /opt/orama/.orama/data/ipfs/repo/swarm.key && echo yes || echo no echo "$SEP" curl -sf -X POST 'http://localhost:4501/api/v0/bootstrap/list' 2>/dev/null | python3 -c "import sys,json; peers=json.load(sys.stdin).get('Peers',[]); print(len(peers))" 2>/dev/null || echo -1 ` diff --git a/pkg/node/wireguard_sync.go b/pkg/node/wireguard_sync.go index 451b525..d3a669c 100644 --- a/pkg/node/wireguard_sync.go +++ b/pkg/node/wireguard_sync.go @@ -30,7 +30,7 @@ func (n *Node) syncWireGuardPeers(ctx context.Context) error { } // Check if wg0 interface exists - out, err := exec.CommandContext(ctx, "sudo", "wg", "show", "wg0").CombinedOutput() + out, err := exec.CommandContext(ctx, "wg", "show", "wg0").CombinedOutput() if err != nil { n.logger.ComponentInfo(logging.ComponentNode, "WireGuard interface wg0 not active, skipping peer sync") return nil @@ -116,7 +116,7 @@ func (n *Node) ensureWireGuardSelfRegistered(ctx context.Context) { } // Check if wg0 is active - out, err := exec.CommandContext(ctx, "sudo", "wg", "show", "wg0").CombinedOutput() + out, err := exec.CommandContext(ctx, "wg", "show", "wg0").CombinedOutput() if err != nil { return // WG not active, nothing to register } diff --git a/pkg/rqlite/util.go b/pkg/rqlite/util.go index 0d480e3..662e0d2 100644 --- a/pkg/rqlite/util.go +++ b/pkg/rqlite/util.go @@ -17,7 +17,7 @@ func (r *RQLiteManager) rqliteDataDirPath() (string, error) { } func (r *RQLiteManager) resolveMigrationsDir() (string, error) { - productionPath := "/home/orama/src/migrations" + productionPath := "/opt/orama/src/migrations" if _, err := os.Stat(productionPath); err == nil { return productionPath, nil } diff --git a/pkg/systemd/manager.go b/pkg/systemd/manager.go index 3507ae9..3ac0412 100644 --- a/pkg/systemd/manager.go +++ b/pkg/systemd/manager.go @@ -47,7 +47,7 @@ func (m *Manager) StartService(namespace string, serviceType ServiceType) error zap.String("service", svcName), zap.String("namespace", namespace)) - cmd := exec.Command("sudo", "-n", "systemctl", "start", svcName) + cmd := exec.Command("systemctl", "start", svcName) m.logger.Debug("Executing systemctl command", zap.String("cmd", cmd.String()), zap.Strings("args", cmd.Args)) @@ -75,7 +75,7 @@ func (m *Manager) StopService(namespace string, serviceType ServiceType) error { zap.String("service", svcName), zap.String("namespace", namespace)) - cmd := exec.Command("sudo", "-n", "systemctl", "stop", svcName) + cmd := exec.Command("systemctl", "stop", svcName) if output, err := cmd.CombinedOutput(); err != nil { // Don't error if service is already stopped or doesn't exist if strings.Contains(string(output), "not loaded") || strings.Contains(string(output), "inactive") { @@ -96,7 +96,7 @@ func (m *Manager) RestartService(namespace string, serviceType ServiceType) erro zap.String("service", svcName), zap.String("namespace", namespace)) - cmd := exec.Command("sudo", "-n", "systemctl", "restart", svcName) + cmd := exec.Command("systemctl", "restart", svcName) if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("failed to restart %s: %w; output: %s", svcName, err, string(output)) } @@ -112,7 +112,7 @@ func (m *Manager) EnableService(namespace string, serviceType ServiceType) error zap.String("service", svcName), zap.String("namespace", namespace)) - cmd := exec.Command("sudo", "-n", "systemctl", "enable", svcName) + cmd := exec.Command("systemctl", "enable", svcName) if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("failed to enable %s: %w; output: %s", svcName, err, string(output)) } @@ -128,7 +128,7 @@ func (m *Manager) DisableService(namespace string, serviceType ServiceType) erro zap.String("service", svcName), zap.String("namespace", namespace)) - cmd := exec.Command("sudo", "-n", "systemctl", "disable", svcName) + cmd := exec.Command("systemctl", "disable", svcName) if output, err := cmd.CombinedOutput(); err != nil { // Don't error if service is already disabled or doesn't exist if strings.Contains(string(output), "not loaded") { @@ -145,7 +145,7 @@ func (m *Manager) DisableService(namespace string, serviceType ServiceType) erro // IsServiceActive checks if a namespace service is active func (m *Manager) IsServiceActive(namespace string, serviceType ServiceType) (bool, error) { svcName := m.serviceName(namespace, serviceType) - cmd := exec.Command("sudo", "-n", "systemctl", "is-active", svcName) + cmd := exec.Command("systemctl", "is-active", svcName) output, err := cmd.CombinedOutput() outputStr := strings.TrimSpace(string(output)) @@ -185,7 +185,7 @@ func (m *Manager) IsServiceActive(namespace string, serviceType ServiceType) (bo // ReloadDaemon reloads systemd daemon configuration func (m *Manager) ReloadDaemon() error { m.logger.Info("Reloading systemd daemon") - cmd := exec.Command("sudo", "-n", "systemctl", "daemon-reload") + cmd := exec.Command("systemctl", "daemon-reload") if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("failed to reload systemd daemon: %w; output: %s", err, string(output)) } @@ -228,7 +228,7 @@ func (m *Manager) StartAllNamespaceServices(namespace string) error { // ListNamespaceServices returns all namespace services currently registered in systemd func (m *Manager) ListNamespaceServices() ([]string, error) { - cmd := exec.Command("sudo", "-n", "systemctl", "list-units", "--all", "--no-legend", "orama-namespace-*@*.service") + cmd := exec.Command("systemctl", "list-units", "--all", "--no-legend", "orama-namespace-*@*.service") output, err := cmd.CombinedOutput() if err != nil { return nil, fmt.Errorf("failed to list namespace services: %w; output: %s", err, string(output)) @@ -260,7 +260,7 @@ func (m *Manager) StopAllNamespaceServicesGlobally() error { for _, svc := range services { m.logger.Info("Stopping service", zap.String("service", svc)) - cmd := exec.Command("sudo", "-n", "systemctl", "stop", svc) + cmd := exec.Command("systemctl", "stop", svc) if output, err := cmd.CombinedOutput(); err != nil { m.logger.Warn("Failed to stop service", zap.String("service", svc), diff --git a/scripts/check-node-health.sh b/scripts/check-node-health.sh index 018a49c..765dc50 100755 --- a/scripts/check-node-health.sh +++ b/scripts/check-node-health.sh @@ -86,7 +86,7 @@ echo "" # 4. IPFS echo "── IPFS ──" -PEERS=$(sudo -u orama IPFS_PATH=/home/orama/.orama/data/ipfs/repo /usr/local/bin/ipfs swarm peers 2>/dev/null) +PEERS=$(IPFS_PATH=/opt/orama/.orama/data/ipfs/repo /usr/local/bin/ipfs swarm peers 2>/dev/null) if [ -n "$PEERS" ]; then COUNT=$(echo "$PEERS" | wc -l) echo " Connected peers: $COUNT" diff --git a/scripts/clean-testnet.sh b/scripts/clean-testnet.sh index 838f3dc..d0ea5d0 100755 --- a/scripts/clean-testnet.sh +++ b/scripts/clean-testnet.sh @@ -50,11 +50,10 @@ ufw --force reset ufw allow 22/tcp ufw --force enable -echo " Killing orama processes..." -pkill -u orama 2>/dev/null || true -sleep 1 +echo " Removing orama data..." +rm -rf /opt/orama -echo " Removing orama user and data..." +echo " Removing legacy user and data..." userdel -r orama 2>/dev/null || true rm -rf /home/orama diff --git a/scripts/extract-deploy.sh b/scripts/extract-deploy.sh index bf6af0a..1eb034c 100755 --- a/scripts/extract-deploy.sh +++ b/scripts/extract-deploy.sh @@ -3,34 +3,27 @@ # Run as root on the target VPS. # # What it does: -# 1. Extracts source to /home/orama/src/ +# 1. Extracts source to /opt/orama/src/ # 2. Installs CLI to /usr/local/bin/orama # All other binaries are built from source during `orama install`. # -# Usage: sudo bash /home/orama/src/scripts/extract-deploy.sh +# Usage: sudo bash /opt/orama/src/scripts/extract-deploy.sh set -e ARCHIVE="/tmp/network-source.tar.gz" -SRC_DIR="/home/orama/src" -BIN_DIR="/home/orama/bin" +SRC_DIR="/opt/orama/src" +BIN_DIR="/opt/orama/bin" if [ ! -f "$ARCHIVE" ]; then echo "Error: $ARCHIVE not found" exit 1 fi -# Ensure orama user exists -if ! id -u orama &>/dev/null; then - echo "Creating 'orama' user..." - useradd -m -s /bin/bash orama -fi - echo "Extracting source..." rm -rf "$SRC_DIR" mkdir -p "$SRC_DIR" "$BIN_DIR" tar xzf "$ARCHIVE" -C "$SRC_DIR" -chown -R orama:orama "$SRC_DIR" || true # Install CLI binary if [ -f "$SRC_DIR/bin-linux/orama" ]; then @@ -41,6 +34,4 @@ else echo " ⚠️ CLI binary not found in archive (bin-linux/orama)" fi -chown -R orama:orama "$BIN_DIR" || true - echo "Done. Ready for: sudo orama install --vps-ip ..." diff --git a/scripts/migrate-to-opt.sh b/scripts/migrate-to-opt.sh new file mode 100755 index 0000000..1210564 --- /dev/null +++ b/scripts/migrate-to-opt.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# +# Migrate an existing node from /home/orama to /opt/orama. +# +# This is a one-time migration for nodes installed with the old architecture +# (dedicated orama user, /home/orama base). After migration, redeploy with +# the new root-based architecture. +# +# Usage: +# scripts/migrate-to-opt.sh +# +# Example: +# scripts/migrate-to-opt.sh root@51.195.109.238 'mypassword' +# +set -euo pipefail + +if [[ $# -lt 2 ]]; then + echo "Usage: $0 " + exit 1 +fi + +USERHOST="$1" +PASS="$2" + +SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR) + +echo "== Migrating $USERHOST from /home/orama → /opt/orama ==" +echo "" + +sshpass -p "$PASS" ssh -n "${SSH_OPTS[@]}" "$USERHOST" 'bash -s' <<'REMOTE' +set -e + +echo "1. Stopping all services..." +systemctl stop orama-node orama-gateway orama-ipfs orama-ipfs-cluster orama-olric orama-anyone-relay orama-anyone-client coredns caddy 2>/dev/null || true +systemctl disable orama-node orama-gateway orama-ipfs orama-ipfs-cluster orama-olric orama-anyone-relay orama-anyone-client coredns caddy 2>/dev/null || true + +echo "2. Creating /opt/orama..." +mkdir -p /opt/orama + +echo "3. Migrating data..." +if [ -d /home/orama/.orama ]; then + cp -a /home/orama/.orama /opt/orama/ + echo " .orama/ copied" +fi +if [ -d /home/orama/bin ]; then + cp -a /home/orama/bin /opt/orama/ + echo " bin/ copied" +fi +if [ -d /home/orama/src ]; then + cp -a /home/orama/src /opt/orama/ + echo " src/ copied" +fi + +echo "4. Removing old service files..." +rm -f /etc/systemd/system/orama-*.service +rm -f /etc/systemd/system/coredns.service +rm -f /etc/systemd/system/caddy.service +systemctl daemon-reload + +echo "5. Removing orama user..." +userdel -r orama 2>/dev/null || true +rm -rf /home/orama + +echo "6. Removing old sudoers files..." +rm -f /etc/sudoers.d/orama-access +rm -f /etc/sudoers.d/orama-deployments +rm -f /etc/sudoers.d/orama-wireguard + +echo "7. Tearing down WireGuard (will be re-created on install)..." +systemctl stop wg-quick@wg0 2>/dev/null || true +wg-quick down wg0 2>/dev/null || true +systemctl disable wg-quick@wg0 2>/dev/null || true +rm -f /etc/wireguard/wg0.conf + +echo "8. Resetting UFW..." +ufw --force reset +ufw allow 22/tcp +ufw --force enable + +echo "9. Cleaning temp files..." +rm -f /tmp/orama /tmp/network-source.tar.gz /tmp/network-source.zip +rm -rf /tmp/network-extract /tmp/coredns-build /tmp/caddy-build + +echo "" +echo "Migration complete. Data preserved at /opt/orama/" +echo "Old /home/orama removed." +echo "" +echo "Next: redeploy with new architecture:" +echo " ./bin/orama install --vps-ip --nameserver --domain --base-domain " +REMOTE + +echo "" +echo "Done." diff --git a/scripts/patches/fix-anyone-relay.sh b/scripts/patches/fix-anyone-relay.sh index 6dfd276..57bae82 100755 --- a/scripts/patches/fix-anyone-relay.sh +++ b/scripts/patches/fix-anyone-relay.sh @@ -51,7 +51,7 @@ fix_node() { local cmd cmd=$(cat <<'REMOTE' set -e -PREFS="/home/orama/.orama/preferences.yaml" +PREFS="/opt/orama/.orama/preferences.yaml" # Only patch nodes that have the Anyone relay service installed if [ ! -f /etc/systemd/system/orama-anyone-relay.service ]; then diff --git a/scripts/recover-rqlite.sh b/scripts/recover-rqlite.sh index 7264d96..fdebc66 100644 --- a/scripts/recover-rqlite.sh +++ b/scripts/recover-rqlite.sh @@ -133,7 +133,7 @@ if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then fi echo "" -RAFT_DIR="/home/orama/.orama/data/rqlite/raft" +RAFT_DIR="/opt/orama/.orama/data/rqlite/raft" BACKUP_DIR="/tmp/rqlite-raft-backup" # ── Phase 1: Stop orama-node on ALL nodes ─────────────────────────────────── @@ -286,4 +286,4 @@ echo "" echo "Next steps:" echo " 1. Run 'scripts/inspect.sh --devnet' to verify full cluster health" echo " 2. If some nodes show Candidate state, give them more time (up to 5 min)" -echo " 3. If nodes fail to join, check /home/orama/.orama/logs/rqlite-node.log on the node" +echo " 3. If nodes fail to join, check /opt/orama/.orama/logs/rqlite-node.log on the node" diff --git a/systemd/orama-namespace-gateway@.service b/systemd/orama-namespace-gateway@.service index 3eea274..b4541cd 100644 --- a/systemd/orama-namespace-gateway@.service +++ b/systemd/orama-namespace-gateway@.service @@ -7,14 +7,12 @@ PartOf=orama-node.service [Service] Type=simple -User=orama -Group=orama -WorkingDirectory=/home/orama +WorkingDirectory=/opt/orama -EnvironmentFile=/home/orama/.orama/data/namespaces/%i/gateway.env +EnvironmentFile=/opt/orama/.orama/data/namespaces/%i/gateway.env # Use shell to properly expand NODE_ID from env file -ExecStart=/bin/sh -c 'exec /home/orama/bin/gateway --config ${GATEWAY_CONFIG}' +ExecStart=/bin/sh -c 'exec /opt/orama/bin/gateway --config ${GATEWAY_CONFIG}' TimeoutStopSec=30s KillMode=mixed @@ -27,14 +25,7 @@ StandardOutput=journal StandardError=journal SyslogIdentifier=orama-gateway-%i -# Security hardening -NoNewPrivileges=yes -ProtectSystem=strict -ProtectHome=read-only -ProtectKernelTunables=yes -ProtectKernelModules=yes -ReadWritePaths=/home/orama/.orama/data/namespaces - +PrivateTmp=yes LimitNOFILE=65536 MemoryMax=1G diff --git a/systemd/orama-namespace-olric@.service b/systemd/orama-namespace-olric@.service index 8869da3..c8beb0d 100644 --- a/systemd/orama-namespace-olric@.service +++ b/systemd/orama-namespace-olric@.service @@ -7,14 +7,12 @@ PartOf=orama-node.service [Service] Type=simple -User=orama -Group=orama -WorkingDirectory=/home/orama +WorkingDirectory=/opt/orama # Olric reads config from environment variable (set in env file) -EnvironmentFile=/home/orama/.orama/data/namespaces/%i/olric.env +EnvironmentFile=/opt/orama/.orama/data/namespaces/%i/olric.env -ExecStart=/home/orama/bin/olric-server +ExecStart=/opt/orama/bin/olric-server TimeoutStopSec=30s KillMode=mixed @@ -27,14 +25,7 @@ StandardOutput=journal StandardError=journal SyslogIdentifier=orama-olric-%i -# Security hardening -NoNewPrivileges=yes -ProtectSystem=strict -ProtectHome=read-only -ProtectKernelTunables=yes -ProtectKernelModules=yes -ReadWritePaths=/home/orama/.orama/data/namespaces - +PrivateTmp=yes LimitNOFILE=65536 MemoryMax=2G diff --git a/systemd/orama-namespace-rqlite@.service b/systemd/orama-namespace-rqlite@.service index 0777c4e..3e982b4 100644 --- a/systemd/orama-namespace-rqlite@.service +++ b/systemd/orama-namespace-rqlite@.service @@ -7,12 +7,10 @@ StopWhenUnneeded=false [Service] Type=simple -User=orama -Group=orama -WorkingDirectory=/home/orama +WorkingDirectory=/opt/orama # Environment file contains namespace-specific config -EnvironmentFile=/home/orama/.orama/data/namespaces/%i/rqlite.env +EnvironmentFile=/opt/orama/.orama/data/namespaces/%i/rqlite.env # Start rqlited with args from environment (using shell to properly expand JOIN_ARGS) ExecStart=/bin/sh -c 'exec /usr/local/bin/rqlited \ @@ -21,7 +19,7 @@ ExecStart=/bin/sh -c 'exec /usr/local/bin/rqlited \ -http-adv-addr ${HTTP_ADV_ADDR} \ -raft-adv-addr ${RAFT_ADV_ADDR} \ ${JOIN_ARGS} \ - /home/orama/.orama/data/namespaces/%i/rqlite/${NODE_ID}' + /opt/orama/.orama/data/namespaces/%i/rqlite/${NODE_ID}' # Graceful shutdown TimeoutStopSec=30s @@ -37,15 +35,8 @@ StandardOutput=journal StandardError=journal SyslogIdentifier=orama-rqlite-%i -# Security hardening -NoNewPrivileges=yes -ProtectSystem=strict -ProtectHome=read-only -ProtectKernelTunables=yes -ProtectKernelModules=yes -ReadWritePaths=/home/orama/.orama/data/namespaces - # Resource limits +PrivateTmp=yes LimitNOFILE=65536 MemoryMax=2G