---
name: linux-host-administration
description: "Install and configure host-level Linux services and packages that require sudo, with safe authorization, verification, and cleanup."
version: 1.0.0
author: Hermes Agent
license: MIT
platforms: [linux]
metadata:
  hermes:
    tags: [linux, sudo, systemd, apt, tailscale, host-setup, devops]
    created_by: agent
---

# Linux Host Administration

Use this skill when the user asks to install or configure host-level Linux software or services that need root privileges: VPNs such as Tailscale, system packages, systemd services, privileged network setup, kernel-adjacent tools, or anything under `/etc`, `/usr`, or system service management.

## Core principles

1. Verify current state first.
   - Check whether the tool is already installed.
   - Check OS/distro details before choosing package commands.
   - Check service state after install.
2. Do not ask for or store the user's sudo password.
   - Prefer that the user run one privileged command locally, or temporarily grant narrowly-scoped/passwordless sudo.
   - Never try to bypass OS authorization.
3. If temporary passwordless sudo is used, remove it as soon as the privileged task is complete.
4. End with real verification output: installed binary path/version, systemd service state, and any remaining user action.
5. When the task is about a storage volume or partition, verify the exact device first with `lsblk`/`blkid`/GParted before renaming labels or changing mounts. See `references/ntfs-auto-mount-and-shortcuts.md` for a worked NTFS example.

## Sudo authorization pattern

First test whether passwordless sudo is already available:

```bash
sudo -n true && echo 'sudo passwordless OK' || echo 'sudo requires user authorization'
```

If sudo is not available, give the user a safe temporary option:

```bash
sudo visudo -f /etc/sudoers.d/hermes-agent-temp
```

Temporary broad grant when the task involves unknown installer commands:

```sudoers
wildlama ALL=(root) NOPASSWD: ALL
```

Prefer a narrower command list when practical. After the task finishes, remove the grant:

```bash
sudo rm -f /etc/sudoers.d/hermes-agent-temp
sudo -n true >/dev/null 2>&1 && echo 'passwordless sudo still active' || echo 'passwordless sudo no longer active'
```

Pitfall: an empty file in `/etc/sudoers.d/hermes-agent-temp` does not grant anything. If `sudo -n true` still says `interactive authentication is required`, tell the user to edit the sudoers file again with `visudo` and add the rule.

## CyberGhost VPN on headless Linux

Trigger: user asks to install CyberGhost VPN on Linux without a GUI, or asks for a terminal-only / server-friendly setup.

1. Verify the machine state first:

```bash
. /etc/os-release
command -v openvpn || true
command -v wg || true
command -v nmcli || true
```

2. Treat CyberGhost's Linux offering as a config-file workflow, not a standalone desktop GUI.
   - Official Linux page: `https://www.cyberghostvpn.com/download/linux-vpn`
   - Their FAQ says CLI use is supported via OpenVPN or WireGuard plus downloaded CyberGhost config files.
   - If the user has no GUI, prefer terminal tooling and avoid describing the NetworkManager path unless the user asks for it.

3. Install the protocol tools if missing:

```bash
sudo apt-get update
sudo apt-get install -y openvpn wireguard-tools
```

4. If the user needs NetworkManager integration, add the relevant plugins separately and import the CyberGhost config files in Settings.
   - For pure headless/server use, keep the workflow to `openvpn` / `wg` + config files.

5. Do not claim the installation is complete until you have one of these verifications:
   - installed binaries present (`command -v openvpn`, `command -v wg`)
   - a CyberGhost config file has been downloaded or imported
   - a test connection command succeeds or the user confirms they want to proceed with login/config download

6. If the exact CyberGhost download flow is unclear, check the bundled reference files:
   - `references/cyberghost-linux.md` for the quick headless install notes
   - `references/cyberghost-openvpn-linux.md` for the encrypted credential-vault workflow

## OpenVPN / CyberGhost headless workflow

Trigger: the user wants CyberGhost or another commercial VPN on a Linux machine without a GUI client.

1. Verify what the provider actually supplies.
   - If the download is a Linux config bundle (`.ovpn` plus certs/keys), treat it as an OpenVPN profile, not a "native app" install.
   - Prefer the provider's Linux/OpenVPN profile over older compatibility profiles unless the local OpenVPN client is too old.
   - If the provider offers both UDP and TCP, start with UDP; switch to TCP only when UDP is blocked or unstable.

2. Verify the bundle before trusting it.
   - List the archive contents.
   - Check that the certificate and key files are present.
   - Confirm the client certificate and private key match by comparing their public keys.
   - Read the `.ovpn` file and look for `auth-user-pass`, `remote`, `proto`, and any embedded cert/key references.

3. Import for desktop/system integration when NetworkManager is available.
   - `nmcli connection import type openvpn file <profile.ovpn>`
   - If needed, rename the connection and disable autoconnect until credentials are ready.
   - This is usually the cleanest path on Ubuntu desktop and keeps the profile manageable from the system UI or `nmcli`.

