|
| 1 | +# harden-ubuntu-lts-24.sh |
| 2 | + |
| 3 | +Ubuntu 24.04 LTS server hardening script with interactive stage-by-stage execution. |
| 4 | + |
| 5 | +## Quick Start |
| 6 | + |
| 7 | +```bash |
| 8 | +# Download |
| 9 | +curl -fsSL https://raw.githubusercontent.com/statisticsnorway/statbus/main/doc/harden-ubuntu-lts-24.sh -o harden.sh |
| 10 | +chmod +x harden.sh |
| 11 | + |
| 12 | +# Run (will prompt for configuration, then each stage) |
| 13 | +sudo ./harden.sh |
| 14 | +``` |
| 15 | + |
| 16 | +## Features |
| 17 | + |
| 18 | +- **Interactive**: Prompts Yes/No before each stage - safe to run from uncomfortable consoles |
| 19 | +- **Verification**: Automatic checks after each stage with pass/fail indicators |
| 20 | +- **Configurable**: Settings stored in `~/.harden-ubuntu.env` |
| 21 | +- **Non-interactive mode**: `--non-interactive` flag for automation |
| 22 | + |
| 23 | +## Stages |
| 24 | + |
| 25 | +| # | Stage | What it does | |
| 26 | +|---|-------|--------------| |
| 27 | +| 0 | HTTPS APT Sources *(optional)* | Switch to HTTPS mirror for networks that block HTTP | |
| 28 | +| 1 | Base System | etckeeper, eternal bash history, locale configuration | |
| 29 | +| 2 | SSH Hardening | Disable password auth, root password login, empty passwords | |
| 30 | +| 3 | Auto Updates | unattended-upgrades with nightly schedule, email notifications | |
| 31 | +| 4 | Security Tools *(optional)* | CrowdSec IDS + firewall bouncer, UFW firewall | |
| 32 | +| 5 | Core Tools | neovim, htop, ripgrep, Docker CE + compose | |
| 33 | +| 6 | User Setup | devops user, GitHub SSH keys, Homebrew, helix/bottom/zellij | |
| 34 | +| 7 | Caddy *(optional)* | Caddy web server with optional plugin support via xcaddy | |
| 35 | + |
| 36 | +## Configuration |
| 37 | + |
| 38 | +On first run, you'll be prompted for: |
| 39 | + |
| 40 | +| Variable | Description | |
| 41 | +|----------|-------------| |
| 42 | +| `ADMIN_EMAIL` | Email for unattended-upgrades notifications | |
| 43 | +| `GITHUB_USERS` | Space-separated GitHub usernames for SSH key fetching | |
| 44 | +| `EXTRA_LOCALES` | Extra locales to enable (e.g., `nb_NO fr_FR`) | |
| 45 | +| `CADDY_PLUGINS` | Caddy plugins for custom build (empty = standard Caddy) | |
| 46 | + |
| 47 | +Configuration is saved to `~/.harden-ubuntu.env` and reused on subsequent runs. |
| 48 | + |
| 49 | +### Caddy Plugin Options |
| 50 | + |
| 51 | +When prompted, select by number or enter custom plugin paths: |
| 52 | + |
| 53 | +1. `github.com/mholt/caddy-l4` - Layer 4 (TCP/UDP) proxying |
| 54 | +2. `github.com/caddy-dns/cloudflare` - Cloudflare DNS for ACME |
| 55 | +3. `github.com/caddy-dns/namedotcom` - Name.com DNS for ACME |
| 56 | +4. `github.com/caddy-dns/route53` - AWS Route53 DNS for ACME |
| 57 | +5. `github.com/caddy-dns/digitalocean` - DigitalOcean DNS for ACME |
| 58 | +6. `github.com/greenpau/caddy-security` - Authentication/Authorization |
| 59 | + |
| 60 | +## Non-Interactive Mode |
| 61 | + |
| 62 | +For automation, create the `.env` file first: |
| 63 | + |
| 64 | +```bash |
| 65 | +cat > ~/.harden-ubuntu.env << 'EOF' |
| 66 | +ADMIN_EMAIL="admin@example.com" |
| 67 | +GITHUB_USERS="githubuser1 githubuser2" |
| 68 | +EXTRA_LOCALES="nb_NO fr_FR" |
| 69 | +CADDY_PLUGINS="" |
| 70 | +EOF |
| 71 | + |
| 72 | +sudo ./harden.sh --non-interactive |
| 73 | +``` |
| 74 | + |
| 75 | +## Post-Installation |
| 76 | + |
| 77 | +After running: |
| 78 | + |
| 79 | +1. **Test SSH access** as `devops` user before closing console session |
| 80 | +2. **Configure Caddy** at `/etc/caddy/Caddyfile` |
| 81 | +3. **Review CrowdSec**: `cscli metrics`, `cscli decisions list` |
| 82 | +4. **Check firewall**: `ufw status` |
| 83 | + |
| 84 | +## What Gets Hardened |
| 85 | + |
| 86 | +### APT Sources (Stage 0) |
| 87 | +- Switches from HTTP to HTTPS mirror (`mirrors.edge.kernel.org`) |
| 88 | +- Required for networks that block unencrypted HTTP traffic |
| 89 | + |
| 90 | +> **Note**: Skip Stage 0 if your network allows HTTP or you prefer a different mirror. |
| 91 | +
|
| 92 | +### SSH (`/etc/ssh/sshd_config.d/hardening.conf`) |
| 93 | +- Root login: key-only (no password) |
| 94 | +- Password authentication: disabled |
| 95 | +- Empty passwords: disabled |
| 96 | +- Keyboard-interactive auth: disabled |
| 97 | + |
| 98 | +### Firewall (UFW) |
| 99 | +- Default: deny incoming, allow outgoing |
| 100 | +- Allowed: SSH (22), HTTP (80), HTTPS (443), PostgreSQL (5432) |
| 101 | + |
| 102 | +> **Note**: Skip Stage 4 if your server is on a private network with existing firewall infrastructure. |
| 103 | +
|
| 104 | +### Intrusion Detection (CrowdSec) |
| 105 | +- SSH brute-force protection |
| 106 | +- Caddy log analysis (prepared) |
| 107 | +- nftables firewall bouncer for automatic IP banning |
| 108 | + |
| 109 | +### Memory Tuning (`/etc/sysctl.d/20-server-tuning.conf`) |
| 110 | +- `vm.swappiness=1` - Minimize swapping for server workloads |
| 111 | +- Dirty page limits tuned for predictable I/O |
| 112 | + |
| 113 | +## Requirements |
| 114 | + |
| 115 | +- Ubuntu 24.04 LTS |
| 116 | +- Root/sudo access |
| 117 | +- Internet connection (for package downloads) |
| 118 | + |
| 119 | +## STATBUS Integration |
| 120 | + |
| 121 | +When using this script to prepare a server for STATBUS deployment: |
| 122 | + |
| 123 | +1. **Stage 0 (HTTPS Sources)** — Run if your network blocks HTTP traffic |
| 124 | +2. **Run Stages 1-3, 5-6** — Essential hardening and tools |
| 125 | +3. **Stage 4 (Security Tools)** — Skip if on a private network with existing firewall |
| 126 | +4. **Stage 7 (Caddy)** — Skip, as STATBUS runs Caddy inside Docker |
| 127 | + |
| 128 | +After hardening, continue with the [STATBUS Deployment Guide](DEPLOYMENT.md). |
| 129 | + |
| 130 | +## License |
| 131 | + |
| 132 | +MIT |
0 commit comments