DEV Community

Cover image for How I Built an Automated Linux Hardening Script as a Complete Beginner
Tharuka Dilshara
Tharuka Dilshara

Posted on

How I Built an Automated Linux Hardening Script as a Complete Beginner

Why I Built This

The first time I deployed a Linux server I made the same mistake thousands of developers make.

I thought security was something for advanced users. Something complicated. Something I would handle later.

Within hours of my server going live I checked the logs and saw thousands of failed login attempts. Bots were scanning my ports. Automated scripts were trying common username and password combinations over and over again.

My server was a brand new house with every door and window wide open.
That experience changed how I think about servers forever. Security is not optional. It is foundational. And it needs to happen on day one — not day thirty.

So I built an automated hardening script. One script that takes a completely unsecured Linux server and locks it down automatically.
This is the complete story of how I built it, what I learned, and how you can build it too.

creenshot of failed login attempts in server logs

What is a Hardening Script?

A hardening script is a bash file — basically a list of commands — that runs automatically and secures your server without you having to type each command manually.

Instead of doing this every time you set up a new server:

Step 1 — open SSH config
Step 2 — disable root login
Step 3 — disable password auth
Step 4 — install firewall
Step 5 — configure firewall rules
Step 6 — install fail2ban
Step 7 — configure fail2ban
Step 8 — enable auto updates
... and 10 more steps

You just run one command:

sudo bash hardening.sh
Enter fullscreen mode Exit fullscreen mode

And everything happens automatically in under 60 seconds.

The Four Security Problems This Solves

Simple diagram showing 4 security layers

  • Problem 1 — SSH is Wide Open

SSH is how you connect to your server remotely. By default any person on the internet can try to log in using any username and any password as many times as they want.

Attackers use automated bots that try thousands of common username and password combinations every hour.

The fix: Disable password login completely. Force key-based authentication only. Disable root login. Limit login attempts to 3.

  • Problem 2 — No Firewall

A fresh Linux server has thousands of open ports. Each open port is a potential door for attackers.

The fix: Install UFW firewall. Block everything by default. Only open the 3 ports you actually need — SSH, HTTP, and HTTPS.

  • Problem 3 — No Attack Detection

Without monitoring nobody tells you when someone is actively trying to break into your server.

The fix: Install fail2ban. It watches your logs 24/7 and automatically bans any IP address that fails to login too many times.

  • Problem 4 — Unpatched Software

New security vulnerabilities are discovered every day. If your server software is not updated regularly it becomes vulnerable to known attacks.

The fix: Enable unattended-upgrades. Your server automatically downloads and installs security patches every night.

What I Built — The Complete Script

 Screenshot of your hardening.sh file open in VS Code

The Foundation

Every good script starts with a solid foundation. Mine has three parts:

Colored output so you can instantly see what is working and what is not. Green means success. Red means error. Yellow means warning.

Root check that stops the script immediately if you forgot to run it with admin privileges.

Dry run mode that lets you test the script safely without making any real changes. Just add --dry-run when running and it prints what it would do instead of actually doing it.

Section 1 — SSH Hardening

> Internet → [Blocked ports ❌] → Server
           [Allowed ports ✅ (22, 80, 443)]

> 
Enter fullscreen mode Exit fullscreen mode

SSH is the front door of your server. This section locks it down properly.

The script makes three critical changes to the SSH configuration file:

Disables root login — Attackers cannot target the most powerful user directly anymore. They would need to know your specific username first.

Disables password authentication — No more password guessing attacks. The only way to connect is with an SSH key pair — a much stronger form of authentication.

Limits login attempts — Maximum 3 tries before the connection is cut. Combined with fail2ban this makes brute force attacks practically impossible.

After making these changes the script automatically restarts SSH to apply them.

Important warning: Always test SSH access in a new terminal window before closing your current session. If something goes wrong you want to be able to fix it while still connected.

Section 2 — UFW Firewall

UFW stands for Uncomplicated Firewall. It is the most beginner friendly way to manage firewall rules on Ubuntu and Debian.

The script configures it with three simple rules:

Block all incoming traffic by default — Every connection attempt is rejected unless it matches a specific rule you create.

Allow outgoing traffic — Your server can still connect to the internet to download updates and send responses.

Open only 3 specific ports — SSH on port 22, HTTP on port 80, and HTTPS on port 443. Everything else stays closed.

One critical thing to always remember — allow SSH before enabling the firewall. If you enable UFW first and forget to allow SSH you will lock yourself out completely.

