General

Initial Server Setup and Hardening on Ubuntu

May 17, 2026
10 min read

A first-hour checklist for a fresh Ubuntu VPS: non-root sudo user, SSH key auth, UFW firewall, fail2ban, and automatic security updates, with why each step matters.

Initial Server Setup and Hardening on Ubuntu | Carpathian

The first hour on a fresh Ubuntu server is the cheapest security you will ever buy. Effective ubuntu server hardening is a short, ordered checklist: create a non-root user with sudo, switch SSH to key-based login and turn off passwords and direct root login, enable the UFW firewall, install fail2ban, and turn on automatic security updates. Do those five things before you install anything else, and you have closed the doors that most automated attacks walk through.

None of this requires you to be a sysadmin. Each step is a few commands, and each one shuts a specific door: brute-force password guessing, root takeover, open ports you forgot about, and stale software with known holes. This guide walks through the steps in order, explains in one line why each matters, and is honest about the limit: hardening lowers your risk, it does not make a server invulnerable.

If you are still picking a server, start with how to choose a VPS. When you are ready to put something on it, deploying a web app with Nginx and Docker is the logical next read, and if you are weighing host types at all, see which hosting type is best for small websites.

Why does a fresh Ubuntu server need hardening at all?

A new public server is found and probed within minutes of coming online. Automated bots scan the whole internet constantly, hammering port 22 with common usernames and passwords and looking for known software flaws. A default install with password login and the root account exposed is the single most attacked configuration there is. Hardening removes the easy targets so the bots move on.

The work breaks into two ideas. First, reduce what is exposed: fewer open ports, no password login, no direct root access. Second, slow down and update: rate-limit attackers, ban repeat offenders, and patch known holes before they are used. Everything below serves one of those two goals.

A quick note before you start. You will need the server's IP address, a way to log in (your host gives you a root password or an initial user), and a terminal on your own machine. On Windows that is PowerShell or Windows Terminal, on macOS or Linux it is your built-in terminal. Run the commands in the order shown, and keep your current session open until you have confirmed the new login works.

How do you create a non-root user with sudo?

Log in, create a normal user, and grant it sudo so you can run admin commands without living as root. Working as root all the time means a single mistake or a single compromised process runs with total control of the machine. A regular user with sudo gives you that power only when you ask for it, which is the safer default.

Connect to the server as root (your host provides the initial credentials):

ssh root@your_server_ip

Create a new user, replacing deploy with whatever name you want, and set a password when prompted:

adduser deploy

Add the user to the sudo group so it can run privileged commands:

usermod -aG sudo deploy

Why it matters: day-to-day work as a limited user contains the blast radius of any mistake or breach to that account, not the whole system.

You can confirm it worked by switching to the new user and running a harmless privileged command:

su - deploy
sudo whoami

If that prints root after you enter the user's password, sudo is configured. Stay in this session for the next step.

How do you set up SSH key authentication?

SSH keys replace a guessable password with a cryptographic key pair: a private key that stays on your computer and a public key you place on the server. Passwords can be brute-forced; a properly generated key cannot be, in any practical timeframe. This is the single highest-value step in the checklist.

On your own machine (not the server), generate a key pair if you do not already have one:

ssh-keygen -t ed25519 -C "your_email@example.com"

Press Enter to accept the default location, and set a passphrase when asked. The passphrase encrypts the private key on disk, so a stolen laptop does not hand someone your key.

Copy the public key to the server's new user. The simplest way is ssh-copy-id from your machine:

ssh-copy-id deploy@your_server_ip

If ssh-copy-id is not available, you can paste the key manually. On the server, as the deploy user:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys

Paste the contents of your local ~/.ssh/id_ed25519.pub into that file, save, then fix permissions:

chmod 600 ~/.ssh/authorized_keys

Why it matters: a key removes password guessing as an attack path entirely, which is where most automated SSH attacks live.

Now test it. From a new terminal on your machine, log in as the user:

ssh deploy@your_server_ip

If you get in without typing the account password (the key passphrase is fine), key auth works. Do not move to the next step until this succeeds, because the next step turns passwords off.

How do you disable password login and root SSH access?

Once key login works, turn off password authentication and direct root login in the SSH server config. This is what locks the door behind you: with passwords disabled, the constant brute-force traffic against your server simply cannot succeed, and with root login off, an attacker has to guess both a username and a key.

Edit the SSH daemon configuration as root or with sudo:

sudo nano /etc/ssh/sshd_config

Find and set these three directives. They may already exist (uncomment them) or you may need to add them:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

These keywords are the standard options documented in the Ubuntu sshd_config manual. On recent Ubuntu releases, some settings live in drop-in files under /etc/ssh/sshd_config.d/, and a file there can override the main config, so check that directory if a change does not take effect.

Apply the change by restarting the SSH service:

sudo systemctl restart ssh

Why it matters: turning off passwords neutralizes the most common attack against any internet-facing Linux box, and disabling root SSH removes the one username every bot already knows.

Test before you trust it. Keep your working session open, open a fresh terminal, and confirm you can still log in as deploy with your key. Then confirm root and password login are refused:

ssh root@your_server_ip

That attempt should be rejected. If your good session breaks for any reason, you still have the open one to fix the config.

How do you configure the UFW firewall?

UFW (Uncomplicated Firewall) is Ubuntu's front end for the kernel's firewall, and its job is to close every port you are not deliberately using. A default server may have services listening that you never meant to expose. A firewall that denies everything inbound except SSH and your application ports shrinks your attack surface to a handful of doors you watch.

