linux-security is an open-source toolkit of bash scripts for hardening Ubuntu and Debian servers.
Two profiles: baseline (any server) and
web-server (Apache addendum).
One config file, one command — from bare server to verified security baseline.
curl -fsSL https://raw.githubusercontent.com/davidwhittington/linux-security/main/install.sh | bash nano /etc/linux-security/config.env linux-security-bootstrap --profile baseline
/opt/linux-security/ · config in /etc/linux-security/ · Run as root--dry-run
Run bash bootstrap.sh and get a fully hardened server covering every major security control area.
UFW default-deny ingress, SSH/HTTP/HTTPS allowlist, connection rate limiting on ports 80 and 443.
Password auth off, modern ciphers only (AES-GCM, ChaCha20), HMAC-SHA2/ETM MACs, Curve25519 key exchange. MaxAuthTries 3.
SSH + Apache jails: apache-auth, apache-badbots (1-strike, 24h ban), apache-noscript. Configurable via config.env.
ServerTokens Prod, HSTS, CSP, X-Content-Type-Options, Referrer-Policy. TRACE off, mod_status off, .git access blocked.
Logwatch daily HTML email digest. GoAccess daily traffic report. Monthly apt upgrade + disk + fail2ban report via msmtp.
Weekly certbot expiry monitor, independent of the monthly report. Fires when any cert is within 30 days of expiry.
ClamAV weekly web-root scan with quarantine. rkhunter rootkit scanner with clean baseline. ModSecurity + OWASP CRS.
sysctl: ICMP redirects off, martian logging, IP forwarding off, TCP SYN cookies, reverse path filtering enabled.
9 read-only posture scripts with color-coded PASS/WARN/FAIL. Ports, SSH config, headers, AppArmor, SUID drift, and more.
Every script backs up files before modifying. rollback.sh restores .bak files per-script or all at once.
Scripts are split into two layers. All support --dry-run.
--json and --report html available
From a fresh Ubuntu 24.04 or Debian 12 server to a verified security baseline.
# 1. Install on the server (run as root) curl -fsSL https://raw.githubusercontent.com/davidwhittington/linux-security/main/install.sh | bash # 2. Fill in your config — email, SSH port, SMTP relay nano /etc/linux-security/config.env # 3. Run bootstrap (baseline = any server; web-server = +Apache/PHP/MySQL) linux-security-bootstrap --profile baseline --dry-run # preview first linux-security-bootstrap --profile baseline # apply # 4. Run the full posture audit linux-security-audit --profile baseline
# 1. Clone the repo git clone https://github.com/davidwhittington/linux-security.git cd linux-security # 2. Fill in your config cp config.env.example config.env nano config.env # 3. Bootstrap and audit bash bootstrap.sh --profile baseline --dry-run bash bootstrap.sh --profile baseline bash scripts/audit/audit.sh --profile baseline
Pass --dry-run to preview every change before anything touches the system.
Reference documentation for configuration, operations, and architecture.
Every config.env variable explained. SMTP provider table, CSP examples, per-server config.env.local override pattern.
Operational playbook — cert renewal, SSH key rotation, fail2ban unbanning, disk alerts, rollback, and adding domains.
Config discovery chain, script execution order, bootstrap orchestration, audit exit codes, and the public/private submodule split.
Minimum security requirements, fail2ban config blocks, verification commands, and recommended audit cadence.
Full version history following Keep a Changelog v1.0.0. Every script addition, change, and fix documented.
Audit reports, server inventories, and per-server config files contain real IPs and hostnames that shouldn't live in a public repo. linux-security uses a git submodule pattern to keep the tooling public and the server data private:
# Public repo — hardening scripts, audit tools, docs linux-security/ scripts/core/hardening/ scripts/web/hardening/ scripts/core/audit/ scripts/web/audit/ profiles/ bootstrap.sh config.env # Private submodule — your own private repo linux-security/private/ servers/server1.example.com/ config.env.local AUDIT_REPORT.md servers/inventory.yml
Clone the repo, initialize the private submodule pointing at your own private GitHub repo, and your server inventory and audit history stay yours.