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>
This commit is contained in:
copilot-swe-agent[bot]
2026-04-12 00:19:25 +00:00
committed by GitHub
parent af14622e45
commit 3ca15d0da4
4 changed files with 41 additions and 116 deletions

View File

@@ -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-<hostname>`)
- The reverse SSH tunnel also activates if `relayHost` was set
7. **Post-install SSH and RDP**:
```bash
# SSH over Tailnet
ssh root@<tailscale-ip>
# RDP over Tailnet (if desktop role)
xfreerdp /v:<tailscale-ip> /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@<tailscale-ip> cat /var/lib/gnome-remote-desktop/rdp-password
# Then connect with any RDP client (Remmina, GNOME Connections, Microsoft Remote Desktop):
# Host: <tailscale-ip>:3389 User: sovran Password: <from above>
```
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@<tailscale-ip> cat /var/lib/gnome-remote-desktop/rdp-password
```
Connect using any RDP client (Remmina, GNOME Connections, Microsoft Remote Desktop) to `<tailscale-ip>: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

View File

@@ -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 <<EOF
{ config, lib, ... }:
{
sovran_systemsOS.deploy = {
enable = true;
authorizedKey = "${DEPLOY_KEY}";
relayHost = "${RELAY_HOST}";
relayUser = "${RELAY_USER}";
relayPort = ${RELAY_PORT};
reverseTunnelPort = ${TUNNEL_PORT};
$([ -n "${HEADSCALE_SERVER}" ] && echo " headscaleServer = \"${HEADSCALE_SERVER}\";")
};
}
EOF
if [[ -n "$DEPLOY_KEY" || -n "$HEADSCALE_SERVER" ]]; then
{
echo '{ config, lib, ... }:'
echo '{'
echo ' sovran_systemsOS.deploy = {'
echo ' enable = true;'
[[ -n "$DEPLOY_KEY" ]] && echo " authorizedKey = \"${DEPLOY_KEY}\";"
[[ -n "$HEADSCALE_SERVER" ]] && echo " headscaleServer = \"${HEADSCALE_SERVER}\";"
echo ' };'
echo '}'
} > /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."

View File

@@ -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
'';

View File

@@ -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