From af14622e45985b275dfad0318495955da4a19814 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 00:14:43 +0000 Subject: [PATCH 1/2] Initial plan From 3ca15d0da4e8576d8803c4b301470c79c1bf3007 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 00:19:25 +0000 Subject: [PATCH 2/2] Cleanup: Remove reverse SSH tunnel code, fix documentation accuracy Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/3941ead1-cb20-4686-92bb-46e447791ae3 Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com> --- docs/remote-deploy-headscale.md | 46 +++++++++++++++---------------- iso/sovran-install-headless.sh | 40 ++++++++------------------- modules/core/remote-deploy.nix | 49 +-------------------------------- sovran-provisioner.nix | 22 ++++----------- 4 files changed, 41 insertions(+), 116 deletions(-) diff --git a/docs/remote-deploy-headscale.md b/docs/remote-deploy-headscale.md index a0535fd..b9e35d3 100644 --- a/docs/remote-deploy-headscale.md +++ b/docs/remote-deploy-headscale.md @@ -44,7 +44,7 @@ This guide covers the Sovran Systems remote deployment system built on [Headscal **Components:** - **`sovran-provisioner.nix`** — NixOS module deployed on a separate VPS; runs Headscale + provisioning API + Caddy. - **Live ISO** (`iso/common.nix`) — Auto-registers with the provisioning server and joins the Tailnet on boot. -- **`remote-deploy.nix`** — Post-install NixOS module that uses Tailscale/Headscale for ongoing access (plus the existing reverse SSH tunnel as a fallback). +- **`remote-deploy.nix`** — Post-install NixOS module that uses Tailscale/Headscale for ongoing access. --- @@ -83,9 +83,6 @@ Add the following to your VPS's `/etc/nixos/configuration.nix`: domain = "prov.yourdomain.com"; headscaleDomain = "hs.yourdomain.com"; - # Optional: set a static token instead of auto-generating one - # enrollToken = "your-secret-token-here"; - # Optional: customise defaults headscaleUser = "sovran-deploy"; # namespace for deploy machines adminUser = "admin"; # namespace for your workstation @@ -114,7 +111,7 @@ Caddy will automatically obtain TLS certificates via Let's Encrypt. cat /var/lib/sovran-provisioner/enroll-token ``` -Keep this token secret — it is used to authenticate ISO registrations. If you set `enrollToken` statically in `configuration.nix`, that value is used directly (but avoid committing secrets to version control). +Keep this token secret — it is used to authenticate ISO registrations. The token is auto-generated on first boot and stored at this path. You never need to set it manually. Just `cat` it from the VPS and copy it to `iso/secrets/enroll-token` before building the ISO. --- @@ -209,19 +206,18 @@ The resulting ISO is in `./result/iso/`. ``` 5. **Run the headless installer**: - ```bash - # Basic install (relay tunnel) - sudo sovran-install-headless.sh \ - --disk /dev/sda \ - --role server \ - --deploy-key "ssh-ed25519 AAAA..." \ - --relay-host relay.yourdomain.com - # With Tailscale for post-install access + The `--deploy-key` is your SSH public key that gets injected into `root`'s `authorized_keys` on the deployed machine. This grants full root access for initial setup. Generate it once on your workstation if you haven't already: + ```bash + ssh-keygen -t ed25519 -f ~/.ssh/sovran-deploy -C "sovran-deploy" + ``` + After deployment is complete and you disable deploy mode, this key is removed. + + ```bash sudo sovran-install-headless.sh \ --disk /dev/sda \ --role server \ - --deploy-key "ssh-ed25519 AAAA..." \ + --deploy-key "$(cat ~/.ssh/sovran-deploy.pub)" \ --headscale-server "https://hs.yourdomain.com" \ --headscale-key "$(headscale preauthkeys create --user sovran-deploy --expiration 2h --output json | jq -r '.key')" ``` @@ -229,15 +225,17 @@ The resulting ISO is in `./result/iso/`. 6. **Machine reboots into Sovran_SystemsOS** — `deploy-tailscale-connect.service` runs: - Reads `/var/lib/secrets/headscale-authkey` - Joins the Tailnet with a deterministic hostname (`sovran-`) - - The reverse SSH tunnel also activates if `relayHost` was set 7. **Post-install SSH and RDP**: ```bash # SSH over Tailnet ssh root@ - # RDP over Tailnet (if desktop role) - xfreerdp /v: /u:free /p:free + # RDP over Tailnet (desktop role) — Sovran_SystemsOS uses GNOME Remote Desktop (native Wayland RDP) + # Retrieve the auto-generated RDP password: + ssh root@ cat /var/lib/gnome-remote-desktop/rdp-password + # Then connect with any RDP client (Remmina, GNOME Connections, Microsoft Remote Desktop): + # Host: :3389 User: sovran Password: ``` 8. **Disable deploy mode** — edit `/etc/nixos/custom.nix` on the target, set `enable = false`, then: @@ -254,18 +252,20 @@ The resulting ISO is in `./result/iso/`. ```bash # Over Tailnet ssh root@100.64.x.x - -# Over reverse tunnel (if configured) -ssh -p 2222 root@relay.yourdomain.com ``` ### RDP (desktop/server roles) +Sovran_SystemsOS uses **GNOME Remote Desktop** (native Wayland RDP — not xfreerdp). The RDP service auto-generates credentials on first boot. + +**Username:** `sovran` +**Password:** auto-generated — retrieve it via SSH: ```bash -# Over Tailnet -xfreerdp /v:100.64.x.x /u:free /p:free /dynamic-resolution +ssh root@ cat /var/lib/gnome-remote-desktop/rdp-password ``` +Connect using any RDP client (Remmina, GNOME Connections, Microsoft Remote Desktop) to `:3389`. + --- ## Security Model @@ -355,7 +355,7 @@ Then rebuild: nixos-rebuild switch ``` -This stops the reverse tunnel and Tailscale connect services. +This stops the Tailscale connect service. ### Revoke All Active Pre-Auth Keys diff --git a/iso/sovran-install-headless.sh b/iso/sovran-install-headless.sh index 3c4f44c..440befe 100755 --- a/iso/sovran-install-headless.sh +++ b/iso/sovran-install-headless.sh @@ -10,10 +10,6 @@ Options: --data-disk /dev/sdb Data disk for Bitcoin (optional) --role server|desktop|node Installation role (default: server) --deploy-key "ssh-ed25519 AAAA..." SSH pubkey for remote access after install - --relay-host HOST Reverse tunnel relay hostname - --relay-user USER Relay username (default: deploy) - --relay-port PORT Relay SSH port (default: 22) - --tunnel-port PORT Reverse tunnel port on relay (default: 2222) --headscale-server URL Headscale login server for post-install Tailnet --headscale-key KEY Headscale pre-auth key for the installed OS USAGE @@ -26,10 +22,6 @@ DISK="" DATA_DISK="" ROLE="server" DEPLOY_KEY="" -RELAY_HOST="" -RELAY_USER="deploy" -RELAY_PORT="22" -TUNNEL_PORT="2222" HEADSCALE_SERVER="" HEADSCALE_KEY="" @@ -58,10 +50,6 @@ while [[ $# -gt 0 ]]; do --data-disk) DATA_DISK="$2"; shift 2 ;; --role) ROLE="$2"; shift 2 ;; --deploy-key) DEPLOY_KEY="$2"; shift 2 ;; - --relay-host) RELAY_HOST="$2"; shift 2 ;; - --relay-user) RELAY_USER="$2"; shift 2 ;; - --relay-port) RELAY_PORT="$2"; shift 2 ;; - --tunnel-port) TUNNEL_PORT="$2"; shift 2 ;; --headscale-server) HEADSCALE_SERVER="$2"; shift 2 ;; --headscale-key) HEADSCALE_KEY="$2"; shift 2 ;; -h|--help) @@ -220,21 +208,17 @@ EOF # ── Step 10: Write custom.nix with deploy config ────────────────────────────── log "=== Writing custom.nix ===" -if [[ -n "$DEPLOY_KEY" ]]; then - cat > /mnt/etc/nixos/custom.nix < /mnt/etc/nixos/custom.nix else cp /mnt/etc/nixos/custom.template.nix /mnt/etc/nixos/custom.nix fi @@ -265,7 +249,5 @@ nixos-install \ log "=== Installation complete! ===" log "You can now reboot into Sovran_SystemsOS." log "After reboot, the machine will be accessible via SSH on port 22 (if --deploy-key was provided)." -[[ -n "$RELAY_HOST" ]] && \ - log "Reverse tunnel will connect to ${RELAY_USER}@${RELAY_HOST}:${RELAY_PORT} — forward port ${TUNNEL_PORT} maps to the machine's SSH." [[ -n "$HEADSCALE_SERVER" ]] && \ log "Tailscale will connect to Headscale at ${HEADSCALE_SERVER} on first boot." diff --git a/modules/core/remote-deploy.nix b/modules/core/remote-deploy.nix index 26650df..4399be3 100644 --- a/modules/core/remote-deploy.nix +++ b/modules/core/remote-deploy.nix @@ -8,30 +8,6 @@ in options.sovran_systemsOS.deploy = { enable = lib.mkEnableOption "Remote deploy mode"; - relayHost = lib.mkOption { - type = lib.types.str; - default = ""; - description = "SSH relay server hostname or IP for the reverse tunnel"; - }; - - relayPort = lib.mkOption { - type = lib.types.port; - default = 22; - description = "SSH port on the relay server"; - }; - - relayUser = lib.mkOption { - type = lib.types.str; - default = "deploy"; - description = "Username on the relay server"; - }; - - reverseTunnelPort = lib.mkOption { - type = lib.types.port; - default = 2222; - description = "Port on the relay that maps back to this machine's SSH (port 22)"; - }; - authorizedKey = lib.mkOption { type = lib.types.str; default = ""; @@ -120,29 +96,6 @@ in path = [ pkgs.tailscale pkgs.coreutils ]; }; - # ── Reverse tunnel service (only when relayHost is configured) ─────────── - systemd.services.deploy-reverse-tunnel = lib.mkIf (cfg.relayHost != "") { - description = "Deploy reverse SSH tunnel to ${cfg.relayHost}"; - wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" "sshd.service" ]; - wants = [ "network-online.target" ]; - serviceConfig = { - Restart = "always"; - RestartSec = "10s"; - ExecStart = "${pkgs.openssh}/bin/ssh" - + " -o StrictHostKeyChecking=accept-new" - + " -o ServerAliveInterval=30" - + " -o ServerAliveCountMax=3" - + " -o ExitOnForwardFailure=yes" - + " -i /var/lib/secrets/deploy-relay-key" - + " -N" - + " -R ${toString cfg.reverseTunnelPort}:localhost:22" - + " -p ${toString cfg.relayPort}" - + " ${cfg.relayUser}@${cfg.relayHost}"; - }; - path = [ pkgs.openssh ]; - }; - # ── Safety auto-expiry service ──────────────────────────────────────────── systemd.services.deploy-auto-expire = { description = "Auto-expire remote deploy mode after 48 hours"; @@ -155,7 +108,7 @@ in script = '' # 48 hours = 172800 seconds sleep $((48 * 60 * 60)) - systemctl stop deploy-reverse-tunnel || true + systemctl stop deploy-tailscale-connect || true mkdir -p /etc/sovran echo "expired" > /etc/sovran/deploy-mode ''; diff --git a/sovran-provisioner.nix b/sovran-provisioner.nix index 2c21c8f..93aefd9 100644 --- a/sovran-provisioner.nix +++ b/sovran-provisioner.nix @@ -151,12 +151,6 @@ in description = "Domain for the Headscale coordination server (e.g. hs.sovransystems.com)"; }; - enrollToken = lib.mkOption { - type = lib.types.str; - default = ""; - description = "Static enrollment token. If empty, one is auto-generated on first boot."; - }; - headscaleUser = lib.mkOption { type = lib.types.str; default = "sovran-deploy"; @@ -251,17 +245,13 @@ in script = '' mkdir -p ${cfg.stateDir} - # Generate enrollment token if not exists and not set statically + # Auto-generate enrollment token on first boot if not already present TOKEN_FILE="${cfg.stateDir}/enroll-token" - ${if cfg.enrollToken != "" then '' - echo "${cfg.enrollToken}" > "$TOKEN_FILE" - '' else '' - if [ ! -f "$TOKEN_FILE" ]; then - ${pkgs.openssl}/bin/openssl rand -hex 32 > "$TOKEN_FILE" - chmod 600 "$TOKEN_FILE" - echo "Generated new enrollment token: $(cat $TOKEN_FILE)" - fi - ''} + if [ ! -f "$TOKEN_FILE" ]; then + ${pkgs.openssl}/bin/openssl rand -hex 32 > "$TOKEN_FILE" + chmod 600 "$TOKEN_FILE" + echo "Generated new enrollment token: $(cat $TOKEN_FILE)" + fi # Ensure headscale users exist ${pkgs.headscale}/bin/headscale users create ${cfg.headscaleUser} 2>/dev/null || true