Secure a fresh VPS: initial server setup on Ubuntu in 10 minutes

A fresh server is exposed with password root login and gets brute-forced immediately. Close the basic holes in ten minutes: a sudo user, key login, sshd, ufw, auto-updates.

A fresh HIP server with Ubuntu 24.04 comes up with a public IP and password-based root login. Automated scanners start hitting it within minutes of the IP going live - on our test box the failed-login counter passed 17,000 in a few hours. This initial server setup closes the basic holes in about ten minutes: a non-root user, key-only login, no password auth, a firewall, and automatic security updates. The commands below were run on a clean Ubuntu 24.04 box.

TL;DR. Log in as root, create a sudo user, add your SSH key to it. In a second terminal confirm key login works. Disable root login and password auth in sshd, enable ufw (allow SSH first) and unattended-upgrades. After that sshd no longer accepts password authentication, so brute-forcing the password over SSH stops making sense.

What you end up with

  • A user deploy with sudo - you work as this user, not root.
  • SSH key authentication instead of a password.
  • Root login and password login disabled in sshd.
  • ufw firewall: only port 22 open inbound.
  • Security updates installed automatically.

Step 0. Log in as root

The IP address and root password are on the server page in the panel, under How to connect. The same page has the web console button - you will need it if you ever lock yourself out of SSH. If you do not have a server yet, create one first - see "How to create a server in the HIP panel".

Connect from your machine (Windows - PuTTY or the built-in ssh; macOS and Linux - ssh in a terminal):

ssh root@YOUR-IP

Step 1. A non-root user with sudo

Running as root full-time is risky: every mistake runs with full privileges, and root over SSH is the number-one brute-force target. Create a regular user and grant it sudo.

adduser deploy
usermod -aG sudo deploy
id deploy

id deploy should show the sudo group:

uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),27(sudo)

adduser creates the user and home directory and asks for a password - you need one, sudo will prompt for it. On Ubuntu, membership in the sudo group is what grants sudo.

Step 2. Put your SSH key on the user

A key is a pair of files on your machine: the private half stays with you, the public half goes on the server. Whoever presents the private key gets in - no password, and a key cannot be brute-forced. If you have no key yet, run ssh-keygen -t ed25519 on your machine; the .pub file is what you copy.

install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys      # paste one line from your .pub
chmod 600 /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy/.ssh/authorized_keys

Recommended modes are 700 for .ssh and 600 for authorized_keys. What actually matters is that the directory, the file and the home directory are not writable by other users: with an unsafe owner or permissions, sshd under StrictModes can refuse the key - and the reason is in the sshd/journal logs.

Step 3. Verify key login - in a second terminal

Do not skip this. Before you disable anything in sshd, open another terminal and confirm the new user logs in with the key and that sudo works. Keep the first session open as a safety net.

ssh deploy@YOUR-IP
deploy@server:~$ sudo whoami
root

Step 4. Lock SSH down to key-only

sshd is the SSH service on the server. Don't edit the main config - drop a file into /etc/ssh/sshd_config.d/ so your changes survive package upgrades.

nano /etc/ssh/sshd_config.d/99-hardening.conf
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
X11Forwarding no
MaxAuthTries 3

Check the syntax and apply without dropping open sessions:

sshd -t && echo OK
systemctl reload ssh

PermitRootLogin no - no root over SSH. PasswordAuthentication no - key only. sshd -t is mandatory before reloading: a broken config keeps sshd from starting and you are locked out.

Ubuntu cloud-image gotcha. Run sshd -T | grep -i passwordauthentication afterwards and you will probably still see yes. On Ubuntu cloud images, 50-cloud-init.conf in the same directory already sets PasswordAuthentication yes, and sshd takes the first value it finds for such keys. Your 99-* file is read later and ignored. Fix: name it so it is read first:
grep -R -n -i passwordauthentication /etc/ssh/sshd_config.d/
mv /etc/ssh/sshd_config.d/99-hardening.conf /etc/ssh/sshd_config.d/00-hardening.conf
sshd -t && systemctl reload ssh

sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|kbdinteractiveauthentication|maxauthtries'

The output should now show permitrootlogin no, passwordauthentication no, kbdinteractiveauthentication no and maxauthtries 3.

The config is applied - but keep the current root session open. Open a NEW SSH session as deploy, confirm it logs in with the applied config, and run sudo -v. Only when that works, close the old root session.

ssh deploy@YOUR-IP
sudo -v

Step 5. Firewall: SSH only

ufw is a thin wrapper over the Linux firewall. Add the SSH rule first: enable ufw with a deny-inbound policy and no rule for port 22, and your session drops with no way back in.

ufw allow OpenSSH
ufw --force enable
ufw status verbose

ufw app info OpenSSH

The OpenSSH profile is 22/tcp. If you have moved SSH to another port, allow that port explicitly (ufw allow 2222/tcp) instead of the profile.

Add web-server profiles (Nginx Full, etc.) later, once the web server is installed.

Step 6. Automatic security updates

Unpatched known vulnerabilities are one of the main risks for a public server. unattended-upgrades installs security updates once a day on its own.

On Ubuntu 24.04 unattended-upgrades is usually already installed and enabled - check before changing anything:

systemctl status unattended-upgrades.service
apt-config dump | grep -Ei 'Periodic::(Update-Package-Lists|Unattended-Upgrade)'

Two "1" lines and an active service mean it is on. If it is off:

apt-get install -y unattended-upgrades
dpkg-reconfigure -f noninteractive unattended-upgrades
cat /etc/apt/apt.conf.d/20auto-upgrades

Two "1" lines in 20auto-upgrades mean the package-list refresh and the upgrade step are both on. The server does not reboot after a kernel update by default; enable Unattended-Upgrade::Automatic-Reboot if you want that.

Step 7. Final check

Root over SSH must be rejected; the new user with the key must work:

ssh root@YOUR-IP
root@YOUR-IP: Permission denied (publickey).
ssh deploy@YOUR-IP
deploy@server:~$

Next

  • fail2ban - bans IPs after repeated failures; mostly log-noise reduction once passwords are off.
  • Snapshot the server from the panel now - a clean baseline to roll back to.
  • Reverse DNS (PTR) if the server will send mail.

If you lock yourself out

SSH is not the only way in. The server page in the panel has a web console (serial console) that bypasses sshd and the firewall - use it to log in as root with the password and fix the config. Keep the panel root password even after disabling SSH password auth.

FAQ

Where do I start when setting up a new Ubuntu server?

Three things: a separate sudo user, SSH key login, and disabling password and root login in sshd. Then the ufw firewall and automatic updates. That is the baseline initial server setup; everything else depends on the workload.

Do I have to disable root login?

A remote SSH login straight into a privileged account is not needed for day-to-day work. A separate user plus sudo keeps privilege escalation a distinct step and limits what runs directly as UID 0.

Why does PasswordAuthentication no not take effect on Ubuntu?

/etc/ssh/sshd_config.d/50-cloud-init.conf sets PasswordAuthentication yes and is read before your file, and sshd takes the first match. Name your file 00-hardening.conf or edit 50-cloud-init.conf.

I lost my private key.

Log in as root via the panel's web console, add a new public key to authorized_keys, temporarily set PasswordAuthentication yes if needed.

Do I need ufw if only SSH faces the internet?

Yes. Services tend to appear - install a database and it may listen on 0.0.0.0. With ufw that port stays closed until you add an explicit rule.

In short

  • Don't work as root - use a sudo user.
  • Key instead of password; disable password and root login in sshd.
  • On an Ubuntu cloud image, name your config 00-hardening.conf or 50-cloud-init.conf overrides it.
  • SSH rule in ufw before enabling the firewall.
  • unattended-upgrades so known holes close without you.
  • The panel web console is your backup way in.
SECTION
How To
REVIEWED
LANGUAGES
EN · RU