Set up a secure homeserver with CentOS - Part 1

Hey all, In this post I want to take a look at setting up a secure home server with CentOS. Why CentOS and not the more common distros such as Debian? Well, I like the stability and leanness of CentOS and the the package manager is neat as well.

Pretty much everything runs on this thing as easy as it does under Debian, but the added security and stability are a great plus. Besides, I prefer separating/containerizing everything anyway, the underlying host better be as stable as possible.

Stability mostly comes from well-tested, older packages. If you want the latest and greatest, consider running Ubuntu Server.

In Part 1 we’ll look at doing a post-installation setup of CentOS. In later parts, we’ll take a look at Docker and setting up containers.

This page was edited on January 16th 2018 to add some hyper-v related commands

To virtualize or not

First of, I’ve got everything installed in a virtual machine under Hyper-V. Hyper-V is freely available via the Microsoft website by applying for the unlimited Hyper-V 2016 evaluation. Be aware that this is the core-version only with no way to upgrade to a GUI for free. This requires some Powershell knowledge and can be a pain with non-server hardware to get VLAN support working as most consumer networking cards don’t support this out-of-the-box. Alternatively, you can also install CentOS directly on the metal through installation with a USB stick. Several good programs are available for both Windows and MacOS.


Okay, initial CentOS setup is pretty straight forward and requires barely any user interaction apart from setting the user and root password. Please choose carefully! Then, onto the set up process itself. This tutorial used CentOS release 7.3.1611. If you’re on CentOS 7, the commands will most likely be the same, but it’s always wise to check for updates and run them.

To check your version:

cat /etc/centos-release

To check whether there are updates:

sudo yum check-update

Let the operating system update itself:

sudo yum update


Let’s start with the timezone setup, because time is an often overlooked component, but can be every important in logging and troubleshooting. To check the current time settings:

sudo timedatectl

Check whether ntp is installed in this section, if not, follow up with these commands to install time synchronisation:

sudo yum install ntp

Then enable the application to autostart:

sudo systemctl start ntp
sudo systemctl enable ntp

To check the available timezones for this system:

sudo timedatectl list-timezones

Pick the timezone applicable to you and your server, such as Amsterdam in my case:

sudo timedatectl set-timezone Europe/Amsterdam

Then, you can check your settings again with the timedatectl command.


By default the firewall is already enable, but it won’t hurt to check:

sudo systemctl status firewalld

If the firewall is not running, then enable it with the following command:

sudo systemctl start firewalld
sudo systemctl enable firewalld

It’s worth checking what services are enabled to pass through the firewall. Also to allow for later remote sessions with ssh for example:

sudo firewall-cmd --permanent --list-all

The permanent flag allows you to check the permanent rules only, by removing that flag all rules become visible. If properly set up, these two scenarios shouldn’t differ in most setups. Typical output for this command looks something like this:

  target: default
  icmp-block-inversion: no
  services: dhcpv6-client ssh
  masquerade: no
  rich rules:

This indicates that in my case the firewall is set to public (default) and allows only the DHCP ipv6 client and ssh. If SSH is not yet in the list, you can add it by using the following line:

sudo firewall-cmd --permanent --add-service=ssh

To find other services to enable:

sudo firewall-cmd --get-services

Adjusting Sudo password time-out

To adjust the time-out period for the server in which in asks again for the sudo password, it’s possible to alter the sudoers file. However, be careful in the altering the commands, since it can seriously damage your installation.

My commands below have been tested (by me =)), but it’s strongly recommended to do this through the visudo option (sudo visudo) as this will check grammar as well.

Backup the file beforehand with the following command!

sudo cp /etc/sudoers /etc/sudoers.backup

Then the time-out period can be adjusted. In this case, it’s adjusted to 30 minutes:

sudo sh -c 'echo "Defaults timestamp_timeout=30">>/etc/sudoers'

