First configuration steps on a new VPS Server

Published: June 10, 2018  •  linux, selfhosted

I like to self-host my web applications and other applications like blog software and Git servers. This gives you a bit of independence from third party services and the freedom to install any software with any configuration.
Managing your own server has the drawback that it needs more effort than using a third party service. There is the initial setup that takes time and after that you have to periodically manage and update the server.

But even with all these drawbacks, managing your own server is interesting and you can learn a lot and improve your skills.

You don't need a server farm in your apartment to run your own Internet connected servers, although you could. Instead, you visit the homepage of a VPS provider and rent your VPS server there. There are a lot of VPS hosting providers on the Internet, to name a few: OVH, Linode, DigitalOcean, Scaleway, Vultr.

A VPS is a virtual machine, runs its own copy of an operating system and you have root access to. Most VPS run with a Linux operating system, but you also find servers running with Windows.

Renting a VPS server is not that expensive. The cheapest VPS offers I saw cost between 2 and 5 US Dollars per month. Often you can rent them for just one month. A good way to figure out if self-hosting is something for you without wasting a lot of money.

In this blog post I will describe the initial configuration steps after I rent a new VPS. The provider often gives you a plain operating system with just the SSH server installed. The initial steps, I cover in this blog post, include the updating of the operating system, installing a firewall and hardening the SSH server.

For this blog post I will use a VPS from OVH. I'm not affiliated with OVH, it's just the provider that I have the most experience with and where I rented a few VPS. I'm satisfied with the service they provide and they offer VPS for a very cheap price. You find the price list here: https://www.ovh.com/world/vps/vps-ssd.xml

For the operating system I will choose Ubuntu 18.04. I like to use a Debian based Linux, either Debian directly or Ubuntu, because a lot of tutorials you find on the World Wide Web are written for this operating system.


Rent VPS

Visit the Homepage of the VPS hosting provider of your choice and select a VPS server. The offers differ in CPU, RAM and disk space. Often these VPS are not scalable and the RAM, disk space and number of CPUs is fixed. If you run out of resources, the only option then is to buy the next bigger VPS and relocate your software. Therefore, before you rent a VPS you should think about the software you want to install. If you only want to run a self-hosted Git server or a WordPress instance a VPS with 512MB RAM should be sufficient. If you are planning to run multiple services a VPS with more RAM or more disk space might be a better choice.

As mentioned before I will use a VPS from OVH and I choose the cheapest server (VPS SSD 1). With this VPS you get 2GB RAM, 20GB SSD, a bandwidth of 100 Mbps, unlimited traffic, one static IPv4 and one IPv6 address. OVH also supports an upgrade to the bigger VPS SSD2 und VPS SSD3 without reinstalling the operating system.

During the ordering process I can choose the location of the datacentre where my VPS should run in, the operating system and additional offerings like more disk space and snapshots. I can select if I want to rent the VPS for just one month or for a longer period. These options differ from provider to provider. You also have to create an account with the provider and at the end of the ordering process you have to pay.

After the payment is processed the provider sets up the VPS and sends you an email with information about your new VPS. This process can take a few minutes. In my case it took about 10 minutes.


Connect with SSH

The email that OVH sends contains the IPv4 and IPv6 address of the VPS and the SSH username and password. Managing a Linux server is usually done over Secure Shell (SSH). SSH provides a secure (encrypted) channel from your computer to the server. When you work on Linux, macOS or Windows 10 with the latest April 2018 update you have a SSH client already installed (see this follow-up article about Putty if you work on an older Windows).

In a shell or command prompt issue the following command. Replace 51.38.124.133 with your IPv4 address.

ssh root@51.38.124.133

The first time you connect with SSH to a server, the client will present a prompt with the server's fingerprint. The fingerprint is a hash of the public key of the server.

The authenticity of host '51.38.124.133 (51.38.124.133)' can't be established.
ECDSA key fingerprint is SHA256:BXdQQAsjdS9P91cCwR5yRRelfyynpsfY+OxTkLSlr/A.
Are you sure you want to continue connecting (yes/no)? yes

Unfortunately we can't verify the fingerprint, the email from OVH does not contain this information, so we have to trust that this is our server and type yes. The fingerprint is a security measure to prevent man in the middle attacks and if you can find this information before you connect, you should definitely compare it.

Next enter the password and Ubuntu greets you with a welcome screen.

