diff --git a/guide.md b/guide.md index 7e70f83..8365f24 100644 --- a/guide.md +++ b/guide.md @@ -149,176 +149,6 @@ When typing a password in the terminal, **nothing appears on screen** — no dot If you get "Connection refused" or "Connection timed out," wait a minute — your server might still be starting up. Try again after 60 seconds. If it still doesn't work, double-check the IP address. [/callout] -[step: Secure Your Server] - -Before installing anything else, let's lock down your server with a **firewall**, **brute-force protection**, **automatic security updates**, and **Docker log management**. This takes about 3 minutes and prevents the vast majority of problems before they start. - -Think of it this way: your server is now on the public internet, and automated bots are already scanning it looking for easy targets. These steps stop them cold and keep your server healthy long-term. - -**First, update your server's software:** - -This makes sure you have the latest security patches. It's the equivalent of running Windows Update or updating your phone. - -[code:bash] -apt update && apt upgrade -y -[/code] - -This may take a minute. If you see a pink/purple screen asking about restarting services, just press **Enter** to accept the defaults. - -**Install the firewall, fail2ban, and automatic updates:** - -[code:bash] -apt install -y ufw fail2ban unattended-upgrades -[/code] - -This installs three tools: -- [UFW](https://wiki.ubuntu.com/UncomplicatedFirewall) (Uncomplicated Firewall) — blocks all network traffic except what you explicitly allow -- [Fail2ban](https://www.fail2ban.org/) — watches for repeated failed login attempts and automatically bans those IP addresses -- [Unattended Upgrades](https://wiki.debian.org/UnattendedUpgrades) — automatically installs security patches so you don't have to remember to do it manually - -**Configure the firewall:** - -You need to tell the firewall which types of traffic to allow. Your server needs exactly three things open: - -[code:bash] -ufw allow OpenSSH -ufw allow 80/tcp -ufw allow 443/tcp -[/code] - -Here's what each line does: -- `ufw allow OpenSSH` — allows SSH connections (port 22), so you can keep connecting to your server remotely. **This line is critical** — without it, you'd be locked out of your own server. -- `ufw allow 80/tcp` — allows HTTP web traffic (needed for SSL certificate setup) -- `ufw allow 443/tcp` — allows HTTPS web traffic (your actual website) - -Everything else (thousands of other ports) is blocked by default. That's exactly what you want. - -**Turn on the firewall:** - -[code:bash] -ufw enable -[/code] - -You'll see a warning that says "Command may disrupt existing SSH connections." Type `y` and press Enter. Your current connection will stay active — the warning is just being cautious. - -[callout:danger] -**Make sure you ran `ufw allow OpenSSH` before this step.** If you enable the firewall without allowing SSH first, you will be locked out of your server and will need to use your VPS provider's emergency web console to fix it. -[/callout] - -**Verify the firewall is working:** - -[code:bash] -ufw status -[/code] - -You should see output like this: - -[terminal] -$ ufw status -Status: active - -To Action From --- ------ ---- -OpenSSH ALLOW Anywhere -80/tcp ALLOW Anywhere -443/tcp ALLOW Anywhere -OpenSSH (v6) ALLOW Anywhere (v6) -80/tcp (v6) ALLOW Anywhere (v6) -443/tcp (v6) ALLOW Anywhere (v6) -[/terminal] - -If you see `Status: active` with those three rules listed, your firewall is properly configured. - -**Configure fail2ban:** - -Fail2ban works out of the box for SSH protection with sensible defaults, but let's make sure it's running: - -[code:bash] -systemctl enable fail2ban -systemctl start fail2ban -[/code] - -The first command tells fail2ban to start automatically whenever your server reboots. The second starts it right now. - -You can verify it's running with: - -[code:bash] -fail2ban-client status sshd -[/code] - -[terminal] -$ fail2ban-client status sshd -Status for the jail: sshd -|- Filter -| |- Currently failed: 0 -| |- Total failed: 0 -| `- File list: /var/log/auth.log -`- Actions - |- Currently banned: 0 - |- Total banned: 0 - `- Banned IP list: -[/terminal] - -This shows fail2ban is monitoring SSH login attempts. After a few hours online, you'll likely see banned IPs here — that's fail2ban doing its job, blocking automated bots that try to guess passwords. - -[callout:info] -**What does fail2ban actually do?** By default, if someone (or a bot) fails to log in via SSH 5 times within 10 minutes, fail2ban bans their IP address for 10 minutes. This makes brute-force password guessing effectively impossible — a bot that can try thousands of passwords per second gets cut off after just 5 attempts. -[/callout] - -**Enable automatic security updates:** - -Your server should install security patches on its own — you don't want to rely on remembering to SSH in and run updates. Enable it with: - -[code:bash] -dpkg-reconfigure -plow unattended-upgrades -[/code] - -When asked "Automatically download and install stable updates?", select **Yes** and press Enter. - -That's all it takes. From now on, your server will check for and install security updates daily in the background. It won't restart your server or touch your website — it only patches the underlying operating system. - -[callout:info] -**Will auto-updates break anything?** No. Unattended upgrades only installs security patches for your operating system (Ubuntu/Debian), not major version upgrades. It won't touch Docker, WordPress, or anything in your website. It's the same type of automatic update your phone does overnight. -[/callout] - -**Set up Docker log rotation:** - -Docker containers generate log files that grow over time. Without a size limit, these logs can eventually fill up your server's disk. Let's set a sensible limit now so this never becomes a problem. - -Create the Docker configuration file: - -[code:bash] -mkdir -p /etc/docker -cat > /etc/docker/daemon.json << 'EOF' -{ - "log-driver": "json-file", - "log-opts": { - "max-size": "10m", - "max-file": "3" - } -} -EOF -[/code] - -This tells Docker to: -- Keep each log file to a maximum of **10 megabytes** -- Keep at most **3** rotated log files per container -- That's a maximum of 30 MB of logs per container — plenty for troubleshooting, but no risk of filling your disk - -[callout:info] -You're running this **before** the WebsiteBox installer, so Docker may or may not be installed yet. That's fine — if Docker isn't installed yet, the file will be waiting for it. If Docker is already installed, restart it to apply the setting: `systemctl restart docker` -[/callout] - -Now restart Docker if it's already running (if it's not installed yet, this will harmlessly fail): - -[code:bash] -systemctl restart docker 2>/dev/null || true -[/code] - -[callout:tip] -**That's it for server setup.** You now have a firewall blocking all unnecessary ports, fail2ban stopping brute-force attacks, automatic security updates keeping your OS patched, and Docker log rotation preventing disk bloat. Combined with the security features WebsiteBox sets up later (Wordfence, rate-limited logins, encrypted HTTPS), your server will be well-protected and low-maintenance. For further hardening down the road, see the "Going Further" step at the end of this guide. -[/callout] - [step: Run the Installer] Now for the easy part. Copy and paste this single command into your terminal and press Enter: @@ -333,11 +163,60 @@ curl -fsSL https://raw.githubusercontent.com/websitebox/websitebox/main/install. This one command does everything needed to prepare your server: -1. **Installs Docker** — the software that packages and runs your website (think of it as a container system that keeps everything organized and isolated) -2. **Downloads WebsiteBox** — the project files that define your website setup -3. **Starts the setup wizard** — an interactive questionnaire to configure your site (covered in the next step) +1. **Updates your system** — installs the latest security patches +2. **Secures your server** — sets up a firewall ([UFW](https://wiki.ubuntu.com/UncomplicatedFirewall)), brute-force protection ([Fail2ban](https://www.fail2ban.org/)), and automatic security updates ([Unattended Upgrades](https://wiki.debian.org/UnattendedUpgrades)) +3. **Installs Docker** — the software that packages and runs your website (think of it as a container system that keeps everything organized and isolated) +4. **Configures log rotation** — prevents Docker logs from filling up your disk over time +5. **Downloads WebsiteBox** — the project files that define your website setup +6. **Starts the setup wizard** — an interactive questionnaire to configure your site (covered in the next step) -You'll see text scrolling by as things install. This is normal — let it run. It typically takes 1-2 minutes depending on your server's speed. +You'll see output scrolling by as each step completes. Here's roughly what to expect: + +[terminal] +═══════════════════════════════════════════════════════════ + WebsiteBox Installer +═══════════════════════════════════════════════════════════ + +Detected: ubuntu 22.04 + +─────────────────────────────────────────────────────────── + Securing your server... +─────────────────────────────────────────────────────────── +Updating system packages... +System packages updated. +Installing firewall, fail2ban, and automatic updates... +Configuring firewall... +Firewall enabled: SSH, HTTP, and HTTPS allowed. All other ports blocked. +Fail2ban enabled: brute-force SSH protection active. +Automatic security updates enabled. +Docker log rotation configured (10MB max per log, 3 files per container). + + Server secured: + Firewall: active (SSH, HTTP, HTTPS only) + Fail2ban: active (SSH brute-force protection) + Auto-updates: enabled (daily security patches) + Docker log limits: configured (30MB max per container) + +Installing Docker... +Docker installation complete. +Cloning WebsiteBox... + +═══════════════════════════════════════════════════════════ + WebsiteBox Setup Wizard +═══════════════════════════════════════════════════════════ +[/terminal] + +The entire process takes 2-3 minutes. If you see a pink/purple screen asking about restarting services during the update, just press **Enter** to accept the defaults. + +When the "WebsiteBox Setup Wizard" header appears, the installer is done and the setup wizard has started — that's covered in the next step. + +[callout:info] +**What just got secured?** The installer automatically set up four layers of protection: +- **[UFW firewall](https://wiki.ubuntu.com/UncomplicatedFirewall)** — blocks all network traffic except SSH (so you can connect), HTTP (port 80), and HTTPS (port 443). Everything else is locked down. +- **[Fail2ban](https://www.fail2ban.org/)** — if someone (or a bot) fails to log in via SSH 5 times in 10 minutes, their IP address is automatically banned. This stops brute-force password guessing. +- **[Unattended Upgrades](https://wiki.debian.org/UnattendedUpgrades)** — your server will automatically install security patches daily. It only patches the operating system — it won't touch Docker, WordPress, or your website. +- **Docker log rotation** — container logs are capped at 30 MB each so they can't fill up your disk over months of running. +[/callout] [callout:warning] **If you get a "permission denied" error**, your server may need administrator privileges. Try this version instead: diff --git a/install.sh b/install.sh index 8fb134b..cbe31ca 100755 --- a/install.sh +++ b/install.sh @@ -63,6 +63,82 @@ esac echo "Detected: ${OS_ID} ${OS_VERSION}" +# --- Secure the Server --- + +echo "" +echo "───────────────────────────────────────────────────────────" +echo " Securing your server..." +echo "───────────────────────────────────────────────────────────" + +# Update system packages +echo "Updating system packages..." +$SUDO apt-get update -qq +$SUDO apt-get upgrade -y -qq +echo "System packages updated." + +# Install firewall, fail2ban, and automatic updates +echo "Installing firewall, fail2ban, and automatic updates..." +$SUDO apt-get install -y -qq ufw fail2ban unattended-upgrades + +# Configure firewall — allow SSH first to avoid lockout +if ! $SUDO ufw status | grep -q "Status: active"; then + echo "Configuring firewall..." + $SUDO ufw allow OpenSSH + $SUDO ufw allow 80/tcp + $SUDO ufw allow 443/tcp + $SUDO ufw --force enable + echo "Firewall enabled: SSH, HTTP, and HTTPS allowed. All other ports blocked." +else + # Firewall already active — just make sure our ports are open + $SUDO ufw allow OpenSSH 2>/dev/null || true + $SUDO ufw allow 80/tcp 2>/dev/null || true + $SUDO ufw allow 443/tcp 2>/dev/null || true + echo "Firewall already active. Verified SSH, HTTP, and HTTPS are allowed." +fi + +# Enable fail2ban +$SUDO systemctl enable fail2ban --quiet 2>/dev/null || true +$SUDO systemctl start fail2ban 2>/dev/null || true +echo "Fail2ban enabled: brute-force SSH protection active." + +# Enable automatic security updates (non-interactive) +echo 'Unattended-Upgrade::Allowed-Origins { + "${distro_id}:${distro_codename}"; + "${distro_id}:${distro_codename}-security"; + "${distro_id}ESMApps:${distro_codename}-apps-security"; + "${distro_id}ESM:${distro_codename}-infra-security"; +}; +Unattended-Upgrade::AutoFixInterruptedDpkg "true"; +Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; +Unattended-Upgrade::Remove-Unused-Dependencies "true";' | $SUDO tee /etc/apt/apt.conf.d/50unattended-upgrades-websitebox > /dev/null + +echo 'APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Unattended-Upgrade "1";' | $SUDO tee /etc/apt/apt.conf.d/20auto-upgrades > /dev/null +echo "Automatic security updates enabled." + +# Configure Docker log rotation (create config before Docker install) +$SUDO mkdir -p /etc/docker +if [ ! -f /etc/docker/daemon.json ]; then + echo '{ + "log-driver": "json-file", + "log-opts": { + "max-size": "10m", + "max-file": "3" + } +}' | $SUDO tee /etc/docker/daemon.json > /dev/null + echo "Docker log rotation configured (10MB max per log, 3 files per container)." +else + echo "Docker daemon.json already exists. Skipping log rotation config." +fi + +echo "" +echo " Server secured:" +echo " Firewall: active (SSH, HTTP, HTTPS only)" +echo " Fail2ban: active (SSH brute-force protection)" +echo " Auto-updates: enabled (daily security patches)" +echo " Docker log limits: configured (30MB max per container)" +echo "" + # --- Install Docker if needed --- DOCKER_JUST_INSTALLED=false @@ -103,6 +179,11 @@ else $SUDO systemctl enable docker echo "Docker installation complete." +else + # Docker exists — restart to pick up daemon.json if it was just created + if [ -f /etc/docker/daemon.json ]; then + $SUDO systemctl restart docker 2>/dev/null || true + fi fi # --- Clone Repository ---