Skip to content

Commit b3e4a64

Browse files
ranjith-srcclaude
andcommitted
Overhaul README with positioning, module rationale, and compatibility table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d0b55d8 commit b3e4a64

1 file changed

Lines changed: 145 additions & 61 deletions

File tree

README.md

Lines changed: 145 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,46 @@
11
# vps-harden
22

3+
**One script. No dependencies. Dry-run first. Lockout protection built in.**
4+
5+
Idempotent Bash script to harden a Debian/Ubuntu VPS. Run it once on a fresh server or repeatedly to verify and fix drift. Every change is previewed before it's applied, and SSH lockout protection rolls back automatically if something goes wrong.
6+
37
[![CI](https://github.com/ranjith-src/vps-harden/actions/workflows/ci.yml/badge.svg)](https://github.com/ranjith-src/vps-harden/actions/workflows/ci.yml)
4-
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
58
[![ShellCheck](https://img.shields.io/badge/ShellCheck-passing-brightgreen)](https://www.shellcheck.net/)
9+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10+
[![GitHub release](https://img.shields.io/github/v/release/ranjith-src/vps-harden)](https://github.com/ranjith-src/vps-harden/releases)
11+
[![GitHub stars](https://img.shields.io/github/stars/ranjith-src/vps-harden?style=social)](https://github.com/ranjith-src/vps-harden)
12+
13+
---
14+
15+
## Table of Contents
16+
17+
- [Why vps-harden](#why-vps-harden)
18+
- [Quick Start](#quick-start)
19+
- [What It Does](#what-it-does)
20+
- [Security Scorecard](#security-scorecard)
21+
- [server-report](#server-report)
22+
- [Parameters](#parameters)
23+
- [Config File](#config-file)
24+
- [Lockout Protection](#lockout-protection)
25+
- [Compatibility](#compatibility)
26+
- [Documentation](#documentation)
27+
- [Contributing](#contributing)
28+
- [License](#license)
29+
30+
---
31+
32+
## Why vps-harden
633

7-
Idempotent VPS security hardening script for Debian/Ubuntu. Run it once on a fresh VPS or repeatedly to verify and fix drift.
34+
Most VPS hardening guides are long checklists you follow manually. Most scripts are interactive, not idempotent, and will break if you run them twice. This tool is different:
835

9-
> **New here?** Start with the [Getting Started guide](docs/getting-started.md) — it walks you through the full setup in about 10 minutes.
36+
- **Idempotent** — checks current state before every action. Safe to re-run anytime.
37+
- **Dry-run mode** — preview every change before applying. Nothing is modified until you're ready.
38+
- **Modular** — run all 14 modules or pick only what you need with `--skip` and `--only`.
39+
- **Lockout protection** — validates SSH config, keys, firewall rules, and AllowUsers before restarting. Auto-rolls back on failure.
40+
- **Non-interactive** — fully CLI-driven. No prompts. Automate it in CI, cron, or cloud-init.
41+
- **Single file, zero dependencies** — just Bash. No Python, no Ansible, no agents.
42+
43+
---
1044

1145
## Quick Start
1246

@@ -16,7 +50,7 @@ Idempotent VPS security hardening script for Debian/Ubuntu. Run it once on a fre
1650
curl -fsSL https://raw.githubusercontent.com/ranjith-src/vps-harden/main/install.sh | bash
1751
```
1852

19-
**First run (dry run):**
53+
**Preview what would change (dry run):**
2054

2155
```bash
2256
sudo vps-harden --username deploy \
@@ -33,51 +67,36 @@ sudo vps-harden --username deploy \
3367
--timezone UTC
3468
```
3569

36-
## Parameters
70+
> **New to VPS security?** The [Getting Started guide](docs/getting-started.md) walks you through everything step by step, including why each module matters.
3771
38-
| Flag | Required | Description |
39-
|------|----------|-------------|
40-
| `--username USER` | Yes | Non-root user to create/harden |
41-
| `--ssh-key KEY` | Yes | SSH public key (file path or inline `ssh-*` string) |
42-
| `--ssh-safety-ip IP` | No | IP to always allow SSH from (safety net before tightening) |
43-
| `--netbird-key KEY` | No | Netbird setup key for mesh VPN (skips VPN module if omitted) |
44-
| `--timezone TZ` | No | System timezone (e.g. `Europe/Amsterdam`, `UTC`) |
45-
| `--hostname NAME` | No | Set system hostname |
46-
| `--auto-reboot` | No | Enable automatic reboot after kernel updates |
47-
| `--openclaw-skill` | No | Add `server-report` skill to an OpenClaw bot (requires OpenClaw installed) |
48-
| `--skip MOD[,MOD]` | No | Comma-separated modules to skip |
49-
| `--only MOD[,MOD]` | No | Run only specified modules |
50-
| `--dry-run` | No | Preview changes without applying them |
51-
| `--config FILE` | No | Load parameters from a `KEY=VALUE` file |
52-
| `--no-color` | No | Disable colored output (useful for logging) |
53-
| `--verbose` | No | Show command output instead of redirecting to log |
54-
| `--version` | No | Print version and exit |
55-
| `-h`, `--help` | No | Show usage help |
72+
---
5673

57-
## Modules
58-
59-
Modules run in this order. Each is idempotent — safe to re-run.
60-
61-
| Module | What it does |
62-
|--------|-------------|
63-
| `prereqs` | Installs curl, wget, jq, htop, tree, unzip, ufw, fail2ban |
64-
| `user` | Creates non-root user, adds to sudo group, deploys SSH keys |
65-
| `ssh` | Writes `/etc/ssh/sshd_config.d/00-hardening.conf` — disables root login, sets MaxAuthTries 3, AllowUsers, banner. Includes lockout protection with automatic rollback. |
66-
| `firewall` | Configures UFW: deny incoming, allow outgoing, allow SSH |
67-
| `fail2ban` | Configures fail2ban with UFW integration (3 retries, 3h ban) |
68-
| `sysctl` | Kernel hardening: SYN cookies, disable ICMP redirects/source routing, martian logging, reverse path filtering |
69-
| `netbird` | Installs Netbird mesh VPN and connects with setup key (skipped if no key) |
70-
| `firewall_tighten` | Allows traffic on VPN tunnel, restricts SSH to safety IP, removes broad SSH rules |
71-
| `sops` | Installs SOPS + age for encrypted secrets management, generates keypair |
72-
| `upgrades` | Enables unattended-upgrades, optional auto-reboot |
73-
| `monitoring` | Installs auditd + logwatch, deploys audit rules, installs [`server-report`](#server-report) CLI, adds sudoers NOPASSWD rule |
74-
| `shell` | Sets umask 027, configures bash history, scans for plaintext secrets |
75-
| `misc` | Sets timezone/hostname, locks root password, restricts `su` to sudo group |
76-
| `verify` | Runs all checks and prints a security scorecard |
74+
## What It Does
75+
76+
14 modules run in order. Each is idempotent — safe to re-run.
77+
78+
| Module | What it does | Why |
79+
|--------|-------------|-----|
80+
| `prereqs` | Installs curl, wget, jq, htop, tree, unzip, ufw, fail2ban | Foundation packages for the rest of the script |
81+
| `user` | Creates non-root user, adds to sudo, deploys SSH keys | Running as root is dangerous — sudo gives the same power with an audit trail |
82+
| `ssh` | Disables root login, MaxAuthTries 3, AllowUsers, banner | SSH is the #1 attack surface. Bots find your server within minutes |
83+
| `firewall` | UFW: deny incoming, allow outgoing, allow SSH | Default-deny means only services you explicitly allow are reachable |
84+
| `fail2ban` | 3 retries, 3h ban, UFW integration | Stops brute-force bots from hammering your auth log |
85+
| `sysctl` | SYN cookies, disable ICMP redirects/source routing, martian logging, RP filtering | Kernel-level protection against floods, routing attacks, spoofed packets |
86+
| `netbird` | Installs Netbird mesh VPN, connects with setup key | Hide SSH from the public internet — only VPN peers can reach it |
87+
| `firewall_tighten` | Allows VPN tunnel traffic, restricts SSH to safety IP, removes broad rules | Once VPN is up, close the public SSH door |
88+
| `sops` | Installs SOPS + age, generates encryption keypair | Encrypted-at-rest secrets management for API keys and credentials |
89+
| `upgrades` | Enables unattended-upgrades, optional auto-reboot | Most breaches exploit known vulnerabilities with patches already available |
90+
| `monitoring` | Installs auditd + logwatch, deploys audit rules, installs [`server-report`](#server-report) | You can't protect what you can't see |
91+
| `shell` | umask 027, bash history with timestamps, plaintext secret scanning | Prevents accidental world-readable files, aids forensics |
92+
| `misc` | Timezone, hostname, lock root password, restrict `su` | Locks down remaining escalation paths |
93+
| `verify` | Runs all checks, prints security scorecard | Single view of your security posture |
94+
95+
---
7796

7897
## Security Scorecard
7998

80-
The `verify` module prints a scorecard at the end:
99+
The `verify` module prints a scorecard at the end of every run:
81100

82101
```
83102
====================================================================
@@ -87,63 +106,128 @@ The `verify` module prints a scorecard at the end:
87106
[PASS] MaxAuthTries = 3
88107
[PASS] UFW active, default deny
89108
[PASS] fail2ban sshd jail active
90-
[WARN] Netbird installed but wt0 not up
109+
[PASS] SYN cookies enabled
110+
[PASS] auditd active
111+
[PASS] Audit rules loaded (13 rules)
112+
[PASS] logwatch installed
113+
[PASS] server-report installed
114+
[PASS] Root password locked
115+
[WARN] Netbird not installed
91116
...
92117
--------------------------------------------------------------------
93-
SCORE: 18 PASSED | 2 WARNING | 0 FAILED
118+
SCORE: 22 PASSED | 1 WARNING | 0 FAILED
94119
--------------------------------------------------------------------
95120
```
96121

97-
- **PASS** — correctly configured
98-
- **WARN** — not critical but should be reviewed
99-
- **FAIL** — security issue that needs fixing
122+
Run the scorecard anytime to check for drift:
123+
124+
```bash
125+
sudo vps-harden --username deploy --ssh-key ~/.ssh/authorized_keys --only verify
126+
```
127+
128+
---
100129

101130
## server-report
102131

103132
The `monitoring` module installs a companion CLI for quick health checks:
104133

105134
```bash
106-
sudo server-report summary # Uptime, load, memory, disk, SSH, services, updates
107-
sudo server-report auth # Failed/successful logins, sessions, banned IPs
108-
sudo server-report audit # Audit events by key (ssh_config, user_db, etc.)
135+
sudo server-report summary # Uptime, load, memory, disk, SSH attempts, services, updates
136+
sudo server-report auth # Failed/successful logins (48h), sessions, banned IPs
137+
sudo server-report audit # Audit events by key (ssh_config, user_db, sudoers, etc.)
109138
sudo server-report full # Full logwatch report (today)
110139
```
111140

112-
All output is plain text with no colors — safe for piping, logging, or chatbot consumption. Commands degrade gracefully if tools (auditd, logwatch, fail2ban) are not installed.
141+
All output is plain text — no colors, no control codes. Safe for piping, logging, or chatbot consumption. Commands degrade gracefully if tools (auditd, logwatch, fail2ban) are not installed.
142+
143+
**OpenClaw bot integration:** Add `--openclaw-skill` to automatically configure server-report as a chatbot skill, so your bot can answer "how's the server?" on demand.
144+
145+
---
146+
147+
## Parameters
148+
149+
| Flag | Required | Description |
150+
|------|----------|-------------|
151+
| `--username USER` | Yes | Non-root user to create/harden |
152+
| `--ssh-key KEY` | Yes | SSH public key (file path or inline `ssh-*` string) |
153+
| `--ssh-safety-ip IP` | No | IP to always allow SSH from (safety net before tightening) |
154+
| `--netbird-key KEY` | No | Netbird setup key for mesh VPN (skips VPN module if omitted) |
155+
| `--timezone TZ` | No | System timezone (e.g. `Europe/Amsterdam`, `UTC`) |
156+
| `--hostname NAME` | No | Set system hostname |
157+
| `--auto-reboot` | No | Enable automatic reboot after kernel updates |
158+
| `--openclaw-skill` | No | Add `server-report` skill to an OpenClaw bot |
159+
| `--skip MOD[,MOD]` | No | Comma-separated modules to skip |
160+
| `--only MOD[,MOD]` | No | Run only specified modules |
161+
| `--dry-run` | No | Preview changes without applying them |
162+
| `--config FILE` | No | Load parameters from a `KEY=VALUE` file |
163+
| `--no-color` | No | Disable colored output |
164+
| `--verbose` | No | Show command output instead of redirecting to log |
165+
| `--version` | No | Print version and exit |
166+
| `-h`, `--help` | No | Show usage help |
167+
168+
---
113169

114170
## Config File
115171

116-
Instead of passing flags, use a config file:
172+
Instead of passing flags, use a config file for repeatable setups:
117173

118174
```bash
119-
sudo vps-harden --config config.env
175+
sudo vps-harden --config /root/harden.env
120176
```
121177

122178
See [`examples/config.env`](examples/config.env) for the format.
123179

124-
## Requirements
125-
126-
- **OS:** Debian 11+ or Ubuntu 20.04+
127-
- **Access:** Root (via `sudo`)
128-
- **Network:** Outbound internet access (for package installs)
180+
---
129181

130182
## Lockout Protection
131183

132-
The SSH module includes multiple safeguards:
184+
The SSH module includes multiple safeguards to prevent you from losing access:
133185

134186
1. Validates `sshd` config syntax before restarting
135187
2. Verifies SSH keys exist in `authorized_keys`
136188
3. Checks `AllowUsers` includes the target user
137189
4. Confirms UFW has an SSH allow rule
138190
5. Rolls back config automatically if any check fails
139191

192+
If something goes wrong, your current SSH session stays alive and the config is reverted.
193+
194+
---
195+
196+
## Compatibility
197+
198+
| OS | Version | Status |
199+
|----|---------|--------|
200+
| Ubuntu | 24.04 LTS | Tested |
201+
| Ubuntu | 22.04 LTS | Tested |
202+
| Ubuntu | 20.04 LTS | Tested |
203+
| Debian | 12 (Bookworm) | Supported |
204+
| Debian | 11 (Bullseye) | Supported |
205+
206+
**Architecture:** amd64, arm64
207+
208+
**Requirements:** Root access (via `sudo`), outbound internet for package installs.
209+
210+
---
211+
212+
## Documentation
213+
214+
- **[Getting Started](docs/getting-started.md)** — Step-by-step onboarding guide with prerequisites, module explanations, troubleshooting
215+
- **[Changelog](https://github.com/ranjith-src/vps-harden/releases)** — Release notes for each version
216+
- **[Config Example](examples/config.env)** — Sample configuration file
217+
218+
---
219+
140220
## Contributing
141221

142222
1. Fork the repo
143223
2. Create a feature branch
144224
3. Ensure `shellcheck vps-harden.sh` passes
145225
4. Submit a pull request
146226

227+
See open issues labeled [`good-first-issue`](https://github.com/ranjith-src/vps-harden/labels/good%20first%20issue) for ideas.
228+
229+
---
230+
147231
## License
148232

149233
[MIT](LICENSE)

0 commit comments

Comments
 (0)