root@51.38.124.133's password:
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-20-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://www.ubuntu.com/support/plans-and-pricing

  System information as of Thu Jun  7 15:58:40 CEST 2018

  System load:  0.0               Processes:           82
  Usage of /:   5.9% of 19.21GB   Users logged in:     0
  Memory usage: 6%                IP address for ens3: 51.38.124.133
  Swap usage:   0%


  Get cloud support with Ubuntu Advantage Cloud Guest:
    https://www.ubuntu.com/support/plans-and-pricing

8 packages can be updated.
8 updates are security updates.

First thing we should do is change the root password. OVH sent us the password in an unsecure email. Issue the command passwd and it prompts for a new password. To verify that the new password works close the SSH connection with exit and try to reconnect.

If something went wrong and you can no longer login, open the web management console of your VPS provider. There you should find an option where you can either reboot the VPS into a special rescue mode or another way to reset the root password.
In the OVH manager you find the Reboot in rescue mode function. A click on this link reboots the VPS into a special mode where you can fix problems with your Linux installation. The reboot process takes about 3 minutes and OVH sends you an email with the IP address, SSH username and password when the rescue mode is ready.
Visit the website https://docs.ovh.com/gb/en/vps/root-password/ to find more information about how to reset the root password in this mode.

As a last resort, if everything fails, most VPS provider support a Reinstall function, which deletes everything and reinstalls the operating system.


Update Operating System

In the previous welcome screen you see that there are 8 installed packages that can be updated. On Debian and Ubuntu you install and update software packages with the apt command.

First you have to update the local apt database and then upgrade all outdated installed packages.

apt update
apt dist-upgrade

The local apt database contains information about all available apt packages. If you update or install a new package, apt will look in this database and installs the latest version that is listed in this database. When the database is outdated apt installs old packages, therefore it is important that you call apt update before you update or install packages. Ubuntu updates the apt database automatically once a day.

The dist-upgrade command lists the outdated packages and before it installs the updates asks if you want to continue. Type y and apt installs the updates.

When the update process installs a new kernel (packages starting with linux-*) you should reboot the server. Ubuntu will also tell you in the welcome screen if it needs a reboot.

To reboot the server you issue the command reboot. This command closes the SSH connection.

Keeping the installed packages up-to-date is in my opinion very important, especially for a server that is connected to the Internet. Every server will be attacked and if a crucial application like the SSH server has a weakness attackers will find it and exploit it. Fortunately Ubuntu provides a way to install important updates automatically.

Install the unattended-upgrades package and then open the configuration file.

apt install unattended-upgrades
nano /etc/apt/apt.conf.d/50unattended-upgrades

Configure the Allowed-Origins section. If you only want Ubuntu to install important security updates automatically, comment out everything but the "${distro_id}:${distro_codename}-security"; line

Unattended-Upgrade::Allowed-Origins {
//      "${distro_id}:${distro_codename}";
        "${distro_id}:${distro_codename}-security";
        // Extended Security Maintenance; doesn't necessarily exist for
        // every release and this system may not have it installed, but if
        // available, the policy for updates is such that unattended-upgrades
        // should also install from here by default.
        "${distro_id}ESM:${distro_codename}";
//      "${distro_id}:${distro_codename}-updates";
//      "${distro_id}:${distro_codename}-proposed";
//      "${distro_id}:${distro_codename}-backports";
};

