Skip to main content

CentOS

Implementing name-based hosting on CentOS

Normally, if you install Apache as shown in the previous process, you can host exactly one website that is accessible as the server’s IP address or the domain name Apache is running on, for example, http://192.168.1.100 or http://www.centos7.home. Such a system is very wasteful for your server resources as you would need individual servers with Apache installed for every single domain you want to host. Name-based or virtual hosting is used to host multiple domains on the same Apache web server. If a number of different domain names have already been assigned to your Apache web server’s IP address using a DNS server or through a local /etc/hosts file, virtual hosts can be configured for every available domain name to direct the user to a specific directory on the Apache server containing the site’s information. Any modern webspace provider uses this kind of virtual hosting to divide one web server’s space into multiple sites. There is no limit to this system and to the number of sites to create from it as long as your web server can handle its traffic. In this process, we will learn how to configure name-based virtual hosting on the Apache web server.

To Start With: What Do You Need?

To complete this process, you will require a working installation of the CentOS 7 operating system with root privileges and a console-based text editor of your choice. It is expected that your server will be using a static IP address and Apache is installed and currently running, and that you have enabled system users publishing directories in an earlier process. Virtual host names cannot work without previously setting up one or more domains or subdomains outside Apache.

For testing, you could set up your /etc/hosts (see the Setting your hostname and resolving the network process in segment Chapter 2, Configuring the System) or configure some A or CNAMES in your BIND DNS server (refer to Chapter 9 , Working with Domains) to use different domain names or subdomains, such as www.centos7.home, all pointing to your Apache web server’s IP address.

Note
A common misconception is that Apache can create domain names for your Apache web server on its own. This is not true. The different domain names you want to wire to different directories using virtual hosts need to be set up in a DNS server or /etc/hosts file to point to your Apache server’s IP address before you can use them with virtual hosts.

The Process

For the purpose of this process we will be building some local virtual hosts with the following Apache example subdomain names: www.centos7.home, web1.centos7.home, web2.centos7.home and .centos7.home for the corresponding web publishing folders /var/www/html, /var/www/web1, /var/www/web2, and /home//public_html for the domain’s network name centos7.home. These names are interchangeable and it is expected that you will want to customize this process based on something more appropriate to your own needs and circumstances.

  1. To begin, log in as root on your Apache server and create a new configuration file that will hold all our virtual host definitions:
    vi /etc/httpd/conf.d/vhost.conf
  2. Now put in the following content, customizing the centos7.home value and the username to fit your own needs:

           ServerName centos7.home
           ServerAlias www.centos7.home
           DocumentRoot /var/www/html/


             ServerName web1.centos7.home
             DocumentRoot /var/www/web1/public_html/


             ServerName web2.centos7.home
             DocumentRoot /var/www/web2/public_html/


             ServerName .centos7.home
             DocumentRoot /home//public_html/
  3. Now save and close the file in the usual way before proceeding to create the directories for both virtual hosts that are currently missing:
    mkdir -p /var/www/web1/public_html /var/www/web2/public_html
  4. Having done this, we can now create default index pages for the missing subdomains web1 and web2 by using our favorite text editor, as follows:
    echo "

    Welcome to Web1

    " >
    /var/www/web1/public_html/index.html
    echo "

    Welcome to Web2

    " >
    /var/www/web2/public_html/index.html
  5. Now reload the Apache web server:
    apachectl configtest && systemctl reload httpd
  6. Now, for simple testing purposes, we will just configure all our new Apache web server’s subdomains in the hosts file of the client computer that wants to access these virtual hosts, but remember that you can also configure these subdomains in a BIND DNS server. Login to this client computer (it needs to be in the same network as our Apache server) as root and add the following lines to the /etc/hosts file, assuming our Apache server has the IP address 192.168.1.100:
    192.168.1.100 www.centos7.home
    192.168.1.100 centos7.home
    192.168.1.100 web1.centos7.home
    192.168.1.100 web2.centos7.home
    192.168.1.100 john.centos7.home
  7. Now on this computer, open a browser and test things out by typing the following addresses into the address line (replace with the username you defined for the virtual host): 
    http://www.centos7.home, http://web1.centos7.home, http://web2.centos7.home and http://.centos7.home.

How Does It Work?

The purpose of this process was to show you how easy it is to implement name-based virtual hosting. This technique will boost your productivity and using this approach will give you unlimited opportunities to domain-based web hosting.

So what did we learn from this experience?

We began by creating a new Apache configuration file to hold all our virtual host configuration. Remember, all files ending with the .conf extension in the /etc/httpd/conf.d/ directory will be loaded automatically when Apache is started. Following this, we then proceeded to put in the relevant directive blocks, starting with our default server root centos7.home and the alias www.centos7.home. The most important option in any virtual host block is the ServerName directive, which maps an existing domain name for our web server’s IP address to a specific directory on the filesystem. Of course, there are many more settings you can include, but the previous solution provides the basic building blocks that will enable you to use it as the perfect starting point. The next step was to then create individual entries for our centos7.home subdomains web1, web2, and . Remember, each virtual host supports the typical Apache directives and can be customized to suit your needs. Refer to the official Apache manual (install the YUM package httpd-manual, then go to the location /usr/share/httpd/manual/vhosts/) to learn more. After we created our virtual host blocks for every subdomain we wanted, we then proceeded to create the directories to hold the actual content and created a basic index.html in each directory. In this example, our web1 and web2 content directories were added to /var/www. This is not to imply that you cannot create these new folders in another place. In fact most production servers generally place these new directories in the home folder, as shown with our /home//public_html example. However, if you do intend to take this approach, remember to modify the permissions and ownership, as well as SELinux labels (outside/var/www you need to label Apache directories as httpd_sys_content_t) of these new directories so that they can be used as they were intended. Finally, we reloaded the Apache web service so that our new settings would take immediate effect. We could then directly use the subdomain names in our browser to browse to our virtual hosts when correctly set up in /etc/hosts on the client or on a BIND DNS server.

 

Setting up an authoritative-only DNS server on CentOS

In this process, we will learn how to create an authoritative-only DNS server, which can give answers to queries about domains under their control themselves instead of redirecting the query to other DNS servers (such as our caching-only DNS server from the previous process). We will create a DNS server to resolve all our own hostnames and services in our own private local network.
 
As said before, while Unbound should be your first choice when needing a caching-only DNS server as it is the most secure DNS server solution available, it has only limited authoritative capabilities which often is not enough for professional DNS server usage. Here, instead of name lookup of our local servers, we will use the popular authoritative BIND DNS server package and configure a new DNS zone to provide highly customizable name resolution. Technically speaking, we will be writing both a forward and reverse zone file for our domain. Zone files are text files that contain the actual domain name to IP address mappings or the other way around, that is, IP address mappings to domain name mappings. While most queries to any DNS server will be the translation of names to IP addresses, the reverse part is also important to set up if you need the correct domain name for any given IP address. We will configure BIND to be authoritative-only, which means that the server will only answer queries it is authoritative for (has the matching records in its zones), so if the DNS server cannot resolve a requested domain, it will stop the request and not contact other DNS servers using recursive requests to fetch and construct the correct answer.

To Start With: What Do You Need?

To complete this process, you will require a working installation of the CentOS 7 operating system with root privileges, a static IP address, and a console-based text editor of your choice. An Internet connection will be required to download additional packages. In this example, our DNS server runs in the private network with the network address 192.168.1.0/24. Our DNS server should manage a local private domain we decide to be centos7.home (in the form domain.toplevel-domain). The IP address of the new DNS server will be 192.168.1.7 and should get the hostname ns1, leading to the Fully Qualified Domain Name (FQDN) ns1.centos7.home. (Refer to the Setting your hostname and resolving the network process in Chapter division 2 , Configuring the System to learn more about FQDNs). Our configured zone will have an administrative e-mail address with the name admin@centos7.home, and for simplicity, all the other computers in this network will get hostnames such as client1, client2, client3, and so on. We will also have some mail, web, and FTP servers in our own network, each running on separate dedicated servers. We will be using the port 8053 for our BIND service as we already have Unbound running on the same server using the default DNS port 53.