Set the baseline policy first: deny all incoming, allow all outgoing.

sudo ufw default deny incoming
sudo ufw default allow outgoing

Allow SSH before you enable the firewall, or you will lock yourself out:

sudo ufw allow OpenSSH

If you are running a web server, open the web ports too:

sudo ufw allow http
sudo ufw allow https

Turn the firewall on and confirm the rules:

sudo ufw enable
sudo ufw status verbose

The status output should list your allowed services and show the default incoming policy as deny. These commands follow the Ubuntu firewall documentation.

Why it matters: an inbound-deny default means a service you forgot about, or one a future package quietly installs, is not reachable from the internet by accident.

One optional extra: UFW can rate-limit SSH, dropping connections from an IP that retries too quickly. The Ubuntu docs note this throttles repeated connection attempts.

sudo ufw limit OpenSSH

How do you install and configure fail2ban?

fail2ban watches your log files for repeated failed logins and temporarily bans the offending IP address at the firewall. Even with passwords disabled, attackers still flood SSH with attempts, which clutters logs and wastes resources. fail2ban turns that noise down by banning the noisiest sources automatically.

Install it:

sudo apt update
sudo apt install fail2ban

Never edit the stock config directly, because package updates overwrite it. Instead create a local override file:

sudo nano /etc/fail2ban/jail.local

A sensible SSH jail looks like this. It bans an IP for one hour after five failed attempts within ten minutes:

[sshd]
enabled = true
port = ssh
maxretry = 5
findtime = 10m
bantime = 1h

The convention of overriding stock files with jail.local rather than editing the defaults is the documented best practice (fail2ban project). Adjust the numbers to taste: a lower maxretry and a longer bantime are more aggressive, at a small risk of locking out a legitimate user who fat-fingers a login.

Enable and start the service, then check it:

sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Why it matters: fail2ban caps how many guesses any single source gets, which thins out brute-force traffic and keeps your logs readable.

How do you enable automatic security updates?

Unattended-upgrades installs Ubuntu security patches on its own, so known flaws get fixed without you remembering to log in. Unpatched software is one of the most common ways servers get compromised, and a small personal server is the kind that quietly goes months without a manual update. Automating security patches removes that gap.

The package ships on Ubuntu Server, but install it if it is missing:

sudo apt install unattended-upgrades

Enable it interactively and choose Yes at the prompt:

sudo dpkg-reconfigure -plow unattended-upgrades

That writes /etc/apt/apt.conf.d/20auto-upgrades. You can confirm the contents:

cat /etc/apt/apt.conf.d/20auto-upgrades

It should contain two lines, both set to 1, which run the daily update and upgrade jobs:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

This is the configuration described in the Ubuntu automatic updates documentation. To preview what it would install without changing anything, run a dry run:

sudo unattended-upgrade -v --dry-run

Why it matters: security holes are exploited fastest right after they are disclosed, and an automatic patch closes that window while you are not looking.

By default, automatic security updates do not reboot the machine, even when a patch needs one (a kernel update, for example). If you want the server to reboot itself on its own schedule, that behavior is set in /etc/apt/apt.conf.d/50unattended-upgrades. Leave it off if a restart at the wrong moment would disrupt you, and plan your own reboots instead.

Final checks and basic hygiene

A few last touches make the server easier to operate and a little more correct. Set the hostname so you can tell machines apart, set the timezone so your logs make sense, and run one full update so you start from current packages.

Set a clear hostname:

sudo hostnamectl set-hostname web-01

Set the timezone (list options with timedatectl list-timezones):

sudo timedatectl set-timezone America/Chicago

Bring everything current, then reboot if a kernel update was installed:

sudo apt update && sudo apt upgrade

A couple of quick verifications confirm the work held:

  • sudo ufw status verbose shows deny-incoming as the default and only your intended services allowed.
  • sudo fail2ban-client status sshd shows the SSH jail active.
  • ssh root@your_server_ip is refused, and password login is refused, while your key login works.
  • sudo unattended-upgrade -v --dry-run runs without error.

If all four hold, the doors are shut.

The honest limit

Hardening lowers your risk, it does not make a server invulnerable. This checklist closes the common, automated attack paths, the ones that account for the overwhelming majority of break-ins on small servers. It does nothing against a flaw in the application you deploy, a leaked key, a weak database password, or a supply-chain problem in a package you install. Security is not a one-time setup, it is a habit.

So keep going after the first hour. Apply updates (the automation handles security patches, but check in on the rest), keep your private keys private and passphrase-protected, take backups and store them somewhere off the server, and add only the open ports and services you genuinely need. The best-run servers are the boring ones: locked down to a small, well-understood surface, quietly patched, and stripped of anything you are not using. Set them up that way once, then mostly leave them alone.

About the Author

Samuel Malkasian | Founder

Samuel Malkasian | Founder

Samuel Malkasian is the founder and lead cloud architect at Carpathian, where he designed the platform's core architecture along with a range of client enterprise systems and open-source tools for AI workflows and integration. He serves as a Cyber Warfare Officer in the U.S. Army and has a background in machine learning and data science. He is currently focused on building AI infrastructure that is secure, efficient, and low-power by design.

Related Topics

ubuntuserver hardeningvps securitysshufwfail2banunattended-upgradeslinux