This note contains a basic Ubuntu 18.04 server setup. The server will be installed on a encrypted LVM volume which can be unlocked via SSH. This are the settings I found most useful for me, I can’t guaranty a completely secure system by using this notes. If you find any issues or you have suggestions on what I could improve in this setup, just message me.
For advanced options, such as encrypted LVM volumes, to be available during installation, the image must be loaded from the alternative Ubuntu download page and not from the main website - which provides a image which uses the Subiquity installer. The ISO file with the classic installer, which offers more options, can be found on the Ubuntu alternative download page. Select the image for your type of computer, usually the ubuntu-18.04-server-amd64.iso. The installation is straightforward, just follow the installation instructions. Make sure to select a encrypted LVM volume, the installer will ask you for a security key afterwards. You can also select to install the OpenSSH server, because we’ll use it to access the server.
After a reboot you have to unlock the LVM volume with the security key you selected during the installation.
First of all update the server.
sudo apt update sudo apt upgrade
Language / Region settings
I sometimes have problems with language and region settings after installation. To fix this, I set the locales to en_US.UTF-8.
sudo locale-gen en_US.UTF-8 export LANGUAGE=en_US.UTF-8 export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 sudo locale-gen en_US.UTF-8 sudo dpkg-reconfigure locales
This step is optional and depends on how and where you host your server. I need to setup a static IP, which I do in the network settings like follows:
sudo vim /etc/netplan/01-netcfg.yaml
Here’s an example file, the IPs must be changed according to your setup.
network: version: 2 renderer: networkd ethernets: ens3: dhcp4: no dhcp6: no addresses: [192.168.14.2/24, "2001:4::1/64"] gateway4: 192.168.14.1 gateway6: 2001:4::1 nameservers: addresses: [184.108.40.206, 220.127.116.11, "2001:1608:10:25::1c04:b12f", "2001:1608:10:25::9249:d69b"]
addresses contain the IPs of the server. The rest of the settings should be self-explanatory. After changing the config, apply it by:
We also want to setup some IP settings for security. This can be done in:
sudo vim /etc/sysctl.d/50-ip-sec.conf
I’ll just post my configuration file, which disables ICMP redirects, enables IP spoofing protection, ignores broadcast requests and so on. I also disable IPv6 auto configuration, because it’s manually configured in the step before. Some more information about the various options can be found in the redhat docs - Securing Network Access .
# Disable Source Routing net.ipv4.conf.all.accept_source_route = 0 net.ipv6.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 net.ipv6.conf.default.accept_source_route = 0 # Disable acceptance of all ICMP redirected packets on all interfaces net.ipv4.conf.all.accept_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv6.conf.default.accept_redirects = 0 # Disable send IPv4 redirect packets net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 # Set Reverse Path Forwarding to strict mode as defined in RFC 3704 net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 # Ignore ICMP broadcast requests net.ipv4.icmp_echo_ignore_broadcasts = 1 # Block pings net.ipv4.icmp_echo_ignore_all = 1 # Syn flood help net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 2048 net.ipv4.tcp_synack_retries = 2 net.ipv4.tcp_syn_retries = 5 # Log suspicious martian packets net.ipv4.conf.all.log_martians = 1 net.ipv4.conf.default.log_martians=1 net.ipv4.icmp_ignore_bogus_error_responses = 1 # Disable IPv6 auto config net.ipv6.conf.default.accept_ra=0 net.ipv6.conf.default.autoconf=0 net.ipv6.conf.all.accept_ra=0 net.ipv6.conf.all.autoconf=0 net.ipv6.conf.eth0.accept_ra=0 net.ipv6.conf.eth0.autoconf=0
After you’ve created / changed this file, apply the settings:
sudo sysctl --system
Copy your SSH key
If you haven’t selected the option to install the OpenSSH server during the installation process do it now:
sudo apt install openssh-server
We will setup the server to allow SSH access only via SSH keys. Therefore, the public key to be used should be copied to the server at this point. If you don’t have an SSH key yet, it has to be generated - I made a note for that. Here is an example, which needs to be executed on your client system, not on the server, of how a key can be copied to the server:
ssh-copy-id -i ~/.ssh/id_ed25519.pub email@example.com
I copy my Ed25519 public key for the user dennis to the server dennisnotes.com. Make sure to use the public key (.pub) and not your private key! You’ll be asked to provide your password to copy the key to the server. This is because we still use the default SSH settings. We’ll change this in the next step.
In the last step you should test if the access to the server with the SSH key works. Do this from your client machine. It should open up a SSH connection using your SSH key. Maybe you need to unlock the key by entering the keys password.
In addition to the Ed25519 key, I copy an RSA key to the server, which will later be used for the Dropbear SSH server to unlock the encrypted LVM volume via SSH:
ssh-copy-id -i ~/.ssh/id_rsa.pub firstname.lastname@example.org
SSH server configuration
The OpenSSH configuration is located at /etc/ssh/sshd_config.
sudo vim /etc/ssh/sshd_config
I just post the content of my config here. In short I forbid the root login and password logins, I allow the login only for the user dennis, I change the default port 22 to another (e.g. 1234), I use protocol 2 and I allow the login via SSH key. Some more tips and details about the settings can be found in the SSH Docs as well as in the Debian Doc.
Port 1234 # Security by obscurity doesn't work, but it leads to smaller fail2ban logs etc. AllowUsers dennis Protocol 2 HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_ed25519_key # Logging SyslogFacility AUTH LogLevel INFO # Authentication: LoginGraceTime 120 PermitRootLogin no UsePrivilegeSeparation yes StrictModes yes MaxAuthTries 3 MaxSessions 10 PubkeyAuthentication yes RSAAuthentication yes AuthorizedKeysFile %h/.ssh/authorized_keys IgnoreRhosts yes RhostsRSAAuthentication no HostbasedAuthentication no PasswordAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no UsePAM yes # Additional settings X11Forwarding no PrintMotd no Banner none DebianBanner no AcceptEnv LANG LC_* Subsystem sftp /usr/lib/openssh/sftp-server
After you’ve changed the config file restart the ssh service.
sudo systemctl restart sshd
After setting up the SSH server a firewall should be activated to secure the system. We’ll use the uncomplicated firewall (UFW). UFW should be installed by default, if not install it now. afterwards enable the SSH port, which you’ve set in your sshd_config. In the example above this would be port 1234. Afterwards you need to enable the firewall.
sudo apt install ufw sudo ufw allow 1234/tcp sudo ufw enable
You should still be able to connect to your system via the ssh port. Test it by executing the following command on your client system:
ssh -p 1234 email@example.com
Note the -p 1234, with the option -p we set the ssh port of the remote system.
To allow only users in a given admin group to switch users - su - execute the following steps in which you create a admin group, add a user dennis to this group and restrict the access to /bin/su to the admin group.
sudo groupadd admin sudo usermod -a -G admin dennis sudo dpkg-statoverride --update --add root admin 4750 /bin/su
Fail2ban is an intrusion prevention system that basically monitors log files and searches for certain patterns corresponding to a failed login. If a certain number of failed login attempts are detected from an IP address within a certain time, fail2ban blocks access for this IP address by creating a corresponding firewall rule. First of all install fail2ban:
sudo apt install fail2ban
Fail2Ban can be configured via configuration files in /etc/fail2ban/jail.d. Further filters can be created in /etc/fail2ban/filter.d. Currently our system is only accessible via SSH, so we should fail2ban watch the SSH access. To do so create a new configuration file like follows:
sudo vim /etc/fail2ban/jail.d/ssh.conf
Here is a example configuration file.
[sshd] enabled = true port = 1234 filter = sshd logpath = /var/log/auth.log maxretry = 3
It is a relatively simple configuration that specifies that we monitor SSH access to port 1234, whose log files are located at /var/log/auth.log. To check the log file for failed logins, the filter sshd, which is included in the installation, is used. After three failed login attempts the corresponding IP address will be banned. It is also possible to notify the administrator by e-mail if IP addresses have been banned, etc. There are several sources on the Internet, such as the official fail2ban documentation.
After a new configuration has been added, the fail2ban service must be restarted. After the restart, the new configuration should appear in the status query from the fail2ban client, which can then also be viewed in detail.
sudo systemctl restart fail2ban sudo fail2ban-client status sudo fail2ban-client status sshd
LVM Volume - SSH unlock via Dropbear
To unlock the LVM volume via SSH on a reboot we need a little SSH server which is only used during the boot process. This is where Dropbear comes in. Install it via:
sudo apt install dropbear-initramfs
Next we need to set the port we want to use, as well as some other options:
sudo vim /etc/dropbear-initramfs/config
Here is a example of how my configuration looks like:
DROPBEAR_OPTIONS="-p 1234 -s -j -k -I 60"
In the next step you have to specify the RSA key you want to use later. I already copied my id_rsa.pub key to the server in a previous step, it can be found at ~/.ssh/authorized_keys. The key, e.g. ssh-rsa blablakey comment, must now be copied. At the end it must be added to the authorized_keys of dropbear:
sudo vim /etc/dropbear-initramfs/authorized_keys
We add some more options like no X11 forwarding etc. for security, my file looks like this:
no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="/bin/cryptroot-unlock" ssh-rsa blablakey comment
Setup the IP Address in grub
I need a static IP which I setup in a step before, which is only loaded after I decrypted the LVM volume and booted Ubuntu. To set the IP address before I add the following flag in the GRUB config.
sudo vim /etc/default/grub
Heres an example of my GRUB_CMDLINE_LUNX_DEFAULT setting in which 192.168.14.2 is the servers IP, 192.168.14.1 the Gateway and dennisnotes the hostname.
After you’ve added this you need to recreate the grub.cfg file like follows:
Test the SSH LVM Volume unlock
ssh firstname.lastname@example.org -p 1234
- type pw
This is my base server setup. In further notes I will explain how to set up nginx, Nextcloud via Docker images with a nginx proxy and so on.