The Process

For security reasons, we will allow BIND to resolve internal LAN names only (authoritative-only) and only allow localhost to make DNS queries; no other clients in our network can connect to it:
  1. To begin with, log in as root on your Unbound DNS server and install the required BIND package and enable the DNS server on boot:
    yum install bind && systemctl enable named
  2. The actual name of the DNS server in the BIND package is called named, so let’s open its main configuration file to make some adjustments after creating a backup copy of it first:
    cp /etc/named.conf /etc/named.conf.BAK; vi /etc/named.conf
  3. First, find the line listen-on port 53 { 127.0.0.1; }; and then change the port number to the custom port 8053, so it reads as follows:
    listen-on port 8053 { 127.0.0.1; };
  4. Next, find the line listen-on-v6 port 53 { ::1; } and change it to:
    listen-on-v6 port 8053 { none; };
  5. Next, since we are configuring an authoritative-only server, we will disable contacting other remote DNS servers, find the line that reads recursion yes; and change it to:
    recursion no;
  6. Save and close the file, and then validate the syntax of our config changes (no output means no errors!):
    named-checkconf
  7. Now tell SELinux about the changed named DNS port (this needs package policycoreutils-python):
    semanage port -a -t dns_port_t -p tcp 8053
  8. Now type the following command in order to create your forward zone file. Name the file after the domain whose resource records it will contain:
    vi /var/named/..db
  9. In our example, for our centos7.home domain, this will be:
    vi /var/named/centos7.home.db
  10. Now simply add the following lines (be careful not to forget typing the tailing dots in the domain names). We will start with the Start of Authority (SOA) block:
    $TTL 3h
    @ IN SOA ns1.centos7.home. admin.centos7.home.(
    2015082400 ; Serial yyyymmddnn
    3h ; Refresh After 3 hours
    1h ; Retry Retry after 1 hour
    1w ; Expire after 1 week
    1h) ; Minimum negative caching
  11. Afterwards, add the rest of the file’s content:
    ; add your name servers here for your domain
              IN            NS           ns1.centos7.home.
    ; add your mail server here for the domain
              IN            MX     10    mailhost.centos7.home.
    ; now follows the actual domain name to IP
    ; address mappings:

    ; first add all referenced hostnames from above
    ns1              IN             A             192.168.1.7
    mailhost         IN             A             192.168.1.8
    ;  add all accessible domain to ip mappings here
    router          IN              A              192.168.1.0
    www             IN              A              192.168.1.9
    ftp             IN              A              192.168.1.10
    ;  add all the private clients on the Lan here
    client1         IN              A              192.168.1.11
    client2         IN              A              192.168.1.12
    client3         IN              A              192.168.1.13
    ;   finally we can define some aliases for
    ;   existing domain name mappings
    webserver IN CNAME www
    johnny IN CNAME client2

  12. When you have finished, simply save and close the file before proceeding to create the reverse zone file for our private subnetwork used by our domain (the C-Class are the first three numbers (octets) which are separated by dots: XXX.XXX.XXX. For example, for the 192.168.1.0/24 subnet the C-Class is 192.168.1:
    vi /var/named/db.
  13. In our example, a reverse zone file resolving our centos7.home's 192.168.1 C-Class subnet will be:
    vi /var/named/db.1.168.192
  14. First put in the exact same SOA as in step 10, and then append the following content to the end of the file:
    ;    add your name servers for your domain
                           IN          NS          ns1.centos7.home.
    ; here add the actual IP octet to
    ; subdomain mappings:
    7           IN          PTR       ns1.centos7.home.
    8           IN          PTR       mailhost.centos7.home.
    9           IN          PTR       www.centos7.home.
    10          IN          PTR       ftp.centos7.home.
    11          IN          PTR       client1.centos7.home.
    12          IN          PTR       client2.centos7.home.
    13          IN          PTR       client3.centos7.home.
  15. Save and close the file, and then add our new zone pair to the named configuration. To do this, open named.conf again:
    vi /etc/named.conf
  16. Now locate the line including "/etc/named.rfc1912.zones";. Immediately following this line, create a space for your work and add the appropriate zone statement to enable your reverse zone, as follows (substitute XXX.XXX.XXX with the reversed C-Class of your reverse zone file name, in our example 1.168.192):
    zone "XXX.XXX.XXX.in-addr.arpa." IN {
    type master;
    file "/var/named/db.XXX.XXX.XXX";
    update-policy local;
    };
  17.  Having done this, you can now proceed to add a zone statement for your forward zone right afterwards, as follows (replacing ..db with your forward zone file name, in our example centos7.home):

    zone ".." IN {
    type master;
    file "/var/named/..db";
    update-policy local;
    };

  18. When you have finished, simply save and close the file, and then restart the bind service using:
    named-checkconf && systemctl restart named

How Does It Work?

All DNS servers are configured to perform caching functions, but where a caching-only server is restricted in its ability to answer queries from remote DNS servers only, an authoritative nameserver is a DNS server that maintains the master zone for a particular record.
 
So what have we learned from this experience?
 
The purpose of this process was to setup an authoritative-only BIND DNS server and provide a new zone for it. A DNS zone defines all the available resources (hostnames and services) under a single domain. Any DNS zone should always consist of both a forward and reverse zone file. To understand zone configurations, we need to discuss DNS hierarchy first. For example, take a DNS domain from the example in this process client1.centos7.home. Every computer in our private network has a hostname (for example, client1 or www) and is a member of a domain. A domain consists of the Second-level Domain (SLD) (for example, centos7) and a Top-level Domain name (TLD) (for example, home, org, com, and so on). On top of that TLD is the root domain (written . dot) which often is neglected when working with other programs or configurations. However, when working or defining FQDN in zone configurations, it is very important to never forget to add this dot . after the TLD. For example, a DNS domain for our client1 computer would be client1.centos7.home., whereas an FQDN for the /etc/hosts file is often written in the format client1.centos7.home (technically this is incorrect but most of the time sufficient). The root domain is very important because it contains the root DNS servers which will be queried first if an authoritative DNS server cannot find an existing entry for a requested domain in its own records (zones) or cache. But we have DNS servers in all the other domain hierarchies as well and this is how a DNS server makes its recursive requests. A root DNS server, as any other DNS server, resolves all its subdomains (defined in its zone files) which are the TLDs. These TLDs themselves can resolve all the SLDs (also defined in their zone files). The second-level domains resolve all their hostnames (which are special subdomains as they refer to individual computer or services on your network). So any DNS request traverses through the different DNS server hierarchies from the root DNS over the TLD DNS to the SLD DNS server. The root and the TLD DNS servers cannot fully resolve full domain DNS queries such as www.centos7.home and instead will resolve the correct address of the next DNS hierarchy. This system ensures that the root DNS will always find the correct TLD DNS server address and the TLD DNS server will always send the request to the right SLD DNS which has the correct zone file and is finally able to answer the requested DNS query.
 
So what did we learn from this experience?
 
As we have learned, a zone file is a simple text file that consists of directives and resource records and can look quite complicated as it contains a lot of two-letter abbreviations. Remember, you need to set up a zone file pair (forward and reverse) on a base domain level (for example, centos7.home) for all the hostnames and services running under it (for example, www, host1, api, and so on). After installing the named DNS server (which is part of the Berkeley Internet Name Domain (BIND) package), we made a copy of the original main configuration file and changed the default listening port from 53 to 8053 (as unbound is already listening on port 53) but kept it listening to localhost only, and disabled IPv6 to keep compatibility with the other major DNS servers (as IPv6 support is still limited on the Internet). Also, here we disabled recursion because our BIND DNS server had to be authoritative-only, which means that it is not allowed to forward DNS requests to other remote DNS servers when it could not resolve the query from its own zone records.
 
Then we began creating and customizing our own forward DNS zone file with the filename convention /var/named/..db. This file is opened with the $TTL control statement, which stands for Time to Live and which provides other nameservers with a time value that determines how long they can cache the records from this zone. This directive, as many others, is defined using seconds as the default time unit, but you can also use other units using BIND specific short forms to indicate minutes (m), hours (h), days (d), and weeks (w), as we did in our example (3h). Following this, we then provided a Start of Authority (SOA) record. This record contains specific information about the zone as a whole. This begins with the zone name (@), a specification of the zone class (IN), the FQDN of this nameserver in the format hostname.domain.TLD., and an e-mail address of the zone administrator. This latter value is typically in the form hostmaster.hostname.domain.TLD. and it is formed by replacing the typical @ symbol with a dot (.). Having done this, it was then a matter of opening the brackets to assign the zone’s serial number, refresh value, retry value, expire value, and negative caching timeto-live value. These directives can be summarized as follows:
  • The serial-number value is a numeric value, typically taking the form of the date in reverse (YYYYMMDD) with an additional value (VV), which is incremented every time the zone file is modified or updated, in order to indicate that it is time for the named service to reload the zone. The value VV typically starts at 00, and the next time you modify this file, simply increment it to 01, 02, 03, and so on.
  • The time-to-refresh value determines how frequently the secondary or slave nameservers will ask the primary nameserver if any changes have been made to the zone.
  • The time-to-retry value determines how frequently the secondary or slave nameservers should check the primary server after the serial number has failed. If a failure has occurred during the time frame specified by the time-to-expire value elapses, the secondary nameservers will stop responding as an authority for requests.
  • The minimum-TTL value determines how long the other nameservers can cache negative responses.
Having completed this section and having closed the corresponding bracket, we then proceeded to add the authoritative nameserver information (NS) with the IN NS definition. Typically speaking, you will have at least two, if not three, nameservers (put each nameserver’s FQDN in a new IN NS line). However, it is possible to set only one nameserver, which is particularly useful if you are running the server in an office or a home environment and would like to enjoy the benefit of local name resolution, such as .home, .lan, or .dev. The next stage then required us to include a reference for the Mail eXchanger (MX) records in order for us to specify a mail server for the zone. The format is IN MX
. The priority becomes important if you define more than one mail server (each in its separate IN MX line)—the lower the number, the higher the priority. In this respect, a secondary mail server should have a higher value.
 
Note
In the SOA, NS and MX lines we already referenced hostnames which aren’t defined as an IP mapping yet (A record). We could do this because the zone file is not processed sequentially. But do not forget to create corresponding A lines for each hostname later.
 
Depending on your needs, you may also intend to use your name server as your mail server (then you would write instead MX 10 ns1.centos7.home.), although you may have another server dedicated to that role as shown in the example.
 
Following this, it was then a matter of creating the appropriate A records (A for address) and assigning the appropriate IP address to the values shown. This is the heart of any domain name resolution requests to the server. An A record is used for linking an FQDN to an IP address, but much of the preceding settings will be based on your exact needs. Here you can define all the local host names you want to map in your network. As we have already used and referenced some domain names before in the zone file such as the nameserver or mailserver we would begin with these. Afterwards, we defined all the hostnames to IP address mappings for all public available and afterwards our internal clients. Remember that when using the A records you can have multiple mappings of the same IP address to different hostnames. For example, if you do not have dedicated servers for every service in your network but rather one server running all your DNS, mail, web, and ftp services, you can write the following lines instead:
 
ns1             IN A 192.168.1.7
mailhost    IN A 192.168.1.7
www IN A 192.168.1.7
ftp             IN A 192.168.1.7
 
You can also use a canonical name (CNAME) record for this task, which is used to assign an alias to an existing A record. Arguably, the CNAME value makes your DNS data easier to manage by pointing back to an A record. So if you ever consider the need to change the IP address of the A record, all your CNAME records pointed to that record automatically. However, and as this process has tried to show, the alternative solution is to have multiple A records, which implies the need for multiple updates in order to change the IP address.
 
At this stage of the process, we then turned our attention towards the reverse DNS zone. As with the forward zone file, the reverse zone files also have a special naming convention /var/named/db.. Naming your reverse zone file like db.1.168.192 can look strange first but makes sense when you look at how reverse lookup works. It starts from the highest node (in our example 192, which corresponds to the root domain in the forward zone file) and traverses its way down from it. As you see, the content we put in this file has some similarities between the directives and the resources used in the forward zone file. However, it is important to remember that reverse DNS is wholly separate and distinct from forward DNS.
 
The reverse DNS zone is designed to assist in the conversion of an IP address to a domain name. This can be done by using the Pointer Resource Record (PTR) which assigns unique IP addresses to one or more host names. For this reason, you must ensure that a unique PTR record exists for every A record. Every reverse zone file collects IP to hostname translations for a complete Class C address range (the first three dotted numbers, for example, 192.168.1). The last octets of such an IP range are all the hostnames which can be defined within such a file. Remember, the IP address value for the first column in a PTR record should only show this last octet. For example, the line 9 IN PTR www.centos7.home. in the reverse zone file db.1.168.192 will be able to resolve any reverse IP address requests of 192.168.1.9 to the domain value www.centos7.home.
 
Having created our forward and reverse zone files in this process, we then completed the configuration of the named service by adding our new zones to our BIND server in order to start our own domain name service resolving local domain names of our network. In these new appended forward and reverse zone definition blocks, we defined that we are the master zone holder and also specified update-policy local; because this is needed if we want to use the nsupdate command to update our zones dynamically from the localhost (see later). You may add unlimited zone pairs, but remember that each forward or reverse zone definition must be given a single zone entry in curly brackets.
 
In summary, we can say that forward and reverse zone files are defined on a single base domain name basis, one base domain gets one forward zone file. For reverse zone files, it’s a bit different because we are working with IP addresses. We create one zone file based on the Class C address range of the network address of our domain and here the last octet is called the hostname, for which we define our mappings in such a specific file.
 
BIND is a big subject and there is a lot more to learn as this process has only served to introduce you to the subject. In most cases, you may even find that your initial learning period will become known as a process of trial and error, but it will improve. Remember, practice makes perfect and if you do create additional forward zones, always reference them in the reverse zone file.
 

There's more…

 
Having created and added your zones to your BIND server, you are now able to test your configuration. To do this, you can use the host, dig or nslookup command to resolve internal hostnames from localhost only. For example, for testing forward DNS resolution we can use the dig command by specifying that our DNS server is running on localhost with port 8053: dig -p 8053 @127.0.0.1 client2.centos7.home. This should finish DNS lookup successfully and return the following line (output is truncated):
;; ANSWER SECTION:
client2.centos7.home. 10800 IN A 192.168.1.12

 
For reverse lookup, you will use an IP address instead (in this instance, the IP address used should correspond to a domain for which you have configured reverse DNS): nslookup port=8053 192.168.1.12 127.0.0.1. As we have configured BIND as an authoritative-only DNS server, any DNS request which is outside the local records of our zone should not be able to get fully resolved. To test this use dig -p 8053 @127.0.0.1 www.google.com which should return the status REFUSED and WARNING: recursion requested but not available message.
 
For security reasons, we restricted our BIND server to localhost only and did not allow it to connect to other DNS servers. Therefore you cannot use it as your only DNS solution for your private network. Instead, in the next process, we will learn how to combine Unbound with BIND to create an integrated and very secure all-in-one DNS server solution. But if you don’t want to do this and use BIND as your single and full authoritative DNS server solution (which is not recommended on CentOS 7 anymore), you can do this by disabling or uninstalling Unbound, restoring the original named.conf.BAK configuration file, and enabling the following directives in the BIND configuration file: allow-query {localhost;192.168.1.0/24;}; (which enables the complete 192.168.1.0/24 network to make DNS requests), listen-on port 53 {any;}; (listen for requests on any network), listen-on-v6 port 8053 { none; }; (for disabling IPv6). If you want BIND to be forwarding everything, which it is not authoritative for, instead of using recursion to find out the answer, add the following directives as well (in this example we use the official Google DNS servers for any forwarding requests, but you can change this to fit your needs): forwarders { 8.8.8.8;};forward only;. Then restart the bind service.
 

Installing and configuring fail2ban in CentOS

In this process, we will learn how to implement additional security measures for protecting the SSH server with a package called fail2ban. This is a tool that serves to protect a variety of services including SSH, FTP, SMTP, Apache, and many more against unwanted visitors. It works by reading log files for patterns based on failed login attempts and deals with the offending IP addresses accordingly. Of course, you may have already hardened your SSH server or another service on a direct application level, but it is the purpose of this process to show that, when faced with the possibility of Brute Force Attacks, an added layer of protection is always useful.

To Start With: What Do You Need?

To complete this process, you will require a working installation of the CentOS 7 operating system with root privileges, a console-based text editor of your choice, and a connection to the Internet in order to download additional packages. In addition to this, it will be assumed that YUM is already configured to download packages from the EPEL repository.

The Process

Fail2ban is not installed by default, and for this reason, we will need to invoke the YUM package manager and download the necessary packages:

  1. To begin this process, log in as root and type the following command:
    yum install fail2ban-firewalld fail2ban-systemd
  2. Create a new configuration file in your favorite text editor, like so
    vi /etc/fail2ban/jail.local
  3. Put in the following content:
    [DEFAULT]
    findtime = 900
    [sshd]
    enabled = true
  4. Now, append the following line that defines the ban period. It is calculated in seconds, so adjust the time period to reflect a more suitable value. In this case, we have chosen this to be one hour:
    bantime = 3600
  5. Then, append the maximum number of login attempts:
    maxretry = 5
  6. If you are running SSH over a custom port other than 22, you need to tell this to fail2ban as well (replace XXXX with your port number of choice) otherwise skip this step:
    port=XXXX
  7. Now, save and close the file in the usual way before proceeding to enable the fail2ban service at boot. To do this, type the following command:
    systemctl enable fail2ban
  8. To complete this process, you should now start the service by typing:
    systemctl start fail2ban

How Does It Work?

fail2ban is designed to monitor users who repeatedly fail to log in correctly on your server, and its main purpose is to mitigate attacks designed to crack passwords and steal user credentials. It works by continuously reading your system’s log files, and if this contains a pattern indicating a number of failed attempts, then it will proceed to act against the offending IP address. We all know that servers do not exist in isolation, and by using this tool, within a few minutes, the server will be running with an additional blanket of protection.

So, what did we learn from this experience?

fail2ban is not available from the standard CentOS repositories, and for this reason your server will need to have access to the EPEL repository. The installation of the fail2ban packages was very simple; besides the main fail2ban package, we installed two other packages to integrate it into CentOS 7’s new systemd and firewalld server technologies. Next, for our local customization, we created a new jail. local file. We started specifying the findtime parameter for all targets (specified within the [DEFAULT] section), which is the amount of time a user has when attempting to log in. This value is measured in seconds and implies that, if a user fails to log in within the maximum number of attempts during the designated period, then they are banned. Next, we enabled fail2ban for the sshd daemon by adding a [sshd] section. In this section, we introduced the bantime value, which represents the total number of seconds that a host will be blocked from accessing the server if they are found to be in violation of the rules. Based on this, you were then asked to determine the maximum number of login attempts before blocking. Also, if you have changed your service’s standard listening port, you have to define the custom port using the port directive. To test your settings, try to authenticate a user using SSH and provide a wrong password five times. On the sixth occasion, you should not be able to get back to the login prompt for one hour!

Protecting the sshd service from Brute Force Attacks is just the first step to get you started, and there is much more to learn with failban. To troubleshoot the service, please look at its log file at /var/log/fail2ban.log. To get some ideas about what can be done with it, open the following example failban config file: less /etc/fail2ban/jail.conf.

 

Monitoring CentOS important server infrastructure

In this process, we will use a small script that will monitor the available filesystem’s disk space periodically using cron, and if it exceeds a certain percentage threshold the script will send out a mail with a warning message.

To Start With: What Do You Need?

To complete this process, you will require a working installation of the CentOS 7 operating system with root privileges and a console-based text editor of your choice. You should have read the Scheduling tasks with cron process to have a basic understanding of the principles behind the cron system.

The Process

  1. To begin this process, log in as root and create the following file that will contain our monitoring script:
    vi /etc/cron.daily/monitor_disk_space.sh
  2. Now, put in the following content:
    #!/bin/bash
    EMAIL="root@localhost"
    THRESHOLD=70
    df -H | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print $5 " " $6 }'
    | while read output;
    do
      usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1 )
      partition=$(echo $output | awk '{ print $2 }' )
      if [ $usep -ge $THRESHOLD ]; then
      (echo "Subject: Alert: Free space low on `hostname -s`, $usep % used
    on $partition"; echo)|
      sendmail -t $EMAIL
      fi
    done
  3. Now, save the file and make it executable:
    chmod +x /etc/cron.daily/monitor_disk_space.sh

How it works…

We made this script executable and put it in the /etc/cron.daily directory, which is all we need to do to run this script automatically every day via the crond service.

This simple script showed us how easy it is to build monitoring scripts, and this can be a real alternative to installing and configuring big monitoring suites such as Nagios. You can use the shown script as a starting point to expand on, adding further resources that are important to monitor, such as CPU load, available RAM, and so on.

We used a script that executes the Linux command df, which is a tool to report file system disk space usage. From this command’s output, the script then parsed the USE% column (with the Unix tools awk and cut), which gives us the total disk percentage used. This number will then be compared to a threshold the user can set by editing the script and changing the environment variable, THRESHOLD. If the extracted percentage number is higher than our threshold, there will be an email sent to the email address defined with the environment variable, EMAIL (change appropriately if needed).

 

Introduction to Vim on CentOS

Here in this process, we will give you a very brief introduction to the text editor, Vim, which is used as the standard text editor everywhere. You can also use any other text editor you prefer, such as nano or emacs, instead.

To Start With: What Do You Need?

For implementing this process, you will require a working installation of the CentOS 7 operating system with root privileges.

The Process

We will start this process by installing the vim-enhanced package, as it contains a tutorial you can use to learn to work with Vim:

  1. To begin, log in as root and install the following package:
    yum install vim-enhanced
  2. Afterward, type the following command to start the Vim tutorial
    vimtutor
  3. This will open the Vim tutorial in the Vim editor. To navigate, press the up and down key to scroll up and down single-line wise. To exit the tutorial, press the Esc key, then type :q!, followed by the Return key to exit.
  4. You should now read through the file and go through the lessons to get a basic understanding of Vim, to learn how to edit your text documents.

How it works..

The tutorial shown should be seen as a starting point from which we should start learning the basics for working with one of the most powerful and effective text editors available for Linux. Vim has a very steep learning curve, but after dedicating about half an hour to the vimtutor guide, you should be able to do all the common text editing tasks without any problem, such as opening, editing, and saving text files.

 

Monitoring important remote system metrics

The Nagios plugin check_multi is a convenient tool to execute multiple checks within a single check command that generates an overall returned state and output from it. Here in this process, we will show you how to set it up and use it to quickly monitor a list of important system metrics on your clients.

To Start With: What Do You Need?

It is assumed that you’ve gone through this segment division process by process, therefore by now, you should have a Nagios server running and another client computer that you want to monitor, which can already be accessed via its NRPE service externally by our Nagios server. This client computer that you want to monitor needs an installation of the CentOS 7 operating system with root privileges and a console-based text editor of your choice installed on it, as well as a connection to the Internet in order to facilitate the download of additional packages. The client computer will have the IP address 192.168.1.8.

The Process

The check_multi Nagios plugin is available from Github, so we will begin this process to install the git program by downloading it:
  1. Log in as root on your client computer and install Git if not done already:
    yum install git
  2. Now, download and install the check_multi plugin by compiling it from the source:
    cd /tmp;git clone git://github.com/flackem/check_multi;cd
    /tmp/check_multi
    ./configure --with-nagios-name=nagios --with-nagios-user=nagios --withnagios-
    group=nagios --with-plugin-path=/usr/lib64/nagios/plugins --
    libexecdir=/usr/lib64/nagios/plugins/
    make all;make install;make install-config
  3. Next, we install another very useful plugin called check_mem, which is not available in the CentOS 7 Nagios plugin rpms:
    cd /tmp;git clone https://github.com/justintime/nagios-plugins.git
    cp /tmp/nagios-plugins/check_mem/check_mem.pl
    /usr/lib64/nagios/plugins/
  4. Next, let’s create a check_multi command file that will contain all your desired client checks that you want to combine in a single run; open the following file:
    vi /usr/local/nagios/etc/check_multi/check_multi.cmd
  5. Put in the following content:
    command[ sys_load::check_load ] = check_load -w 5,4,3 -c 10,8,6
    command[ sys_mem::check_mem ] = check_mem.pl -w 10 -c 5 -f -C
    command[ sys_users::check_users ] = check_users -w 5 -c 10
    command[ sys_disks::check_disk ] = check_disk -w 5% -c 2% -X nfs
    command[ sys_procs::check_procs ] = check_procs
  6. Next, test out the command file that we just created in the last step using the following commandline:
    /usr/lib64/nagios/plugins/check_multi -f
    /usr/local/nagios/etc/check_multi/check_multi.cmd
  7. If everything is correct, it should print out the results of your five plugin checks and an overall result, for example, OK -5 plugins checked. Next, we will install this new command in the NRPE service on our client so that the Nagios server is able to execute it remotely by calling its name. Open the NRPE configuration file:
    vi /etc/nagios/nrpe.cfg
  8. Add the following line to the end of the file right below the last # command line to expose a new command called check_multicmd to our Nagios server:
    command[check_multicmd]=/usr/lib64/nagios/plugins/check_multi -f
    /usr/local/nagios/etc/check_multi/check_multi.cmd
  9. Finally, let’s reload NRPE:
    systemctl restart nrpe
  10. Now, let’s check whether we can execute our new check_multicmd command that we defined in the last step from our Nagios server. Log in as root and type the following command (change the IP address of your client, 192.168.1.8, appropriately):
    /usr/lib64/nagios/plugins/check_nrpe -H 192.168.1.8 -c "check_multicmd"
  11. If the output is the same as running it locally on the client itself (take a look at the former step), we can successfully execute remote NRPE commands on our client through our server, so let’s define the command on our Nagios server system for real so that we can start using it within the Nagios system. Open the following file:
    vi /etc/nagios/objects/commands.cfg
  12. Put in the following content at the end of the file to define a new command called check_nrpe_multi, which we can use in any service definition:
    define command {
    command_name check_nrpe_multi
    command_line $USER1$/check_nrpe -H $HOSTADDRESS$ -c "check_multicmd"
    }
  13. Next, we will define a new server definition for the client that we want to monitor on our Nagios server (give the config file an appropriate name, for example, its domain name or IP address):
    vi /etc/nagios/servers/192.168.1.8.cfg
  14. Put in the following content, which will define a new host with its service, using our new Nagios command that we just created:
    define host {
             use                      linux-server
             host_name          host1
             address               192.168.1.22
             contact_groups     unix-admins
    }
    define service {
                    use generic-service
                    host_name host1
                    check_command check_nrpe_multi
                    normal_check_interval 15
                    service_description check_nrpe_multi service
    }
  15. Finally, we need to configure all persons who should get notification e-mails for our new service in case of errors. Open the following file:
    vi /etc/nagios/objects/contacts.cfg
  16. Put in the following content at the end of the file:
    define contactgroup{
                  contactgroup_name           unix-admins
                   alias                      Unix Administrators
    }
    define contact {
               contact_name                       pelz
                use                               generic-contact
                alias                             Oliver Pelz
                contactgroups                     unix-admins
                email                             oliverpelz@mymailhost.com
    }
  17. Now, restart the Nagios service:
    systemctl restart nagios

How Does It Work?

We started this process by installing the check_multi and check_mem plugins from their author’s Github repositories; they are plain command-line tools. Nagios performs checks by running such external commands, and it uses the return code along with output from the command as information on whether the check was successful or not. Nagios has a very flexible architecture that can be easily extended using plugins, add-ons, and extensions. A central place to search for all kinds of extensions is at https://exchange.nagios.org/ . Next, we added a new command file for check_multi, where we put five different system check_ commands in. These checks act as a starting point for customizing your monitoring needs and will check system load, memory consumption, system users, free space, and processes. All available check_ commands can be found at /usr/lib64/nagios/plugins/check_*. As you can see in our command file, the parameters of those check_ commands can be very different, and explaining them all is out of the scope of this process. Most of them are used to set threshold values to reach a certain state, for example, the CRITICAL state. To get more information about a specific command, use the --help parameter with the command. For example, to find out what all the parameters in the check_load -w 5,4,3 -c 10,8,6 command are doing, use run /usr/lib64/nagios/plugins/check_load --help. You can easily add any number of new check commands to our command file from existing plugins, or you can download and install any new commands, if you like. There are also a number of command file examples shipped with the check_multi plugin, which are very useful for learning, so please have a look at the directory: /usr/local/nagios/etc/check_multi/*.cmd.
 
Afterwards, we checked the correctness of our new command file that we just created by dry-running it as an -f parameter from the check_multi command locally on the client. In its output, you will find all the single outputs as if you would have run these five commands individually. If one single check fails, the complete check_multi will do. Next, we defined a new NRPE command in the NRPE config file called check_multicmd that can then be executed from the Nagios server, which we tested in the next step from our Nagios server. For a test to be successful, we expect the same results as we got when calling the command from the client itself. Afterwards, we defined this command in our commands.cfg on the Nagios server so that we can reuse it as much as we like in any service definition by referencing the command’s name, check_nrpe_multi. Next, we created a new server file named as the IP address (you can name it anything you like as long it has the .cfg extension in the directory) of the client we want to monitor: 192.168.1.8.cfg. It contains exactly one host definition and one or multiple service definitions, which are linked by the value of host_name of the host with the host_name value in your service definitions.
 
In the host definition, we defined a contact_groups contact that links to the contacts.cfg file’s contact group and contact entry. These will be used to send notification e-mails if the checked service has any errors. The most important value in the service definition is the check_command check_nrpe_multi line, which executes the command that we created before as our one and only check. Also, the normal_check_interval is important as it defines how often the service will be checked under normal conditions. Here, it gets checked every 15 minutes. You can add as many service definitions to a host as you like.
 
Now, go to your Nagios web frontend to inspect your new host and service. Here, go to the Hosts tab, where you will see the new host, host1, that you defined in this process, and it should give you information about its status. If you click on the Services tab, you will see the check_nrpe_multi service. It should show the Status as Pending, OK, or CRITICAL, depending on the success of the single checks. If you click on its check_nrpe_multi link, you will see details about the checks.
 
 We could only show you the very basics of Nagios, and there is always more to learn, so please read the official Nagios Core documentation at https://www.nagios.org , or check out the book Learning Nagios 4, Packt Publishing, by Wojciech Kocjan.

Enabling CentOS system users and building publishing directories

In this process, we will learn how Apache provides you with the option to allow your system users to host web pages within their home directories. This approach has been used by ISPs since the outset of web hosting and in many respects, it continues to flourish due to its ability to avoid the more complex method of virtual hosting. In the previous process, you were shown how to install the Apache web server, and with the desire to provide hosting facilities for system users, it is the purpose of this process to show you how this can be achieved in CentOS 7.

To Start With: What Do You Need?

To complete this process, you will require a working installation of the CentOS 7 operating system with root privileges and a console-based text editor of your choice. It is expected that your server will be using a static IP address that supports a hostname or domain name and that the Apache web server is already installed and currently running. Also, at least one system user account should be available on the server.

The Process

To provide the functionality offered by this process, no additional packages are required but we will need to make some modifications to the Apache configuration file.

  1. To begin, log in as root and open the Apache userdir configuration file in your favorite text editor by typing the following command after you have created a backup copy of it first:
    cp /etc/httpd/conf.d/userdir.conf /etc/httpd/conf.d/userdir.conf.BAK vi /etc/httpd/conf.d/userdir.conf
  2. In the file, locate the directive that reads as UserDir disabled. Change it to the following:
    UserDir public_html
  3. Now scroll down to the section and replace the existing block with the one here:

                AllowOverride All
               Options Indexes FollowSymLinks
               Require all granted
  4. Save and exit the file. Now log in as any system user to work with your publishing web directory (su -), and then create a web publishing web folder in your home directory and a new home page for your user:
    mkdir ~/public_html && vi ~/public_html/index.html
  5. Now add the required HTML. You can use the following code as a starting point but it is expected that you will modify it to suit your own needs:


    Welcome to my web folder's home page

    Welcome to my personal home page


  6. Now modify the permissions of the Linux system user’s home folders by typing:
    chmod 711 /home/
  7. Set the read/write permissions for public_html 755 so Apache can execute it later:
    chmod 755 ~/public_html -R
  8. Now log in as root again using su -root to configure SELinux appropriately for the use of http home directories:
    setsebool -P httpd_enable_homedirs true
  9. As root, change the SELinux security context for your user’s web public directory (this needs policycoreutils-python package to be installed) with the username :
    semanage fcontext -a -t httpd_user_content_t /home//public_html restorecon -Rv /home//public_html
  10. To complete this process, simply reload the httpd service configuration:
    apachectl configtest && systemctl reload httpd
  11.  You can now test your setup by browsing to (substitute appropriately): http:///~ in any browser.

How Does It Work?

In this process, we learned how easy it is to host your own peers by enabling user directories on the Apache web server.

So what did we learn from this experience?

We began the process by making a few minor configuration changes to Apache’s userdir.conf in order to set up the user directory support. We activated the user directories by adjusting the UserDir directive from disabled to pointing to the name of the HTML web directory within each user’s home directory, which will contain all our user’s web content, and call this public_html (you can change this directory name to anything you like but public_html is the de facto standard for naming it). Then we proceeded to modify the tag. This directive applies all its enclosed options to the parts of the filesystem defined in the beginning tag /home/*/public_html. In our example, the following options are enabled for this directory: Indexes are used whenever a directory does not have index.html. This will show the file and folder content of the directory as HTML. As we will see in the process Securing Apache, this should be avoided for your web root whereas, for serving user directories, this can be a good choice if you just want to make your home folder accessible to your peers so they can quickly share some files (if you have any security concerns, remove this option). The FollowSymLinks option allows symbolic links (man ln) from this public_html directory to any other directory or file in the filesystem. Again, avoid this in your web root folder but for home directories, it can be useful if you need to make files or folders accessible within the public_html folder without the need to copy them into it (user directories often have disk quotas). Next we configured access control to the public_html folder. We did so by setting Require all granted, which tells Apache that in this public_html folder anyone from everywhere can access the contents through the HTTP protocol. If you want to restrict access to your public_html folder then you can replace all granted with different options. To allow access based on a hostname use, for example Require host example.com. With the ip parameter we can restrict the public_html folder to an internally available network only, for example Require ip 192.168.1.0/24. This is particularly useful if your web server has multiple network interfaces and one IP address is used for connecting to the public Internet and another one for your internal private network. You can add multiple Require lines within a Directory block. Remember to always set at least Require local which allows local access.

Having saved our work, we then began to make various changes to the home directories. First we created the actual public_html folder within our user’s home directory, which will be the actual personal web publishing folder later. Next, we changed its permissions to 755 which means that our user can do everything in the folder but all the other users and groups can only read and execute its content (and change into this folder). This type of permission is needed because all the files in the public_html folder will be accessed by a user named apache with the group apache if someone requests its content via the Apache web server later. If no read or execute permissions are set for the other users flag (man chmod), we will get an Access denied message in our browser. This will also be the case if we do not change the permissions for the parent /home/ directory in advance because parent directory permissions can affect its child subfolder permissions. A normal user home directory in CentOS Linux has the permissions 700 which means that the home directory’s owner can do anything but everyone else is completely locked out of the home folder and its content.

As written before, the Apache user needs access to the subfolder public_html so we have to change the permissions to 711 for the home folder so that everyone else can at least change into the directory (and then access the subfolder public_html as well since this is set to be read/write accessible). Next, we set the security context of our new web folder for SELinux. On systems running SELinux, it’s mandatory to set all the Apache web publishing folders to the httpd_user_content_t SELinux label (along with their contents) in order to make them available to Apache. Also, we made sure to set the correct SELinux Boolean to enable Apache home directories (which is enabled by default): httpd_enable_homedirs is true, read Working with SELinux to learn more about SELinux.

You should be aware that the previous process of managing the home directories should be repeated for each user. You will not have to restart Apache every time you enable a new system user but, having completed these steps for the first time, it will be simply a matter of reloading the configuration of the httpd service to reflect the initial changes made to the configuration file. From this point on, your local system users can now publish web pages using a unique URL based on their username.

 

Installing and configuring a caching-only nameserver in CentOS

Every network communication between computers can only be made through the use of unique IP addresses to identify the exact endpoints of the communication. For the human brain, numbers are always harder to remember and work with than assigning names to things. Therefore, IT pioneers started in the early 70s to invent systems for translating names to physical network addresses using files and later simple databases. In modern computer networks and on the Internet, the relationship between the name of a computer and an IP address is defined in the Domain Name System (DNS) database. It is a worldwide distributed system and provides the domain name to IP address resolution and also the reverse, that is IP address to domain name resolution. DNS is a big subject, and it is the purpose of this process to provide the perfect starting point by showing you how to install and setup your own caching-only and forwarding nameserver. Here we will use Unbound, which is a highly secure and fast recursive and caching DNS server solution, and therefore our preferred choice. But you need to remember that Unbound cannot be used as a fully authoritative DNS server (which means that it provides its own domain name resolution records) we will use the popular BIND server for this in a later process. A caching-only DNS server will serve to forward all the name resolution queries to a remote DNS server. Such a system has the intention of speeding up general access to the Internet by caching the results of any domain resolution request made. When a caching DNS server tracks down the answer to a client’s query, it returns the answer to the client. However, it also stores the answer in its cache for a specific period of time. The cache can then be used as a source for subsequent requests in order to speed up the total round-trip time.

To Start With: What Do You Need?

To complete this process, you will require a working installation of the CentOS 7 operating system with root privileges, a static IP address, and a console-based text editor of your choice. An Internet connection will be required to download additional packages. In this example, our DNS server runs in a private network with the network address 192.168.1.0/24.

The Process

In this process, we will first configure a caching-only and then a forwarding only DNS server.

Configuring a caching-only Unbound DNS server

In this section, we will consider the role of Unbound as a caching-only nameserver, handling recursive DNS requests to the other remote DNS servers and caching the query for a certain time period to improve the response time when the server is asked for the same name resolution again:

  1. To begin, log in as root and install the required packages by typing:
    yum install unbound bind-utils
  2. Now make a copy of the unbound configuration file so we can revert our changes later, and then open it in your favorite text editor:
    cp /etc/unbound/unbound.conf /etc/unbound/unbound.conf.BAK
    vi /etc/unbound/unbound.conf
  3. Scroll down to find the following line: # interface: 0.0.0.0 Remove the # sign to uncomment it (activate it), so it reads as follows:
    interface: 0.0.0.0
  4. Next, scroll down to find the line # access-control: 127.0.0.0/8 allow. Uncomment the line to activate it and change the network address to fit your needs:
    access-control: 192.168.1.0/24 allow
  5. Save and close the file, and then create an RSA keypair with certificates for secure DNSSEC support before you check the correctness of the changed configuration file:
    unbound-control-setup && unbound-checkconf
  6. Next, open the DNS service in your firewalld configuration on your server because we want to be able to use our new DNS service from other clients in the network for querying as well:
    firewall-cmd --permanent --add-service dns && firewall-cmd --reload
  7. Now ensure the service will be available at boot and start it afterwards:
    systemctl enable unbound && systemctl start unbound
  8. To test if we can reach our Unbound DNS server and make queries, execute the following command from the same server running our Unbound DNS service locally, which should give back the IP address of www.packtpub.com :
    nslookup www.packtpub.com 127.0.0.1
  9. For a more detailed view of the request you can also run locally on the DNS server:
    unbound-host -d www.packtpub.com
  10. From any other client in the network (needs bind-utils installed), you can query any public domain name using our new DNS server as well. For example, if our DNS server has the IP 192.168.1.7:
    nslookup www.packtpub.com 192.168.1.7
  11. Finally, let us use our new nameserver on the server itself. To do this, open the following file with your favorite text editor after you have made a backup copy:
    cp /etc/resolv.conf /etc/resolv.conf.BAK; vi /etc/resolv.conf
  12. Remove all the current nameserver references and replace them with the following:
    nameserver 127.0.0.1

    Note
    If you have set some DNS server information in your network-scripts interface (for example, when configuring a static IP address), you will want to review the /etc/sysconfig/network-scripts/ifcfg-XXX file and modify the current DNS reference to read as DNS1=127.0.0.1 as well.

Configuring a forwarding only DNS server

Now after we have successfully configured our first caching BIND DNS server, here we will show you how to transform it into a forwarding DNS server which will reduce the total bandwidth for resolving hostnames in comparison to the caching-only solution:

  1. Open BIND’s main configuration file again:
    vi /etc/unbound/unbound.conf
  2. Add the following lines to the end of the file:
    forward-zone: name: "." forward-addr: 8.8.8.8
  3. Next, check the correctness of your new configuration file and restart the service:
    unbound-checkconf && systemctl restart unbound
  4. Finally, test your new forwarding DNS server using the tests from the preceding caching DNS server section.

How Does It Work?

In this process, we have installed a caching-only Unbound DNS server with the basic aim of improving the responsiveness of our overall network by caching the answers to any name-based queries. Using such a process will shorten the waiting time on any subsequent visit to the same location. It is a feature that is particularly useful in saving bandwidth if you happen to be managing a large, busy, or slow network. It does not have its own domain name resolution feature but uses its default root domain’s DNS servers in order to perform this task (to learn more about the root domain, see later). Also, as we have seen, you can easily transform your caching nameserver into a pure forwarding system as well. While a caching DNS server makes recursive requests to several associated DNS servers and constructs the complete name resolution result from those multiple requests, a forwarding DNS delegates the complete recursive DNS search to another resolving DNS server which executes the complete search instead. This saves even more bandwidth for our DNS server because only single network requests to communicate with the remote resolving server are made instead of multiple when using the caching-only DNS service.

So what did we learn from this experience?

We started this process by installing the necessary packages. This included the main DNS server program called Unbound and a reference to bind-utils, a small package that enables you to run many different DNS related network tasks, such as dig, nslookup, and host. The next step was to begin making the necessary configuration changes by editing Unbound’s main configuration after we made a simple backup of the original file. Since after installation the default DNS server is completely restricted to doing everything locally only, our main purpose was to adjust the server to make connections from the outside possible. We began this process by allowing the DNS server to listen to all the available network interfaces using the interface directive and afterwards defined who on the network was allowed to make requests to our DNS server by setting allow-query to our local network. This means we allowed anyone in our subnetwork to make DNS resolution requests to our server.

At this point we created the RSA keypair with the unbound-control-setup tool, which is needed for the unbound-checkconf command to work. The generated keys and certificate are important if we want to use Unbound’s DNS Security Extensions (DNSSEC) features which help protect DNS data by providing authentication of origin using digital signatures (configuring DNSSEC is outside the scope of this division. To learn more, consult the Unbound configuration manual: man unbound.conf). Afterwards, we used the unbound-checkconf command, which was necessary to confirm that Unbound’s configuration file was syntactically correct. If the output of the command is empty, there are no errors in the file. We then proceeded by adding the predefined dns firewalld service to our default firewall, thus allowing the other computer systems in our local network to access the DNS server using port 53. Finally, we activated Unbound at boot time and started the service.

Of course, to complete this process we then tested if our new DNS server worked as expected in resolving domain names to IP addresses. We ran a simple nslookup query locally on the server and also from the other computers in the same network to see if our new DNS service was reachable from the outside. When using nslookup without any additional parameters, the program will use the default DNS server resolver known to the system (on CentOS 7 this is defined in /etc/resolv.conf) to resolve our hostnames, so we added another parameter addressing our alternative DNS server we want to query instead (127.0.0.1). For successful testing, the output must contain the resolved IP address of the www.packtpub.com server. On the DNS server, you could also use the unbound-host -d command to get a more technical view of the DNS query within the Unbound service.

After we successfully finished these tests, we updated the current nameserver resolver information on our DNS server with our new DNS service running on localhost.

There's more…

Now we want to see how BIND will perform for caching DNS information. To do this, on your DNS server simply select a target website you have not visited before and use the dig command. For example:
dig www.wikipedia.org

Having run this test, you may see a query time that results in something like the following:
;; Query time: 223 msec

Now repeat this exercise by retesting the same URL. Depending on your networking environment, this may produce the following result:
;; Query time: 0 msec

Now do it again for another website. On every repeat of the preceding command, you should not only see a reduced query time but also experience a faster response time in delivering the output. This same result will be evident in the browser refresh rate, and as a result, we can say that this simple exercise has not only introduced you to Unbound but it will ultimately serve to improve the speed of your local network when surfing the World Wide Web.

 

Locking down remote access in CentOS and hardening SSH

In this process, we will learn how to provide additional security measures in order to harden the secure shell environment. The Secure Shell (SSH) is the basic toolkit that provides remote access to your server. The actual distance to the remote machine is negligible, but the shell environment enables you to perform maintenance, upgrades, the installation of packages and file transfers; you can also facilitate whatever action you need to carry out as the administrator in a secure environment. It is an important tool; as the gateway to your system, it is the purpose of this process to show you how to perform a few rudimentary configuration changes that will serve to protect your server from unwanted guests.

To Start With: What Do You Need?

To complete this process, you will require a minimal installation of the CentOS 7 operating system with root privileges, a console-based text editor of your choice, and a connection to the Internet in order to download additional packages. It is assumed that your server already maintains at least one non-root-based administration account that can use the new features provided by this process.

The Process

The role of SSH will be vital if you are forced to administer your server from a remote location, and for this reason, it is essential that a few basic steps are provided to keep it safe:

  1. To begin, log in as root and create a backup of the original configuration file by typing the following command:
    cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
  2. Now, open the main sshd configuration file by typing the following:
    vi /etc/ssh/sshd_config
  3. We shall begin by adjusting the time allowed to complete the login process, so scroll down and find the line that reads:
    #LoginGraceTime 2m
  4. Uncomment this line and change its value to something more appropriate such as:
    LoginGraceTime 30
  5. Now, scroll down a couple of more lines and find the line that reads as follows:
    #PermitRootLogin yes
  6. Change this to the following:
    PermitRootLogin no
  7. Find the following line:
    X11Forwarding yes
  8. And change it to the following:
    X11Forwarding no
  9. Save and close the file before restarting the SSH service, as shown here:
    systemctl restart sshd
  10. At this stage, you may want to consider creating a new SSH session using the new settings before exiting the current session. This is to ensure that everything is working correctly and to avoid locking yourself out of the server accidentally. If you have difficulty starting a new SSH session, then simply return to the original session window and make the necessary adjustments (followed by a restart of the SSH service). However, if no difficulties have been encountered and you are on successful secondary login, you may close the original shell environment by typing exit.

    Note
    Remember, having followed this process you should now find that root access to the shell is denied and you must log in using a standard user account. Any further work requiring root privilege will require the su or sudo command, depending on your preferences. 

How Does It Work?

SSH is a vital service that enables you to access your server remotely. A server administrator cannot work without it. In this process, you were shown how to make that service a little more secure.

So, what did we learn from this experience?

We began the process by creating a backup copy of our original main sshd configuration file. The next step was to open and edit it. The configuration file for SSH maintains a long list of settings that is ideal for most internal needs, but for a server in a production environment, it is often advised that the default SSH configuration file will need changing to suit your particular needs. In this respect, the first step was to make a recommended change to the login grace time, LoginGraceTime 30. Instead of the default two minutes, the preceding value will allow only up to 30 seconds. This is the period of time where a user may be connected but will have not begun the authentication process; the lower the number, the fewer unauthenticated connections are kept open. Following this, we then removed the ability of a remote user to log in as the root user by using the PermitRootLogin no directive. In most cases, this is a must and a remote server should not allow a direct root login unless the server is in a controlled environment. The main reason behind this is to reduce the risk of getting hacked. The first thing every SSH hacker tries to crack is the password for the user root. If you disallow root login, an attacker needs to guess the user name as well, which is far more complex. The next setting simply disabled X11Forwarding. In situations like these, it is often a good idea to apply the phrase “if you do not use it, disable it”. To complete the process, you are required to restart the SSH server in order to allow the changes to take immediate effect and start a new SSH session with the intention of making sure that the modifications did indeed work as expected. No system is ever safe, but having done this you can now relax, safe in the knowledge of having made the SSH server a little bit safer.

There's more…

There are a few more topics to cover to make your SSH server even more secure: we should change the SSH port number and show you how to limit SSH access to specific system users.

Changing the SSH port number of your CentOS server

Port 22 is the default port used by all SSH servers, and changing the port number used can go a small way to increase the overall security of your server. Again, open the main SSH daemon configuration file, sshd_config. Now, scroll down and locate the following line that reads:

#Port 22

Remove the leading # character (uncomment) and change the port number to another value by replacing XXXX with an appropriate port number:

Port XXXX

You must ensure that the new port number is not already in use, and when complete, save the file and close it. It is important to remember that any changes made here are reflected in your firewall configuration. So, we need to open the new port in firewalld as well. Set the new port via the environment variable NEWPORT (replace XXXX with your new SSH port), then execute the following sed command to change the SSH firewalld service file and reload the firewalld daemon afterwards (for details, read the firewall process)
NEWPORT=XXXX
sed "s/port=\"22\"/port=\"$NEWPORT\"/g" /usr/lib/firewalld/services/ssh.xml > /etc/firewalld/services/ssh.xml firewall-cmd --reload

Also, we have to tell SELinux (see Working with SELinux to learn more about it) about the port change because it is restricted to port 22 by default. Make sure that the SELinux tools have been installed, then create a security label for our custom port, replacing XXXX with your changed port number:
yum install -y policycoreutils-python semanage port -a -t ssh_port_t -p tcp XXXX

Finally restart the sshd service to apply our port change.

Limiting SSH access by user or group in CentOS

By default, all valid users on the system are allowed to log in and enjoy the benefit of SSH. However, a more secure policy is to only allow a predetermined list of users or groups to log in. When henry, james, and helen represent valid SSH users on the system, in the sshd_config add this line to read as follows:

AllowUsers henry james helen

Alternatively, you can use the following method to enable any user that is a member of a valid administration group to log in. When admin represents a valid SSH group on the system, add this line to read as follows:

AllowGroups admin

When you have finished, save and close the file before restarting the SSH service.

 

CentOS backups and taking snapshots

In this process, we will show you how to do data backups, on a regular basis, that will take snapshots of some of your system’s directory using the crond daemon. This will run the rsync program at regular intervals to implement a fully automated backup solution.

To Start With: What Do You Need?

To complete this process, you will require a working installation of the CentOS 7 operating system with root privileges and a console-based text editor of your choice. It is also advantageous if you have read the Synchronizing files and doing more with rsync and Scheduling tasks with cron process to get a deeper understanding of used commands.

The Process

It’s important to install the rsync program on your server before proceeding with this process.

  1. First, log in as root and create a directory where our backups will land:
    mkdir /backups
  2. Now, we will create the following shell script file and open it for editing:
    mkdir ~/bin;vi ~/bin/mybackup.sh
  3. Put in the following content, replacing /backups in the environment variable DEST and SOURCE with the one you would like to backup as well as the recipient’s EMAIL:
    #!/bin/bash
    SBJT="cron backup report for `hostname -s` from $(date +%Y%m%d:%T)"
    FROM=root@domain
    EMAIL=johndoe@internet.com
    SOURCE=/root
    DEST=/backups
    LFPATH=/tmp
    LF=$LFPATH/$(date +%Y%m%d_%T)_logfile.log
    rsync --delete --log-file=$LF -avzq $SOURCE $DEST
    (echo "$SBJT"; echo; cat $LF ) | sendmail -f $FROM -t $EMAIL
  4. Make the script executable:
    chmod a+x /root/bin/mybackup.sh
  5. Now, open crontab using:
    crontab -e
  6. Next, create the following entry by adding the following line to the end of the document, then save and close it:
    30 20 * * * /root/bin/mybackup.sh

How it works…

In this process, we have created a fully automatic backup solution for a single system directory, which will create a snapshot of the files at a certain time point. At the time the backup process is complete you will receive an e-mail informing you that a backup has been made with a brief review of the actions taken.

So what did we learn from this experience?

We started this process by creating a directory where our backup will be placed. Next we created the actual script and filled it with some commands. Line 1 defines the file as a bash script, lines 2-6 are variables you can modify and customize to fit your own needs. lines 7-8 create a path and name for the log file based on the date, and line 9 calls rsync which will synchronize all our source files to the target directory /backups. It uses a special --log-file parameter which writes all output to the given file. The final line (10) sends the content of this log file to an email address.

Remember, you should customize the values as required (that is, change the e-mail address used, select a source directory, and choose a destination directory, and so on.). Before it can be used and executed by cron, we made it executable. Finally, we added this script as a cron job to run on a daily schedule at 20:30 hours. However, as this may be some hours away, if you would like to test your script right now, you can execute it on the command line using the following:
/root/bin/mybackup.sh

In conclusion, it will go without saying that a backup should be located on an external drive or on a separate partition, but having completed this introduction I think you will agree that rsync is ideally positioned in such a way that it will enable any server administrator to develop their own policy with regard to maintaining an effective backup of important data.