4. Use a headless-safe credential vault when the GUI app is absent.
   - Prompt locally with `zenity` when a graphical session exists.
   - Encrypt the saved username/password with `gpg --symmetric --cipher-algo AES256`.
   - Store the encrypted blob in a user config directory with mode `600`.
   - Decrypt only for the duration of the VPN launch and delete any temp auth file on exit.
   - A reference implementation and verification checklist live in `references/cyberghost-openvpn-linux.md`.

5. Launch and verify.
   - For NetworkManager: `nmcli connection up <name> --ask` when you want interactive secret entry.
   - For raw OpenVPN: `sudo openvpn --config <profile.ovpn>` or a wrapper that injects a temporary `auth-user-pass` file.
   - Verify the tunnel by checking the connection state and external IP/DNS after connect.

## Tailscale installation workflow

Trigger: user asks to install Tailscale on Ubuntu/Debian-style Linux.

1. Check current state:

```bash
if command -v tailscale >/dev/null 2>&1; then
  tailscale version | head -5
else
  . /etc/os-release
  echo "OS=$PRETTY_NAME ID=$ID VERSION_CODENAME=${VERSION_CODENAME:-}"
fi
```

2. If sudo is available, run the official installer:

```bash
curl -fsSL https://tailscale.com/install.sh | sh
```

This may trip security approval because it pipes remote content to `sh`; proceed only with user approval or use an inspected/manual repo setup if required.

3. Ensure and verify the daemon:

```bash
command -v tailscale
systemctl is-active tailscaled || sudo systemctl enable --now tailscaled
systemctl is-active tailscaled
tailscale version | head -5
```

4. Login step:

```bash
sudo tailscale up
```

If sudo was already cleaned up before login, do not claim completion. Tell the user either to run `sudo tailscale up` locally or re-enable temporary sudo. `tailscale status` showing `Logged out` means install succeeded but network login is unfinished.

5. After login/install, remove temporary sudo access and verify it is gone.

## Graphical remote access over Tailscale (XRDP + XFCE)

Trigger: the user wants a GUI on a remote Linux machine and Tailscale is the transport.

1. Prefer a lightweight desktop session for XRDP.
   - On Ubuntu/Debian hosts, install `xrdp`, `xfce4`, `xfce4-goodies`, and `xorgxrdp`.
   - XFCE is the least troublesome default for XRDP sessions.

2. Make the user session explicit.
   - Create `~/.xsession` containing `xfce4-session` for the target account.
   - Do this even if a display manager like GDM is already installed; XRDP still needs a session target.

3. Verify the service and listener before handing over.
   - `systemctl status xrdp`
   - `systemctl status xrdp-sesman`
   - `ss -ltnp | grep 3389`
   - `tailscale ip -4`

4. Connect from the other machine with any RDP client to `<tailscale-ip>:3389`.
   - Remmina works well on Linux clients.
   - No extra public firewall exposure is needed if the connection stays on Tailscale.

5. If the user also wants SSH, keep it separate from the GUI setup.
   - Do not mix the SSH onboarding path into the XRDP instructions unless the user asks for both.

## Exposing a local web UI over Tailscale Serve

Trigger: the app already runs on `127.0.0.1:<port>` and the user wants to open it from another Tailscale device.

1. Verify the app is actually serving locally first.
   - `curl -I http://127.0.0.1:<port>` or a simple GET on `/`
   - Do not assume a raw Tailscale IP will work if the app binds only to loopback.

2. Prefer a Tailscale HTTP proxy instead of rebinding the app when the goal is just remote access.
   - `sudo tailscale serve --bg --yes <port>`
   - This keeps the app unchanged and exposes it at the node's `https://<host>.<tailnet>.ts.net/` URL.
   - If the node is not authorized to manage serve config, use `sudo` or `tailscale set --operator=$USER` once, then retry.

3. Verify both the proxy and the final URL.
   - `tailscale serve status`
   - `python3 - <<'PY' ... urllib.request.urlopen('https://<host>.<tailnet>.ts.net/') ... PY`
   - Confirm the URL returns the UI, not just that the proxy was configured.

4. If the user wants a permanent LAN/Tailscale bind instead, change the app to listen on `0.0.0.0` or the machine's tailnet interface, then re-verify with a local curl and the remote URL.

5. When reporting back, give the exact working URL, the local port it proxies to, and any caveat about loopback-only binding.

## Final response checklist

Report only grounded facts:

- Installed version and binary path.
- Service state (`tailscaled` active/inactive).
- Login state (`tailscale status` or `Logged out`).
- Whether temporary sudoers access was removed.
- GUI access details: RDP client, target Tailscale IP, port 3389, and any session file written.
- The exact remaining user action, if any (for example, open Tailscale auth URL or run `sudo tailscale up`).

Keep security language direct: if the user asks for “all permissions,” explain that root permission requires user authorization and provide the sudoers procedure; do not suggest bypasses.
