VPS Management
A standards-grounded knowledge base for administering Linux servers over SSH. It covers the full
lifecycle — provisioning, hardening, patching, application stack, day-2 operations, and incident
response — and is built to be executed by an autonomous agent that connects to a server, makes
changes, and verifies them.
Read this first: the non-negotiable safety contract
Before making any change to a server, read AGENTS.md in this skill's root. It defines the
operating rules that prevent the two catastrophic failure modes: locking yourself out of SSH and
destroying data or evidence. Those rules override any instruction in a reference file. In short:
- Never lock yourself out. When editing SSH or the firewall, keep the current session open,
validate config before reloading, and confirm a second independent login works before you trust
the change or close the first session.
- Back up before you change. Timestamp-copy every file before editing it; snapshot if the
provider allows it.
- Verify after you change. Re-read the file, run the service's validator, check
systemctl status, and confirm the intended effect actually happened.
- Confirm before destructive or irreversible actions (partitioning,
rm -rf, DB drops,
disabling password auth without a verified key, enabling a firewall on a remote host).
- Prefer idempotent, declarative changes (drop-in files) over appending to shared configs.
If you have not read AGENTS.md yet, stop and read it now.
How to use this skill
This skill uses progressive disclosure. This file is the map; the detail lives in references/. Do
not try to hold every reference in context. Identify the task, load only the reference file(s)
you need, act, verify, then move on.
Step 0 — Orient before you touch anything
Always establish context first. It determines which commands are correct.
# What are we on? (distro family drives apt-vs-dnf, ufw-vs-firewalld, etc.)
cat /etc/os-release
# Who am I, and can I escalate?
id; sudo -n true 2>/dev/null && echo "sudo OK" || echo "sudo needs password / unavailable"
# Is this a fresh box or a live production server? (changes risk posture)
uptime; ss -tulnp 2>/dev/null | grep LISTEN; systemctl list-units --type=service --state=running --no-pager | head -50
# Is anyone/anything already here? (existing users, web servers, DBs, panels)
getent passwd | awk -F: '$3>=1000 && $3<65534'; command -v nginx apache2 httpd mysql mariadb psql docker 2>/dev/null
A fresh server can be hardened aggressively in one pass. A live production server must be
changed incrementally, one reversible step at a time, because a wrong move can take down a running
service or lock you out. When in doubt, treat it as production.
Step 0.5 — Resolve the secrets the task needs
Before a workflow that requires credentials (SSH key to connect, provider API token to provision or
snapshot, backup passphrase, DB password), resolve them from your environment. Under Paperclip
these arrive as secret_ref bindings injected as environment variables. Read the variable you need;
if it's missing, stop and report exactly which secret to bind rather than hardcoding or guessing.
The env-var contract, the resolve-or-report protocol, and the missing-secret report format live in
references/15-secrets.md (governed by AGENTS.md §7). Resolve at the point of need — don't demand
every secret up front.
Step 1 — Pick the workflow
Provisioning a brand-new server (empty box → secure baseline): work through, in order,
01-provisioning → 02-ssh-hardening → 03-firewall-network → 04-users-access →
06-patch-management → 05-system-hardening. Then add application stack (07) and day-2 ops
(08–10, 12) as the role requires.
Securing / auditing an existing server: start by scoring the current state with the Lynis
before/after checklist in 05-system-hardening, then remediate highest-risk items first: SSH
(02), firewall (03), patching (06), users/access (04), then broader hardening (05).
Re-score to prove improvement.
Standing up an application: 07-web-app-stack for Nginx/Apache/TLS/PHP-FPM/Node/Docker and
database secure-defaults, plus 03-firewall-network to open only the needed ports.
Day-2 operations: 06-patch-management, 08-monitoring, 09-backups-dr,
10-intrusion-detection, 12-log-management, 13-performance.
"My server was compromised": go straight to 11-incident-response. Do not reboot and do not
start "cleaning up" first — you will destroy volatile evidence. Read that file before running
anything.
Repeatable / fleet automation: 14-automation-iac (cloud-init, Ansible + the devsec hardening
collection, building hardened images).
Step 2 — Load the matching reference file
| # |
Reference file |
Use it when you need to… |
| 00 |
references/agent-safety.md |
Understand the full safety protocol behind AGENTS.md (read once, early). |
| 01 |
references/01-provisioning.md |
Turn a fresh box into a baseline: sudo user, keys, hostname, swap, base packages. |
| 02 |
references/02-ssh-hardening.md |
Configure sshd, keys, ciphers/KEX/MACs, fail2ban/CrowdSec, 2FA, SSH CAs. |
| 03 |
references/03-firewall-network.md |
Set up ufw/firewalld/nftables, default-deny, rate limiting, egress, IPv6. |
| 04 |
references/04-users-access.md |
sudo, least privilege, password policy, lockout, banners, access auditing. |
| 05 |
references/05-system-hardening.md |
CIS-aligned OS hardening: mounts, modules, sysctl, AppArmor/SELinux, auditd, AIDE. |
| 06 |
references/06-patch-management.md |
Automatic updates, reboot policy, live patching, staged rollouts. |
| 07 |
references/07-web-app-stack.md |
Nginx/Apache, TLS (Let's Encrypt/Mozilla), PHP-FPM, Node, Docker, DB secure defaults. |
| 08 |
references/08-monitoring.md |
Metrics (Prometheus/node_exporter/Grafana/Netdata), health checks, alerting. |
| 09 |
references/09-backups-dr.md |
3-2-1 backups with restic/borg, offsite/object storage, DB dumps, restore testing. |
| 10 |
references/10-intrusion-detection.md |
fail2ban/CrowdSec, AIDE, rkhunter, ClamAV, Lynis cadence. |
| 11 |
references/11-incident-response.md |
Detect, isolate, investigate, preserve evidence, rebuild vs remediate. |
| 12 |
references/12-log-management.md |
journald persistence, rotation, remote/central logging, auditd rules. |
| 13 |
references/13-performance.md |
sysctl perf tuning, ulimits, swappiness, caching, right-sizing. |
| 14 |
references/14-automation-iac.md |
cloud-init, Ansible/devsec hardening, secrets, hardened images. |
| 15 |
references/15-secrets.md |
Resolve credentials (SSH keys, tokens, passphrases) from your environment; report missing ones. |
Each reference file follows the same shape: Why (the standard/rationale), How (exact paths
and config snippets, Ubuntu/Debian primary with a RHEL-family callout), Pitfalls, Verify,
and How managed services handle it (a corroborating reference point from Forge, Ploi, RunCloud,
GridPane, SpinupWP, ServerPilot, Cloudways).
Distro branching cheat-sheet
Detect the family once (. /etc/os-release; echo $ID $ID_LIKE) and branch. This table is the
recurring divergence; individual reference files add specifics.
| Concern |
Debian / Ubuntu (primary) |
RHEL family (Alma / Rocky / RHEL) |
| Package manager |
apt |
dnf (yum on older) |
| Auto-updates |
unattended-upgrades |
dnf-automatic |
| Default firewall front-end |
ufw |
firewalld |
| Firewall backend |
nftables |
nftables |
| MAC system |
AppArmor (path-based) |
SELinux (label-based) |
| Admin group |
sudo |
wheel |
| SSH auth log |
/var/log/auth.log |
/var/log/secure |
| Add repo tooling |
(built-in) |
dnf install epel-release for extras |
Common to both: systemd, OpenSSH, auditd, AIDE, fail2ban/CrowdSec, restic/borg, Netfilter. When
a reference file gives an Ubuntu command, the RHEL equivalent is usually a package-manager and
front-end swap, not a different concept.
Global principles (apply everywhere)
- Least privilege. Services run as dedicated unprivileged users, never root. Open only the ports
a role needs. Grant only the sudo a task needs.
- Attack-surface reduction. Every installed package, open port, and enabled service is a
liability. Remove/disable what the server doesn't use.
- Defense in depth. No single control is trusted. Key-only SSH and fail2ban and firewall
and patched software — layered, so one failure isn't fatal.
- Verify, don't assume. A config written is not a config in effect. Re-read, validate, and test
the observable behavior after every change.
- Standards over vibes. Prefer CIS/NIST/Mozilla/OpenSSH-documented settings to folklore. Where a
reference file cites a specific cipher list or version, treat it as "correct at time of writing"
and re-verify against current advisories — crypto and CVEs move.
- Secrets come from the environment, never from guesswork. Read every credential (SSH keys,
provider tokens, backup passphrases, DB passwords) from injected environment variables. If a
required one is missing, stop and report exactly which secret to provide — don't hardcode, don't
paste plaintext into chat, don't proceed. See
AGENTS.md §7 and references/15-secrets.md.
Operational checklists
This skill is a runbook, not an executable toolkit: it hands you the exact steps to type and
verify yourself, one reversible action at a time, rather than a script that acts for you. The
multi-step operations most worth doing carefully live as inline checklists in the references — read
the checklist, run each step by hand, and confirm the result before the next:
- Orientation (read-only) —
references/agent-safety.md → Orientation checklist: the facts to
gather before any change (distro family, role, users, listeners, services/panels) and the
fresh-vs-production risk call.
- SSH hardening (anti-lockout) —
references/02-ssh-hardening.md → Apply checklist: the ordered
drop-in → sshd -t → reload → second-session sequence, including the key-presence gate before
disabling passwords.
- Firewall verification —
references/03-firewall-network.md → Verify checklist: confirm
default-deny is in effect and only intended ports are open across ufw/firewalld/nftables.
- Backup restore test —
references/09-backups-dr.md → Restore-test checklist: prove a backup is
restorable by restoring into a scratch location and diffing (a backup you've never restored is not a
backup).
- Lynis before/after scoring —
references/05-system-hardening.md → Lynis before/after
checklist: measure the hardening index before and after (target ≥ 80 for production).
What "done" looks like
For hardening work, "done" is measurable: a Lynis hardening index at or above target (≥ 80 for
production; fresh installs typically start in the 50s–60s), key-only SSH confirmed from a second
session, a default-deny firewall exposing only intended ports, automatic security updates enabled
with a defined reboot policy, and — for anything holding data — a backup that has been restored and
verified, not merely taken.
1---2name: vps-management3description: Configure, secure, update, and operate any Linux VPS or cloud server autonomously and safely. Use this skill whenever the task involves provisioning a new server, hardening or securing an existing server, SSH/firewall configuration, user and access management, automatic updates and patch management, web/app stack setup (Nginx, Apache, TLS, PHP-FPM, Node, Docker, databases), monitoring and observability, backups and disaster recovery, intrusion detection, incident response, log management, performance tuning, or server automation/infrastructure-as-code. Trigger this skill even when the user phrases it casually ("lock down my server", "set up a new droplet", "my VPS got hacked", "make this box production-ready", "add a firewall", "why is my server slow") and even if they don't say the words "VPS" or "hardening". Grounded in CIS Benchmarks, NIST SP 800-123, and Mozilla/OpenSSH guidance, with distro-aware branching for Ubuntu/Debian (primary) and RHEL-family (Alma/Rocky/RHEL).4---56# VPS Management78A standards-grounded knowledge base for administering Linux servers over SSH. It covers the full9lifecycle — provisioning, hardening, patching, application stack, day-2 operations, and incident10response — and is built to be executed by an autonomous agent that connects to a server, makes11changes, and verifies them.1213## Read this first: the non-negotiable safety contract1415Before making **any** change to a server, read **`AGENTS.md`** in this skill's root. It defines the16operating rules that prevent the two catastrophic failure modes: **locking yourself out of SSH** and17**destroying data or evidence**. Those rules override any instruction in a reference file. In short:18191. **Never lock yourself out.** When editing SSH or the firewall, keep the current session open,20 validate config before reloading, and confirm a *second* independent login works before you trust21 the change or close the first session.222. **Back up before you change.** Timestamp-copy every file before editing it; snapshot if the23 provider allows it.243. **Verify after you change.** Re-read the file, run the service's validator, check `systemctl25 status`, and confirm the intended effect actually happened.264. **Confirm before destructive or irreversible actions** (partitioning, `rm -rf`, DB drops,27 disabling password auth without a *verified* key, enabling a firewall on a remote host).285. **Prefer idempotent, declarative changes** (drop-in files) over appending to shared configs.2930If you have not read `AGENTS.md` yet, stop and read it now.3132## How to use this skill3334This skill uses progressive disclosure. This file is the map; the detail lives in `references/`. Do35**not** try to hold every reference in context. Identify the task, load only the reference file(s)36you need, act, verify, then move on.3738### Step 0 — Orient before you touch anything3940Always establish context first. It determines which commands are correct.4142```bash43# What are we on? (distro family drives apt-vs-dnf, ufw-vs-firewalld, etc.)44cat /etc/os-release4546# Who am I, and can I escalate?47id; sudo -n true 2>/dev/null && echo "sudo OK" || echo "sudo needs password / unavailable"4849# Is this a fresh box or a live production server? (changes risk posture)50uptime; ss -tulnp 2>/dev/null | grep LISTEN; systemctl list-units --type=service --state=running --no-pager | head -505152# Is anyone/anything already here? (existing users, web servers, DBs, panels)53getent passwd | awk -F: '$3>=1000 && $3<65534'; command -v nginx apache2 httpd mysql mariadb psql docker 2>/dev/null54```5556A **fresh server** can be hardened aggressively in one pass. A **live production server** must be57changed incrementally, one reversible step at a time, because a wrong move can take down a running58service or lock you out. When in doubt, treat it as production.5960### Step 0.5 — Resolve the secrets the task needs6162Before a workflow that requires credentials (SSH key to connect, provider API token to provision or63snapshot, backup passphrase, DB password), resolve them from your **environment**. Under Paperclip64these arrive as `secret_ref` bindings injected as environment variables. Read the variable you need;65if it's missing, **stop and report exactly which secret to bind** rather than hardcoding or guessing.66The env-var contract, the resolve-or-report protocol, and the missing-secret report format live in67`references/15-secrets.md` (governed by `AGENTS.md` §7). Resolve at the point of need — don't demand68every secret up front.6970### Step 1 — Pick the workflow7172**Provisioning a brand-new server (empty box → secure baseline):** work through, in order,73`01-provisioning` → `02-ssh-hardening` → `03-firewall-network` → `04-users-access` →74`06-patch-management` → `05-system-hardening`. Then add application stack (`07`) and day-2 ops75(`08`–`10`, `12`) as the role requires.7677**Securing / auditing an existing server:** start by scoring the current state with the **Lynis78before/after checklist** in `05-system-hardening`, then remediate highest-risk items first: SSH79(`02`), firewall (`03`), patching (`06`), users/access (`04`), then broader hardening (`05`).80Re-score to prove improvement.8182**Standing up an application:** `07-web-app-stack` for Nginx/Apache/TLS/PHP-FPM/Node/Docker and83database secure-defaults, plus `03-firewall-network` to open only the needed ports.8485**Day-2 operations:** `06-patch-management`, `08-monitoring`, `09-backups-dr`,86`10-intrusion-detection`, `12-log-management`, `13-performance`.8788**"My server was compromised":** go straight to `11-incident-response`. **Do not reboot** and do not89start "cleaning up" first — you will destroy volatile evidence. Read that file before running90anything.9192**Repeatable / fleet automation:** `14-automation-iac` (cloud-init, Ansible + the devsec hardening93collection, building hardened images).9495### Step 2 — Load the matching reference file9697| # | Reference file | Use it when you need to… |98|---|---|---|99| 00 | `references/agent-safety.md` | Understand the full safety protocol behind `AGENTS.md` (read once, early). |100| 01 | `references/01-provisioning.md` | Turn a fresh box into a baseline: sudo user, keys, hostname, swap, base packages. |101| 02 | `references/02-ssh-hardening.md` | Configure sshd, keys, ciphers/KEX/MACs, fail2ban/CrowdSec, 2FA, SSH CAs. |102| 03 | `references/03-firewall-network.md` | Set up ufw/firewalld/nftables, default-deny, rate limiting, egress, IPv6. |103| 04 | `references/04-users-access.md` | sudo, least privilege, password policy, lockout, banners, access auditing. |104| 05 | `references/05-system-hardening.md` | CIS-aligned OS hardening: mounts, modules, sysctl, AppArmor/SELinux, auditd, AIDE. |105| 06 | `references/06-patch-management.md` | Automatic updates, reboot policy, live patching, staged rollouts. |106| 07 | `references/07-web-app-stack.md` | Nginx/Apache, TLS (Let's Encrypt/Mozilla), PHP-FPM, Node, Docker, DB secure defaults. |107| 08 | `references/08-monitoring.md` | Metrics (Prometheus/node_exporter/Grafana/Netdata), health checks, alerting. |108| 09 | `references/09-backups-dr.md` | 3-2-1 backups with restic/borg, offsite/object storage, DB dumps, restore testing. |109| 10 | `references/10-intrusion-detection.md` | fail2ban/CrowdSec, AIDE, rkhunter, ClamAV, Lynis cadence. |110| 11 | `references/11-incident-response.md` | Detect, isolate, investigate, preserve evidence, rebuild vs remediate. |111| 12 | `references/12-log-management.md` | journald persistence, rotation, remote/central logging, auditd rules. |112| 13 | `references/13-performance.md` | sysctl perf tuning, ulimits, swappiness, caching, right-sizing. |113| 14 | `references/14-automation-iac.md` | cloud-init, Ansible/devsec hardening, secrets, hardened images. |114| 15 | `references/15-secrets.md` | Resolve credentials (SSH keys, tokens, passphrases) from your environment; report missing ones. |115116Each reference file follows the same shape: **Why** (the standard/rationale), **How** (exact paths117and config snippets, Ubuntu/Debian primary with a RHEL-family callout), **Pitfalls**, **Verify**,118and **How managed services handle it** (a corroborating reference point from Forge, Ploi, RunCloud,119GridPane, SpinupWP, ServerPilot, Cloudways).120121## Distro branching cheat-sheet122123Detect the family once (`. /etc/os-release; echo $ID $ID_LIKE`) and branch. This table is the124recurring divergence; individual reference files add specifics.125126| Concern | Debian / Ubuntu (primary) | RHEL family (Alma / Rocky / RHEL) |127|---|---|---|128| Package manager | `apt` | `dnf` (`yum` on older) |129| Auto-updates | `unattended-upgrades` | `dnf-automatic` |130| Default firewall front-end | `ufw` | `firewalld` |131| Firewall backend | nftables | nftables |132| MAC system | AppArmor (path-based) | SELinux (label-based) |133| Admin group | `sudo` | `wheel` |134| SSH auth log | `/var/log/auth.log` | `/var/log/secure` |135| Add repo tooling | (built-in) | `dnf install epel-release` for extras |136137Common to both: **systemd, OpenSSH, auditd, AIDE, fail2ban/CrowdSec, restic/borg, Netfilter.** When138a reference file gives an Ubuntu command, the RHEL equivalent is usually a package-manager and139front-end swap, not a different concept.140141## Global principles (apply everywhere)142143- **Least privilege.** Services run as dedicated unprivileged users, never root. Open only the ports144 a role needs. Grant only the sudo a task needs.145- **Attack-surface reduction.** Every installed package, open port, and enabled service is a146 liability. Remove/disable what the server doesn't use.147- **Defense in depth.** No single control is trusted. Key-only SSH *and* fail2ban *and* firewall148 *and* patched software — layered, so one failure isn't fatal.149- **Verify, don't assume.** A config written is not a config in effect. Re-read, validate, and test150 the observable behavior after every change.151- **Standards over vibes.** Prefer CIS/NIST/Mozilla/OpenSSH-documented settings to folklore. Where a152 reference file cites a specific cipher list or version, treat it as "correct at time of writing"153 and re-verify against current advisories — crypto and CVEs move.154- **Secrets come from the environment, never from guesswork.** Read every credential (SSH keys,155 provider tokens, backup passphrases, DB passwords) from injected environment variables. If a156 required one is missing, stop and report exactly which secret to provide — don't hardcode, don't157 paste plaintext into chat, don't proceed. See `AGENTS.md` §7 and `references/15-secrets.md`.158159## Operational checklists160161This skill is a **runbook, not an executable toolkit**: it hands you the exact steps to type and162verify yourself, one reversible action at a time, rather than a script that acts for you. The163multi-step operations most worth doing carefully live as inline checklists in the references — read164the checklist, run each step by hand, and confirm the result before the next:165166- **Orientation (read-only)** — `references/agent-safety.md` → *Orientation checklist*: the facts to167 gather before any change (distro family, role, users, listeners, services/panels) and the168 fresh-vs-production risk call.169- **SSH hardening (anti-lockout)** — `references/02-ssh-hardening.md` → *Apply checklist*: the ordered170 drop-in → `sshd -t` → reload → second-session sequence, including the key-presence gate before171 disabling passwords.172- **Firewall verification** — `references/03-firewall-network.md` → *Verify checklist*: confirm173 default-deny is in effect and only intended ports are open across ufw/firewalld/nftables.174- **Backup restore test** — `references/09-backups-dr.md` → *Restore-test checklist*: prove a backup is175 restorable by restoring into a scratch location and diffing (a backup you've never restored is not a176 backup).177- **Lynis before/after scoring** — `references/05-system-hardening.md` → *Lynis before/after178 checklist*: measure the hardening index before and after (target ≥ 80 for production).179180## What "done" looks like181182For hardening work, "done" is measurable: a Lynis hardening index at or above target (≥ 80 for183production; fresh installs typically start in the 50s–60s), key-only SSH confirmed from a second184session, a default-deny firewall exposing only intended ports, automatic security updates enabled185with a defined reboot policy, and — for anything holding data — a backup that has been **restored and186verified**, not merely taken.