Important note for Docker users: UFW and Docker do not work together the way most people assume. Docker creates its own firewall rules that UFW does not control. Always test your container ports manually after setting up UFW.

Section 3 — fail2ban

ail2ban is one of the simplest and most effective security tools available for Linux servers.

It works by watching your log files. Every time an IP address fails to authenticate too many times — fail2ban automatically adds a rule to block that IP address for a set period of time.

The script configures three key settings:

bantime = 3600 — Banned IPs are blocked for 1 hour
findtime = 600 — Counts failures within a 10 minute window

maxretry = 5 — Bans after 5 failed attempts
On a publicly accessible server you will typically see multiple banned IP addresses within just a few hours of going live. fail2ban handles all of this silently in the background without you doing anything.

Section 4 — Automatic Updates

The most boring security measure is also one of the most effective.

Keeping your software updated patches known vulnerabilities before attackers can exploit them. The gap between a vulnerability being discovered and a patch being released is short. The gap between the patch being released and you actually installing it is where most server breaches happen.

unattended-upgrades solves this by automatically downloading and installing security patches every night.

One important limitation: unattended-upgrades only covers your operating system packages. It does not update Docker images. If you run containers you need to handle those separately using a tool like Watchtower.

The Professional Features

What makes this more than just a collection of commands are the professional features built into the script.

Idempotency means the script can be run multiple times safely. Before making any change it checks whether that change has already been made. If SSH root login is already disabled it skips that step instead of trying to disable it again. This prevents the script from breaking things if you run it twice.

Dry run mode lets you see exactly what the script would do before it does anything. Run it with --dry-run and it prints every action without executing any of them. This is essential for safely testing on production servers.

Colored output makes the results easy to read at a glance. You do not have to read through walls of text to see if something failed.

How to Run It

# Test first — always
sudo bash hardening.sh --dry-run

# When you are happy with what it shows
sudo bash hardening.sh
Enter fullscreen mode Exit fullscreen mode

After running verify everything worked:

# Check firewall is on
sudo ufw status verbose

# Check fail2ban is running
sudo fail2ban-client status sshd

# Check what ports are open
ss -tlpn
Enter fullscreen mode Exit fullscreen mode

What Runs Automatically After Setup

Once you run the script once you do not need to run it again. Here is what keeps working automatically:

fiturse

What I Learned Building This

  1. Security is contextual.
    There is no universal checklist. What works for one server may not work for another. Understand your specific setup before applying anyone else's commands.

  2. Test before you apply.
    The dry run flag saved me multiple times. Always know what your script will do before it does it.

  3. Order matters.
    Allow SSH before enabling UFW. Back up config files before editing them. Test in a new terminal before closing your current session. Small things in the wrong order cause big problems.

  4. Simple tools work.
    fail2ban is not sophisticated. UFW is called Uncomplicated Firewall for a reason. You do not need complex enterprise tools to secure a personal server. Simple tools applied correctly are very effective.

  5. Security is never finished.
    This script is a strong starting point. But security is an ongoing practice — not a one time setup. Check your logs regularly. Keep learning.

Resources

Learning bash scripting:

  • Linux Command Line book by William Shotts — free online at linuxcommand.org
  • Bash scripting tutorial at ryanstutorials.net

Learning about server security:

  • DigitalOcean community tutorials — digitalocean.com/community
  • Linux security documentation — linux.die.net

Tools used in this project:

  • Ubuntu 22.04 LTS
  • UFW — built into Ubuntu
  • fail2ban — apt install fail2ban
  • unattended-upgrades — apt install unattended-upgrades
  • VS Code with Remote SSH extension

Free servers to practice on:

  • Oracle Cloud free tier — cloud.oracle.com
  • GitHub Student Pack — education.github.com
  • Google Cloud free trial — cloud.google.com

Get the Code

The complete script is available on GitHub:
🔗 https://github.com/dilsharatharuka52-web/Automated-Linux-Hardening-Script.git

The repository includes:

  • Complete hardening script with all sections
  • README with setup instructions
  • Checklist of everything the script does
  • Example output screenshots

Final Thoughts

Building this project taught me more about Linux security in one week than months of reading about it.

The best way to learn security is to actually secure something.

Start with a free server from Oracle Cloud. Run the script. Read the output. Check what changed. Break things and fix them.

Security feels overwhelming until you start doing it. Then it becomes one of the most satisfying parts of working with servers.

If you have questions about any part of this project leave a comment below. I am happy to help.

profile

Top comments (0)