When creating a new VPS you need to make sure that you secure your server from the scary internet. The only one that should be able to administrate the server should be you and only you!
There are few (simple) steps involved in how you can secure your server and have a good sleep at night, without fearing someone might hack your server.
You should have an existing or freshly installed server running Ubuntu 20.08 VPS available and able to log in.
Disclaimer: links containing a * at the end are affiliate links, which means if you signup using that link I would get a small commission and it helps me out!
When you create a new VPS you usually get access to the
root user with a password. For security reasons, we create a new user that will be used to administrate the server. It is good practice to only work with the least amount of privileges you need and use
sudo when you need more permissions.
We will disable the possibility to log in as the
root user using a password, but we will allow it to log in using public-key authentication.
To add a new user you can use the
You will be asked a few questions including what password you want to use. Make sure the password is secure and in the best case random generated and stored in a password manager like 1Password or Lastpass.
Adding user `phiilu' ... Adding new group `phiilu' (1000) ... Adding new user `phiilu' (1000) with group `phiilu' ... Creating home directory `/home/phiilu' ... Copying files from `/etc/skel' ... New password: Retype new password: passwd: password updated successfully Changing the user information for phiilu Enter the new value, or press ENTER for the default Full Name : Florian Room Number : Work Phone : Home Phone : Other : Is the information correct? [Y/n]
Now we have a new user that we can use to log in. If you are the
root user you can just type
and you will be logged in as the user without prompted a password. You can also use log in with the
Next, we want to give the user permission to administrate the server. Right now we have a new user, but the user does not have any permission to make any changes as a superuser.
You can confirm this when trying to update the packages:
sudo apt install
[sudo] password for phiilu: phiilu is not in the sudoers file. This incident will be reported.
As you can see, we need to add the new user to the sudoers file to be able to execute commands as the superuser.
We need to exit our current session with
exit. You should now be logged in as the
If you are
root, you can type
visudo to check the current sudoers file.
# # This file MUST be edited with the 'visudo' command as root. # # Please consider adding local content in /etc/sudoers.d/ instead of # directly modifying this file. # # See the man page for details on how to write a sudoers file. # Defaults env_reset Defaults mail_badpass Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" # Host alias specification # User alias specification # Cmnd alias specification # User privilege specification root ALL=(ALL:ALL) ALL # Members of the admin group may gain root privileges %admin ALL=(ALL) ALL # Allow members of group sudo to execute any command %sudo ALL=(ALL:ALL) ALL # See sudoers(5) for more information on "#include" directives: #includedir /etc/sudoers.d
You can see that if a user is in the
sudo group, he should be able to execute commands as
root. There is also the
admin group in my
sudoers file which will allow the user in that group to execute some commands as
root. We want to be able to do the same things the root user can do so we will choose the
To add a user to a group you can use the
usermod command using the options
-a for add and
-G for alternative groups followed by the group's name and the user you want to modify.
usermod -a -G sudo phiilu
id you can check the groups (and ids) of a user and can confirm that the user is now part of the
id phiilu uid=1000(phiilu) gid=1000(phiilu) groups=1000(phiilu),27(sudo)
Now that our user is in the
sudo group, you can log in as that user and try to update the packages again and this time it should work!
Now that we have a new user that can execute commands as
root, we can go forward and harden our server even more by changing some settings for
Before doing that we want to set up public-key authentication for both our users
root and the one we created before.
This is a recap of the "Skip passwords with public key authentication" section of my Use Visual Studio Code Remote to edit files on servers post.
Public key authentication is a secure way to connect to a server with SSH using a set of key pairs. The public key is saved on the server and the private key should be kept on your local machine. This is the key to unlock the server and must never be leaked or shared with someone else.
If you are using Windows you must have Git for Windows installed and use the following commands inside the Git Bash.
The following commands should be the same for Windows and macOS except you might have to end the commands on Windows with
If you already have an SSH key that you might already use with
git you can skip this step.
ssh-keygen -b 4096
Which results in the following output.
Generating public/private rsa key pair. Enter file in which to save the key (/c/Users/flori/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /c/Users/flori/.ssh/id_rsa. Your public key has been saved in /c/Users/flori/.ssh/id_rsa.pub. The key fingerprint is: SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx flori@Windows
You can set a passphrase for the key if you want, but then you have to enter a password for the log in which we want to avoid.
You can either manually paste the key to the server or you can use a program called
ssh-copy-id which I prefer.
On macOS you have to install
brew on Windows it should be already present in the Git Bash.
brew install ssh-copy-id
To copy the key to the server you just have to log in to the server using the
ssh-copy-id utility. Do this step twice for both users.
replace VPS_IP with the real IP of your VPS
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/florian/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@VPS_IP's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'root@VPS_IP'" and check to make sure that only the key(s) you wanted were added.
Now if you try to log in with
ssh you should not be asked for a password.
If you are still asked for a password check if the permissions on the
authorized_keys file on the server are correct:
ls -la ~/.ssh
drwx------ 2 root root 4096 Sep 18 17:23 . drwx------ 7 root root 4096 Sep 21 14:48 .. -rw------- 1 root root 416 Sep 18 17:23 authorized_keys
If your permissions are different you might have to change them:
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys
To change the configuration for
ssh open the
/etc/ssh/sshd_config file with your favorite text editor or you can check out my blog post Use Visual Studio Code Remote to edit files on servers to use a GUI editor to modify your server files.
First of all, I want to change that the
root user is not able to log in with a password, but should be able to use public-key authentication to sign in.
Find the line that says
PermitRootLogin yes and change it to
If you want to only allow public-key authentication find the following configuration keys and change them:
PubkeyAuthentication yes PasswordAuthentication no
Last but not least only allow users that you explicitly defined to log in to your server. Go to the end of the file and add the following line:
AllowUsers phiilu root dokku
Here you should add the usernames separated with space. In my case, I am allowing the users
dokku to log in into my server using ssh.
After changing the configuration you must restart the
sudo service sshd restart
The Internet is a scary place and you need to be aware that everyone out there wants to take over your server. It is very important to make sure bad people or in this case, bad IP addresses get sent to jail and never will bother our server again.
This is why we will install
fail2ban. Fail2ban is a small service that will run on your server and will read your log files and makes sure to ban IP addresses that are trying to log in to your server.
In this post, I will only show you how you configure
fail2ban to only check the logs of the
ssh service, but
fail2ban can also be used to check other log files like
Installation is very easy and only one command away.
sudo apt install fail2ban
That is it, we don't need to make any additional configuration, fail2ban is now working and will make sure it bans bad log in attempts.
If you want to make changes to the config file, you must copy the original
/etc/fail2ban/jail.conf file and create a
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Now you could make changes in
jail.local and adjust ban time or retries, but I think the default is already pretty good.
Sometimes you may want to unban an IP address because you somehow locked yourself out, but you still got access using the VPS providers web console.
fail2ban lets us easily unban IP addresses using the included client:
sudo fail2ban-client set sshd unbanip IP
Here you can see an example of how I unbanned an IP.
root@dokku:~# fail2ban-client status sshd Status for the jail: sshd |- Filter | |- Currently failed: 0 | |- Total failed: 1114 | `- File list: /var/log/auth.log `- Actions |- Currently banned: 2 |- Total banned: 241 `- Banned IP list: 184.108.40.206 220.127.116.11 root@dokku:~# fail2ban-client set sshd unbanip 18.104.22.168 1 root@dokku:~# fail2ban-client status sshd Status for the jail: sshd |- Filter | |- Currently failed: 0 | |- Total failed: 1114 | `- File list: /var/log/auth.log `- Actions |- Currently banned: 1 |- Total banned: 241 `- Banned IP list: 22.214.171.124
Fail2ban comes with an easy to use client, where you can check the status of a specific service and see how many IPs are already banned
fail2ban-client status sshd
This is my server after being online for about a week. You can see and confirm that the Internet is a scary place and everyone wants to take over your server!
Status for the jail: sshd |- Filter | |- Currently failed: 0 | |- Total failed: 663 | `- File list: /var/log/auth.log `- Actions |- Currently banned: 1 |- Total banned: 129 `- Banned IP list: 126.96.36.199
What is a Firewall? you may ask. A firewall defines rules in which services can connect to our server (incoming) or are allowed to talk to others on the Internet (outgoing). A server without a firewall will be allowed to do everything and has no restriction and can talk to everyone, but as we already learned we don't want that because we can't trust anyone on the Internet.
A lot of VPS providers are allowing you to configure a firewall within their dashboard, but for those of you that are not able to do that, you can still use a software firewall like
ufw. UFW is a software firewall and we can secure our server with just four commands!
ufw default deny incoming ufw default allow outgoing ufw allow ssh ufw enable
Now your server is only allowed to respond to requests that are talking on port 22 (ssh) and every other service is disabled.
ufw allow ssh is just an easy way to write
ufw allow 22/tcp. Some services are known to run on a specific port so
ufw already knows a lot of them!
If you have a webserver running too, you probably want to enable
https. So just type
ufw allow http and
ufw allow https and your server is now allowed to respond to
For additional services you may run on your server you will eventually open more ports.
Hosting your server can be a bit scary, but if you followed the post closely you should be fine. Of coures, you should still log in into the server from time to tome and run updates with
sudo apt update && sudo apt upgrade to make sure you get the latest security patches.
Let me know in the comments if this was useful and if I might have missed something that every server should configure to be more secure!