Alternatively, to always require the password, the timestamp_timeout should be set to 0. To completely disable it, set it to -1.

Setlocale warning

My installations usually show a warning on the setlocale settings, which looks something like this:

-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory

This can easily be fixed by adding a few lines to /etc/environment:

sudo vi /etc/environment

Insert by pressing i.


Then hit Esc on the keyboard and save and close by typing:


Click here for more information on vi editor.

Hyper-V specific

To allow for automatic expandable memory, contrary to a pre-selected set amount, the machine needs to allow for this:

sudo vi /etc/udev/rules.d/100-balloon.rules

In this empty file, paste the following:

SUBSYSTEM=="memory", ACTION=="add", ATTR{state}="online"

Most Hyper-V related tools are already installed in CentOS, however some features are not yet installed and enabled, such as:

  • VSS daemon (for backup of a live system)
  • KVP daemon
  • Powershell File copy daemon

If you want to enable this, then issue the following command:

sudo yum install -y hyperv-daemons

Lastly, you would want to disable the disk I/O optimiser, since Hyper-V is already doing this as well and having two optimisers is usually far from ideal. To do this, we have to be root first and then issue the appropriate command:

su root
echo noop > /sys/block/sda/queue/scheduler

Installing Docker

Now, we’re ready to install Docker Community Edition. The latest documentation can be found here, but I though it would be good to write a compact version here, also as my own documentation. Start by installing the pre-requistes:

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

Now, we should add the docker repository to our sources.list:

sudo yum-config-manager --add-repo

By installing docker with the standard command set, we install the latest release. Alternatively, a release can be selected from the channel. The available releases are visible with the following command:

yum list docker-ce --showduplicates | sort -r

If you want to select a specific version, then replace docker by the name of the version from the list you just received (sudo yum install). Otherwise, proceed with the following command:

sudo yum install docker-ce

Since we’re downloading from a third party source, please check the fingerprint whether it matches:

Importing GPG key 0x621E9F35:
Userid     : "Docker Release (CE rpm) <[email protected]>"
Fingerprint: 060a 61c5 1b55 8a7f 742b 77aa c52f eb6b 621e 9f35
From       :

To start Docker:

sudo systemctl start docker

To autostart Docker after reboot:

sudo systemctl enable docker

Docker is now ready for usage. However, it’s strongly recommended to also complete the following steps as a security best-practice.

Docker security

Since Docker binds to the socket, it runs with root privileges meaning that sudo’ing is constantly required to make changes. I mean, elevating yourself to root user is bad practice. Bad admin, bad admin!

So, create a group called Docker:

sudo groupadd Docker

Then add your local user to that group:

sudo usermod -aG Docker <user>

In my case, this would be:

sudo usermod -aG Docker linux

The new group assignment will be active after logging out and back into the machine, because of the revaluation of the user rights. If for whatever reason you would want to point Docker to another set of DNS servers, then you can add this in the config file:

sudo vi /etc/docker/daemon.json

and add the following key in this file:

        "dns": ["", ""]

Then restart Docker:

sudo systemctl restart Docker

For more linux configuration options, please review the official Docker documentation.

Optional - Docker compose

Docker compose allows for easier container management when using multiple containers at the same time. Since I’m planning on doing so, I’ll install docker-compose. However, in a later tutorial I will include the commands for both docker and docker-compose to get containers to work. For more information, please review the excellent documentation on the Docker website.

To start installing, first review the latest version on the Docker Github page. At the time of writing, version 1.18.0 is the latest. Before issuing the following command, please beware that a script is kicked off and this carries some security risk. Please review the contents of the script before kicking it of on the Github page. After code review, the following command can be used for installation:

sudo curl -L`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

Then, adjust the rights to run docker-compose:

sudo chmod a+rx /usr/local/bin/docker-compose

You can check if the docker-compose commands can be found by

which docker-compose

This should return the path /usr/local/bin/docker-compose To check the Docker-compose version:

docker-compose --version