If you want Ubuntu to automatically upgrade everything uncomment (remove //) all ${distro_id}:* lines. Save and close the file with ctrl+o and ctrl+x.

Next we need to enable unattended-upgrades. Run the command nano /etc/apt/apt.conf.d/20auto-upgrades to open the configuration file and add these lines.

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";

Visit the official documentation about unattended-upgrades for more information:
https://help.ubuntu.com/lts/serverguide/automatic-updates.html


IPv6

OVH gives you one free static IPv6 address, but it's not configured yet. If you are not sure if IPv6 is enabled or not issue this command

ping6 www.google.com

If the command prints out connect: Network is unreachable IPv6 is not enabled.

In Ubuntu 18.04 netplan is responsible for managing the network interfaces. To add IPv6 we have to open the configuration file.

nano /etc/netplan/50-cloud-init.yaml

On my VPS the file contains this code

network:
    version: 2
    ethernets:
        ens3:
            dhcp4: true
            match:
                macaddress: fa:16:3e:dd:b2:03
            set-name: ens3

ens3 is the name of the network interface. You see that only DHCP for IPv4 is enabled. OVH assigns static IPv4 addresses to the VPS over DHCP by maintaining a mapping in the DHCP server from MAC address to IP address, so even it is DHCP your server always gets the same IPv4 address.

To enable IPv6 support we have to add an address and gateway6 element. You find both IPv6 addresses in the OVH web console.

network:
    version: 2
    ethernets:
        ens3:
            addresses:
              - 2001:41d0:701:1100:0:0:0:e54/64
            gateway6: 2001:41d0:0701:1100:0000:0000:0000:0001
            dhcp4: true
            match:
                macaddress: fa:16:3e:dd:b2:03
            set-name: ens3

Save (ctrl+o) and close (ctrl+x) the text editor. Now try to load the configuration.

netplan try

With the try argument, netplan activates the network configuration and you have to press enter during the next 120 seconds if you want to keep the settings. If not netplan reverts to the old configuration. This prevents any misconfiguration that accidently disables IPv4 and kicks you out of the SSH session. Just wait 120 seconds and you should be able to login again.

To check if IPv6 is enabled, issue the command ping6 www.google.com. You can also see the configured addresses with ip -6 addr.


Harden SSH server

The SSH server is the main entry point to the server and we should make this entry as secure as possible. The current login with username and password is not the most secure authentication method. In this section we change the SSH configuration and make it more difficult for an attacker to gain access to our server.

Change default port

First thing I like to do is changing the default listening port (22) of SSH.

Open the SSH configuration file, uncomment the Port line and set it to a random port. For this example I set the port to 44933.

nano /etc/ssh/sshd_config

Port 44933

Make sure that you not accidently choose a port that is used by another service. The following command lists all currently running services that listen on a port.

ss -tulpn | grep LISTEN

Ports from 0 to 1023 are reserved and should not be used. Choose a port greater than 1023 and less than 65535.

This change does not make your server more secure. A targeted attack will easily find all open ports. But it helps against drive by scans. If you run your server for a few hours you will notice in the /var/log/auth.log file warnings about users that tried to access the server. These are automated scripts that scan the Internet for open ports and look for ways to break in.

By changing the default SSH port from 22 to something else we can prevent or at least significantly reduce these scans and attacks.

To activate the change restart the SSH server sudo systemctl restart ssh and check the status sudo systemctl status ssh. You should see a green Active: active (running) message. If there is a syntax error in the configuration file you will see a warning.

Close the SSH connection with exit and reconnect. Because we have changed the port, we need to specify the port with the -p option.

ssh -p 44933 root@51.38.124.133

Disable Protocol 1

SSH supports two protocols, 1 and 2. Version 1 is considered to be less secure and should no longer be used. Open the configuration file nano /etc/ssh/sshd_config and insert a new line Protocol 2. Ctrl+o and Ctrl+x saves the change and closes the text editor. Restart the SSH server with systemctl restart ssh


Disable root login

So far we logged in with the root user, which has super user permissions on the server. From a security stand point, it is better to create an unprivileged user for SSH access and then disable the root login.

Issue the command adduser manager to create a new Linux user. Instead of manager you can name the user anything you want.

Enter a new password for the user. The command asks for information like name and phone. It is okay to accept the defaults and leave all fields blank.

This user will be the only user that is allowed to login with SSH. But for managing a server we need a user that has root privileges. The easiest way is to add this user to the sudo group. Users in this group can execute commands with the sudo command and have then the same privileges a root user has.

usermod -aG sudo manager

Close the SSH connection and try to login with the new user ssh -p 44933 manager@51.38.124.133

Verify that the user can run commands with sudo. Run the command sudo ls -al /root, when successful lists the contents of the /root directory. The first time you use sudo in a session, Linux asks for the user's password.

When everything is okay we can disable root login in the SSH server and limit the login to the manager user. Because we are now logged in with the manager user and need to change a system file we have to use sudo.

Issue the command sudo nano /etc/ssh/sshd_config, change the line PermitRootLogin yes to PermitRootLogin no and insert a new line AllowUsers manager

Restart the server sudo systemctl restart ssh and check the status sudo systemctl status ssh.

Exit the SSH connection and try to login with the root user. The client should not be able to establish the connection. Only the login with manager should work.

//FAIL
ssh -p 44933 root@51.38.124.133

//OK
ssh -p 44933 manager@51.38.124.133

Disable password login

Using public/private keys as authentication is considered to be more secure than using passwords. In this section we will disable password authentication and switch to Ed25519 public/private key authentication (elliptic curve algorithm).

First we have to create a key pair for the server.

sudo ssh-keygen -f /etc/ssh/ssh_host_ed25519_key -N '' -t ed25519

This creates a public and a private key and stores them in the /etc/ssh/ directory. Open the SSH configuration sudo nano /etc/ssh/sshd_config and uncomment (remove #) the following line

HostKey /etc/ssh/ssh_host_ed25519_key

Save the change and restart the SSH server sudo systemctl restart ssh

Next we need to create a public/private key pair on the client computer. Make sure that you open a new shell or close the SSH connection and issue this command

ssh-keygen -N "mysupersecretpassphrase" -t ed25519 -C "mydesktopcomputer"

This command generates a public and private key and stores them in two files (id_ed25519 and id_ed25519.pub) in the home directory of the logged in user.

The -N option specifies a passphrase that protects the private key. You could create a private key that is not password protected, but I would advise against this because everybody that has access to the private key file can login to the server without entering any password. The -C is a description about the key.

Next we need to transfer the public key from the client to the server.

ssh -p 44933 manager@51.38.124.133
mkdir /home/manager/.ssh
nano /home/manager/.ssh/authorized_keys

copy and paste the content from your public key <user_home>/.ssh/id_ed25519.pub into the editor. Close nano with ctrl+o and ctrl+x. We need to change the permission of the authorized_keys file, SSH ignores the file if it does not has the correct permissions.

chmod 0600 /home/manager/.ssh/authorized_keys

If you work on Linux or macOS you can issue the ssh-copy-id command that does all the steps above in one command

ssh-copy-id -i ~/.ssh/id_ed25519.pub manager@51.38.124.133

If ssh-copy-id is not installed you can run this one liner

cat ~/.ssh/id_ed25519.pub | ssh manager@51.38.124.133 "mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod -R go= ~/.ssh && cat >> ~/.ssh/authorized_keys"

Close the SSH connection and try to login with the key.

ssh -i <user_home>/.ssh/id_ed25519 -p 44933 manager@51.38.124.133

The client asks for the private key's passphrase and if everything is okay opens the connection without asking for another password.

With public/private authentication working we can disable the password authentication in the SSH server. Open the configuration file sudo nano /etc/ssh/sshd_config, search for the line PasswordAuthentication yes and change it to PasswordAuthentication no. Save and close the editor and restart the SSH server.

When you want to access the SSH server from multiple clients, it is recommended to create a key pair on each device and add it to the /home/manager/.ssh/authorized_keys file. Insert a comment after the key so you know which client uses which key. If one of the devices gets lost or stolen you remove the entry in the authorized_keys file. This makes the private key useless and nobody can access the server with this key even when they are able to brute force the passphrase.


Simplify client access

To simplify the command on the client you can enter all the command line option in the <user_home>/.ssh/config file. Create the file if it does not already exist.

Host 51.38.124.133
  User manager
  IdentityFile ~/.ssh/id_ed25519
  IdentitiesOnly yes
  Port 44933

Now you can connect to the server with just this command: ssh 51.38.124.133

The only problem left is that we have to enter the passphrase for the private key each time we want to connect. It would be nice if we only have to do that once per session. For that SSH provides the SSH agent. First start the ssh-agent and then add the key with this command: ssh-add <user_home>\.ssh\id_ed25519

On Windows 10 (April 2018 Update) ssh-agent is installed as a service. It is not started automatically. To start it automatically, change the Startup Type in the Service panel to Automatic.


Install Firewall

As the last step in this tutorial we install a firewall. I usually install the Uncomplicated Firewall UFW. UFW is a frontend for iptables and eases the firewall configuration.

sudo apt install ufw

When we enable UFW, it will block by default every incoming connection. Therefore, it is important that we allow incoming connections to the SSH server before enabling the firewall.

sudo ufw allow 44933/tcp

Check that the rule is added

sudo ufw show added

Make sure that the port matches the listening port of the SSH server. If there is a mismatch, you can no longer connect to the server.
Enable the firewall

sudo ufw enable

Check the current active firewall rules.

sudo ufw status

Close the SSH connection with exit and then try to reconnect. The firewall rule is configured correctly when the SSH client is able to open a connection.

For more information about UFW visit the official homepage: https://help.ubuntu.com/community/UFW


Our plain server is ready for future endeavours. If there are errors in my description or other useful configuration steps that should be done on a fresh VPS server, send me a message.

If you can't wait installing software here is an awesome list of software packages you can self-host:
https://github.com/Kickball/awesome-selfhosted

See also my other blog posts:

Self-hosted Git server with Gitea:
https://golb.hplar.ch/2018/06/self-hosted-git-server.html

Self-hosted Google Drive alternative with SparkleShare:
https://golb.hplar.ch/2018/06/self-hosted-gdrive-onedrive-dropbox-alternative.html

Sending emails:
https://golb.hplar.ch/2018/06/send-only-email.html

Self-hosted tile server:
https://golb.hplar.ch/2018/07/self-hosted-tile-server.html

Self-host Polyfill.io:
https://golb.hplar.ch/2018/01/Self-host-Polyfill-io.html