Skip to main content

CentOS

Installing, configuring, and testing PHP on CentOS

Hypertext Preprocessor (PHP) remains one of the most popular server-side scripting languages designed for web development. It already supports some nice features, such as connecting to relational databases like MariaDB out-of-the-box which can be used to implement modern web applications very fast. While a current trend can be seen for larger enterprises to move away from PHP in favor of some newer technologies such as Node.js (server-side JavaScript), it is still the superior scripting language on the consumer market. Every hosting company in the world provides some kind of LAMP stack (Linux, Apache, MySQL, PHP) to run the PHP code. Also, a lot of very popular web applications are written in PHP, such as WordPress, Joomla, and Drupal, so it’s fair enough to say that PHP represents a must-have feature for almost any Apache web server. Here in this process, we will show you how to get started with installing and running PHP in your Apache web server with the module mod_php.

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 and an Internet connection. It is expected that your server will be using a static IP address and Apache is installed and currently running, and that your server supports one or more domains or subdomains.

The Process

We will begin this process by installing the PHP Hypertext Processor together with the Apache mod_php module, both not installed by default on CentOS 7 minimal.

  1. To begin, log in as root and type the following command:
    yum install mod_php
  2. Now let’s open the standard PHP configuration file after we have made a backup of the original file first:
    cp /etc/php.ini /etc/php.ini.bak && vi /etc/php.ini
  3. Find the line ; date.timezone = and replace it with your own timezone. A list of all the available PHP time zones can be found at http://php.net/manual/en/timezones.php. For example (be sure to remove the leading ; as this is disabling the interpretation of a command; this is called commenting out) to set the timezone to the city Berlin in Europe use:
    date.timezone = "Europe/Berlin"
  4. To make sure the new module and settings have been properly loaded, restart the Apache web server:
    systemctl restart httpd
  5. To be consistent with the CGI examples from the former recipe, here we will create our first dynamic PHP script which will print out the current local server time in the script vi /var/www/html/php-test.php, and run the popular PHP function phpinfo() that we can use to print out important PHP information:
    Server time via Mod PHP

    Time

    The time is

    phpinfo(); ?>

Populating the domain on CentOS

In this process, we will show you how you can quickly add new local domain record entries to your authoritative BIND server which are currently unknown to your nameserver.

To Start With: What Do You Need?

To complete this process, you will require a working installation of the CentOS 7 operating system and a console-based text editor of your choice. It is expected that Unbound and BIND have both been installed and are already running and that you have read and applied the zone process and have prepared the required forward and reverse zone files for resolving hostnames of your private network.

The Process

If you want to add new domain names to the IP address mappings to your DNS server, for example for new or unknown hosts in your local network, you have two alternatives. Since we have already created zone files for our local network, we can simply add new A (and/or CNAME) and corresponding PTR entries for every new subdomain within our base domain name into our forward and reverse zone file configuration using our text editor of choice. Alternatively, we can use the nsupdate command-line tool to add those records interactively without the need to restart the DNS server. In this section, we will show you how to prepare and work with the nsupdate tool. In our example, we will add a new subdomain client4.centos7.home for a computer with the IP address 192.168.1.14 to our DNS server’s zone:

  1. Log in as root on the server running your BIND service. Now first we need to activate named to be allowed to write into its zone files by SELinux:
    setsebool -P named_write_master_zones 1
  2. Next, we need to fix some permission problems with the named configuration directory, otherwise nsupdate cannot update our zone files later:
    chown :named /var/named -R; chmod 775 /var/named -R
  3. Since our BIND server is running on port 8053, type the following command to start the interactive nsupdate session locally:
    nsupdate -p 8053 -d -l
  4. At the prompt (>), first connect to the local DNS server by typing the following (press Return to finish commands):
         local 127.0.0.1
  5. To add a new forward domain to IP mapping to your DNS server, type the following:
    update add client4.centos7.home. 115200 A 192.168.1.14
    send
  6. Now add the reverse relationship using the following command:
    update add 14.1.168.192.in-addr.arpa. 115200 PTR client4.centos7.home. send
    If both the update commands’ outputs contained the message NOERROR, press Ctrl+c key to exit the interactive nsupdate session.
  7. Finally, check if both the domain and IP resolution for the new zone entry work (this should also work remotely through the Unbound server):
    dig -p 8053 @127.0.0.1 client4.centos7.home.
    nslookup -port=8053 192.168.1.14 127.0.0.1

How Does It Work?

In this fairly easy process, we showed you how easily you can add new domain name resolution records with the nsupdate tool dynamically at runtime without needing to restart your BIND DNS server.

So what did we learn from this experience?

In this process, we introduced you to the nsupdate command-line tool which is a utility for making changes to a running BIND DNS database without the need to edit the zone files or restart the server. If you have already configured the zone files in your DNS server, then this is the preferred way to make changes to the DNS server. It has several options, for example, you can connect to the remote DNS servers but for simplicity and for security reasons we will only use and allow the most simple form and only connect nsupdate to our BIND server locally (to connect to a BIND server remotely using nsupdate, you need to do more configuration, such as generate secure key-pairs, open the firewall, and so on).

After allowing named to write into its own zone files, which otherwise is prohibited by SELinux, and fixing some permission problems on the default named configuration directory, we started the nsupdate program with -l for local connection, and -p 8053 to connect to our BIND DNS server on port 8053. -d gives us debug output which can be useful for resolving any problems. We then got prompted by an interactive shell where we could run BIND specific update commands. First we set local 127.0.0.1 which connects to our local server, than we used the commands update add to add a new forward A record to our running DNS server. The syntax is similar to defining records in the zone files. Here we used the line update add to add a new A record with a TTL of three days (115200 seconds) for the domain client4.centos7.home to resolve to the IP address 192.168.1.14. The next line was used to config some reverse resolution rules for our new domain and which adds the domain name as a PTR entry into our reverse zone. Here it is important to note that you need to define the domain part of the reverse update add rule the following way: ..in-addr.arpa. To finally execute our commands and make them permanent in our DNS server’s database, without the need to restart the server, we used the send command for both the reverse and forward commands separately since they target different zones. Finally, we tested if the new entries into the DNS server’s zone files were working by querying the BIND server.

 

Forging the CentOS firewall rules by example

In this process, we want to show you how to create your own firewalld service definitions or how to change existing ones, which any CentOS 7 system administrator should know if the predefined service files don’t fit your system’s need.

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 and a console-based text editor of your choice. We will be changing the SSH service’s port number in firewalld, so make sure that you have configured the new port as shown in the process Locking down remote access and hardening SSH. Here, in our example, we have changed the port to 2223. Also, we will create a new firewalld service for a small Python-based web server that we will use to demonstrate the integration of new system service’s into firewalld. It’s advantageous to grasp the basics of firewalld by working through the Working with a firewall process before starting here.

The Process

Here in this process, we will show you how to change and how to create new firewalld service definitions. In this process, it is considered that we are in the default public zone.

To change an existing firewalld service (ssh)

  1. First, log in as root and copy the ssh service to the right place to edit it:
    cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services
  2. Next, open the ssh service definition file:
    vi /etc/firewalld/services/ssh.xml
  3. Change the port from 22 to 2223, then save the file and close it:

  4. Finally, reload the firewall:
    firewall-cmd --reload

To create your own new service
Perform the following steps to create your own new service:

  1. Open a new file:
    vi /etc/firewalld/services/python-webserver.xml
  2. Put in the following service definition:


       Python Webserver
       For pythons webservers
       
  3. Save and close the file, and then finally reload the firewall:
    firewall-cmd --reload
  4. Now, add this new service to our default zone:
    firewall-cmd --add-service=python-webserver
  5. Afterwards, run the following command to start a simple Python web server in the foreground on port 8000 (press the key combination Ctrl + C to stop it):
    python -m SimpleHTTPServer 8000
  6. Congratulations! Your new web server sitting at port 8000 can now be reached from other computers in your network:
    http://:8000/

How Does It Work?

Here in this process, we have shown how easy it is to customize or define new firewalld services if the predefined needs to be changed, or for new system services that are not defined at all. Service definition files are simple XML files where you define rules for a given system service or program. There are two distinct directories where our firewalld service files live: /usr/lib/firewalld/services for all predefined services available from the system installation, and /etc/firewalld/services for all custom and user-created services.

So, what did we learn from this experience?

We started this process by making a working copy of the SSH firewalld service file in the right place at /etc/firewalld/services. We could just copy the original file because all files in this directory will overload the default configuration files from /usr/lib/firewalld/services. In the next step, we then modified it by opening it and changing the default port from 22 to 2223. We have to do this every time we change a system’s service standard listening port to make the firewall aware that it should allow network traffic to flow through the changed port. As you can see when opening this file, service files are simple XML text files with some mandatory and some optional tags and attributes. They contain a list of one or more ports and protocols that defines exactly what firewalld should enable if the service is connected to a zone. There can be another important setting in the XML file: helper modules. For example, if you open the SAMBA service file at /usr/lib/firewalld/services/samba.xml, you will see the tag, . These are special kernel netfilter helper modules that can be dynamically loaded into the underlying kernel-based firewall, and which are needed for some system services, such as Samba or FTP, which create dynamic connections on temporary TCP or UDP ports instead of using static ports. After reloading the firewall configuration, we should now be able to test the connection from another computer in our network using the altered port.

In the second part of this process, we created a brand-new service file for a new system service, which is a simple Python web server listening on port 8000 displaying a simple directory content listing. Therefore, we created a simple XML service file for the Python web server including the right port 8000, restarted the firewall, and afterwards added this new service to our default public zone so that we can actually open connections through this service. You should now be able to browse to our web server’s start page using another computer in the same network. However, as we did not use the --permanent flag, if you restart the firewalld daemon, the python-webserver service will be gone from the public zone (or you can also use the parameter, --remove-service=python-webserver).

In summary, we can say that the recommended firewall choice in CentOS 7 is firewalld, as all important system services have already been set up to use it via predefined service rules. You should remember that Linux firewalls are a very complex topic that can easily fill up a whole book, and you can do a lot more with the firewall-cmd that cannot be covered here in this book.

There's more…

Often, you just want to quickly open a specific port to test out things before writing your own custom-made service definition. In order to do this, you can use the following command line, which will open port 2888 using the tcp protocol temporarily on the default zone:
firewall-cmd --add-port=2888/tcp

Once you have finished your tests, just reload the firewall configuration to remove and close the specific port again.

 

Using YUM to update the CentOS

In this process, we will investigate the role of the Yellowdog Updater, Modified (YUM) package manager with regard to running a system update. Every once in a while, you may become aware of an update or may simply wish to discover if one exists. Applying patches and updates is a regular task for every server administrator, and an up-to-date system can help increase or ensure the security of your server as software bugs and vulnerabilities are found all the time and must be fixed promptly. In this process, you will learn how to achieve this with the help of YUM.

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 facilitate the download of additional packages.

The Process: 

You can run this process, as often as required but it should be done frequently, based on a schedule of your own choosing in the full knowledge that on occasion, some updates may
require a full system reboot:

  1. Log in as root and check whether there are any updates for your installed packages. To do this, log in and type the following:
    yum check-update
  2. If no updates are available, then the update process will end and no further work will need to be done. However, if updates are available, YUM will now return a list of all package updates from the repositories known to your system. To complete the update process, type the following command:
    yum -y update
  3. By using the -y flag, the preceding command will now bypass the need to confirm the transaction summary, and your system will now undergo an immediate update process. When complete, you will be provided with a final report that identifies what dependencies have been installed and what packages have been updated.
  4. Generally speaking, no further work is required and you may resume typical operations. However, if a new kernel has been installed, or an important security update has taken place, it may be necessary to reboot the system for the new changes to take effect. To do this, type the following:
    reboot

Note

While there is much debate as to whether an update will require a full system restart in practice, this is only to be considered after a kernel update, which is an update to glibc and particular security-based features that are activated during the boot process.

How Does It Work?

YUM is the default package management system for CentOS and part of its role is to automatically calculate what packages may require updating, what dependencies are required, and to manage the entire process of updating your system in a very simple way.

So, what have we learned from this experience?

We started the process by checking to see if any updates were available to our system using the yum command with the check-update option. In this way, YUM will now check a central repository to confirm if an update is applicable to our system. A repository is a remote directory or website that contains prepared software packages and utilities. YUM will use this facility to automatically locate and obtain the correct Red Hat Package Manager (RPM) and dependencies, and if an update is available, then YUM will respond accordingly with a full summary of what packages and dependencies are available. For
this reason, YUM is a very useful tool, and without doubt its mechanism does serve to simplify the processes associated with package management, because it can talk to repositories and this saves us from having to find and install new applications or updates
manually. If there are updates available, the output will show us exactly which packages are affected, then we can proceed to update the system by using YUM’s update parameter.

In this instance, the preceding command includes the -y flag. This is done in order to circumvent the need to agree with the transaction summary given, and to confirm that we have already agreed to make these updates after running the previous check. Otherwise, you would simply confirm the requests by using the Y key.

There’s more:

You can also use the update parameter to update single packages instead of the whole system by providing the package name like so: yum update package_name. YUM will serve to ensure that all of the requirements for an application are met during installation, and it will automatically install the packages for any dependencies that are not already present on your system. However, and I am sure you will be pleased to hear this, if a new application has requirements that conflict with existing software, YUM will abort the process without making any changes to your system. If you want to automate the updating of your system using a specific time interval, you can install the yum-cron package, which can be highly customized but is outside the scope of this book. To start after installation, use man yum-cron.

 

Synchronizing the CentOS system clock with NTP and the chrony suite

In this process, we will learn how to synchronize the system clock with an external time server using the Network Time Protocol (NTP) and the chrony suite. From the need to time-stamp documents, e-mails, and log files, to securing, running, and debugging a network, or to simply interact with shared devices and services, everything on your server is dependent on maintaining an accurate system clock, and it is the purpose of this proces to show you how this can be achieved.

To Start With: What Do You Need?

For completion of 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 to facilitate downloading additional packages.

The Process

In this process, we will use the chrony service to manage our time synchronization. As chrony is not installed by default on CentOS minimal, we will start this process by installing it:

  1. To begin, log in as root and install the chrony service, then start it and verify that it is running:
    yum install -y chrony
    systemctl start chronyd
    systemctl status chronyd
  2. Also, if we want to use chrony permanently, we will have to enable it on server startup:
    systemctl enable chronyd
  3. Next, we need to check whether the system already uses NTP to synchronize our system clock over the network:
    timedatectl | grep "NTP synchronized"
  4. If the output from the last step showed No for NTP synchronized, we need to enable it using:
    timedatectl set-ntp yes
  5. If you run the command (from step 3) again, you should see that it is now synchronizing NTP.
  6. The default installation of chrony will use a public server that has access to the atomic clock, but in order to optimize the service, we will need to make a few simple changes to streamline and optimize at what time servers are used. To do this, open the main chrony configuration file with your favorite text editor, as shown here:
    vi /etc/chrony.conf
  7. In the file, scroll down and look for the lines containing the following:
    server 0.centos.pool.ntp.org iburst
    server 1.centos.pool.ntp.org iburst
    server 2.centos.pool.ntp.org iburst
    server 3.centos.pool.ntp.org iburst
  8. Replace the values shown with a list of preferred local time servers:
    server 0.uk.pool.ntp.org iburst
    server 1.uk.pool.ntp.org iburst
    server 2.uk.pool.ntp.org iburst
    server 3.uk.pool.ntp.org iburst

    Note
    Visit http://www.pool.ntp.org/ to obtain a list of local servers geographically near your current location. Remember, the use of three or more servers will have a tendency to increase the accuracy of the NTP service.
  9. When complete, save and close the file before synchronizing your server using the sytstemctl command:
    systemctl restart chronyd
  10. To check whether the modifications in the config file were successful, you can use the following command:
    systemctl status chronyd
  11. To check whether chrony is taking care of your system time synchronization, use the following:
    chronyc tracking
  12. To check the network sources chrony uses for synchronization, use the following:
    chronyc sources

How it works…

Our CentOS 7 operating system’s time is set on every boot based on the hardware clock, which is a small-battery driven clock located on the motherboard of your computer. Often, this clock is too inaccurate or has not been set right, therefore it’s better to get your system time from a reliable source over the Internet (that uses real atomic time). The chrony daemon, chronyd, sets and maintains system time through a process of synchronization with a remote server using the NTP protocol for communication.

So, what have we learned from this experience?

As a first step, we installed the chrony service, since it is not available by default on a CentOS 7 minimal installation. Afterward, we enabled the synchronization of our system time with NTP using the timedatectl set-ntp yes command.

After that, we opened the main chrony configuration file, /etc/chrony.conf, and showed how to change the external time servers used. This is particularly useful if your server is behind a corporate firewall and have your own NTP server infrastructure.

Having restarted the service, we then learned how to check and monitor our new configuration using the chronyc command. This is a useful command line tool (c stands for client) for interacting and controlling a chrony daemon (locally or remotely). We used the tracking parameter with chronyc, which showed us detailed information about the current NTP synchronization process with a specific server. Please refer to the man pages of the chronyc command if you need further help about the properties shown in the output (man chronyc).

We also used the sources parameter with the chronyc program, which showed us an overview of the used NTP time servers.

You can also use the older date command to validate correct time synchronization. It is important to realize that the process of synchronizing your server may not be instantaneous, and it can take a while for the process to complete. However, you can now relax in the full knowledge that you now know how to install, manage and synchronize your time using the NTP protocol.

There's more…

In this process, we set our system’s time using the chrony service and the NTP protocol. Usually, system time is set as Coordinated Universal Time (UTC) or world time, which means it is one standard time used across the whole world. From it, we need to calculate our local time using time zones. To find the right time zone, use the following command 

timedatectl list-timezones
If you have found the right time zone, write it down and use it in the next command; for example, if you are located in Germany and are near the city of Berlin, use the following command:

timedatectl set-timezone Europe/Berlin
Use timedatectl again to check if your local time is correct now:

timedatectl | grep "Local time"
Finally, if it is correct, you can synchronize your hardware clock with your system time to make it more precise:
hwclock --systohc

 

Implementing CGI with Perl and Ruby on CentOS

In the previous processes in this segment, our Apache service only served static content, which means that everything requested by a web-browser already existed in a constant state on the server, for example as plain HTML text files that don’t change. Apache simply sends the content of a specific file from the web server to the browser as a response where it then gets interpreted and rendered. If there were no way to change the contents sent to the client, the Internet would be really boring and not the huge success it is today. Not even the simplest example of dynamic content, such as showing a web page with the web server’s current local time would be possible.

Therefore, early in the 1990’s, some smart people started inventing mechanisms to make communication possible between a web server and some executable programs installed on the server to generate web pages dynamically. This means that the content of the HTML sent to the user can change in response to different contexts and conditions. Such programs are often written in scripting languages such as Perl or Ruby but can be written in any other computer language as well, such as Python, Java, or PHP (see later). Because Apache is written in pure C and C++, it cannot execute or interpret any other programming language such as Perl directly. Therefore, a bridge between the server and the program is needed to define how some external programs can interact with the server. One of these methods is called the Common Gateway Interface (CGI) which is a very old way to serve dynamic content. Most Apache web servers use some form of CGI applications and in this process, we will show you how to install and configure CGI for use with Perl and Ruby to generate our first dynamic content.

Note
There also exist some special Apache web server modules such as mod_perl, mod_python, mod_ruby, and so on which should be generally preferred as they directly embed the interpreter of the language into the web server process and therefore are a lot faster in comparison to any interface technology such as CGI.

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 facilitate the download of additional packages.

It is expected that your server will be using a static IP address, Apache is installed and currently running, and that your server supports one or more domains or subdomains.

The Process

As both scripting languages Perl as well as Ruby are not installed by default on CentOS 7 Minimal, we will start this process by installing all required packages using YUM.

  1. To begin, log in as root and type the following command:
    yum install perl perl-CGI ruby
  2. Next, restart the Apache web server:
    systemctl restart httpd
  3. Next, we need to configure SELinux appropriately for the use of CGI scripts:
    setsebool -P httpd_enable_cgi 1
  4. Then we need to change the correct security context for our cgi-bin directory for SELinux to work:
    semanage fcontext -a -t httpd_sys_script_exec_t /var/www/cgi-bin restorecon -Rv /var/www/cgi-bin

Creating your first Perl CGI script

  1. Now create the following Perl CGI script file by opening the new file vi /var/www/cgi-bin/perl-test.cgi and putting in the following content:
    #!/usr/bin/perl
    use strict;
    use warnings;
    use CGI qw(:standard);
    print header;
    my $now = localtime;
    print start_html(-title=>'Server time via Perl CGI'),
    h1('Time'), p("The time is $now"),
    end_html;
  2. Next, change the file’s permission to 755, so our apache user can execute it:
    chmod 755 /var/www/cgi-bin/perl-test.cgi
  3. Next, to test and actually see what HTML is being generated from the preceding script, you can execute the perl script directly on the command line; just type:
    /var/www/cgi-bin/perl-test.cgi
  4. Now open a browser on a computer in your network and run your first Perl CGI script, which will print the local time by using the URL:
    http:///cgi-bin/perl-test.cgi
  5. If the script is not working, have a look at the log file /var/log/httpd/error_log.

Creating your first Ruby CGI script

  1. Create the new Ruby CGI script file vi /var/www/cgi-bin/ruby-test.cgi and put in the following content:
    #!/usr/bin/ruby
    require "cgi"
    cgi = CGI.new("html4")
    cgi.out{
         cgi.html{
         cgi.head{ cgi.title{"Server time via Ruby CGI"} } +
         cgi.body{
              cgi.h1 { "Time" } +
              cgi.p { Time.now}
          }
       }
    }
  2. Now change the file’s permission to 755 so our apache user can execute it:
    chmod 755 /var/www/cgi-bin/ruby-test.cgi
  3. To actually see what HTML is being generated from the preceding script, you can execute the Ruby script directly on the command line; just type /var/www/cgibin/ruby-test.cgi. When the line offline mode: enter name=value pairs on standard input is shown, press Ctrl+D to see the actual HTML output.
  4. Now open a browser on a computer in your network and run your first Ruby CGI script which will print the local time by using the following URL:
    http:///cgi-bin/ruby-test.cgi
  5. If it is not working, have a look at the log file /var/log/httpd/error.log.

How Does It Work?

Here in this process, we showed you how easy it is to create some dynamic web sites using CGI. When a CGI resource is accessed, the Apache server executes that program on the server and sends its output back to the browser. The main advantage of this system is that CGI is not restricted to any programming language but works as long as a program is executable on the Linux command line and generates some form of text output. The big disadvantage of CGI technology is that it is a very old and outdated technology: every user request to a CGI resource starts a new process of the program. For example, every request to a Perl CGI script will start and load a new interpreter instance into memory, which will produce a lot of overhead, therefore making CGI only usable for smaller websites or lower parallel user request numbers. As said before, there are other technologies to deal with this issue, for example FastCGI or Apache modules such as mod_perl.

So what did we learn from this experience?

We began this process by logging in as root and installing the perl interpreter and the CGI.pm module for it as it is not included in the Perl standard library (we will use it in our script), as well as by installing the ruby interpreter for the Ruby programming language. Afterwards, to make sure our Apache web server takes notice of our new programming languages installed on the system, we restarted the Apache process.

Next, we made sure that SELinux is enabled to work with CGI scripts and then we provided the standard Apache cgi-bin directory /var/www/cgi-bin with the proper SELinux context type to allow system-wide execution. To learn more about SELinux, read, Working with SELinux. In this directory we then put our Perl and Ruby CGI scripts and made them executable afterwards for the Apache user. In the main Apache configuration file, the /var/www/cgi-bin directory has been defined as the standard CGI directory by default, which means that every executable file you put into this directory, with proper access and execution permissions and the .cgi extension, is automatically defined as a CGI script and can be accessed and executed from your web browser, no matter which programming or scripting language it has been written in. To test our scripts, we then opened a web browser and went to the URL http:///cgi-bin/ with the name of the .cgi script to follow.

There's more…

If you would like to allow execution of CGI scripts in other web directories as well, you need to add the following two lines (Options and AddHandler) to any virtual host or existing Directive directive, or create a new one in the following way (remember that you then also have to set the SELinux httpd_sys_script_exec_t label on the new CGI location as well):

Options +ExecCGI
AddHandler cgi-script .cgi

 

 

Creating an integrated CentOS nameserver solution

So far in this chapter division, we used Unbound as a caching-only DNS server solution because it is very secure and fast, and BIND as our authoritative-only DNS server because its zone management is highly configurable and customizable. BIND has been around for a long time and is the most used DNS software ever. However, a number of critical bugs have been found (and luckily fixed) in the past. Here in this process, we will combine Unbound with BIND to get the best of both worlds: Only the very secure Unbound service will be directly exposed to your private network and can take and serve DNS queries from your clients. The BIND service stays bound to localhost only as it was configured in a former process and is only allowed to resolve internal hostnames and does not have direct access to the Internet or your clients. If a client connects to your Unbound service and requests to resolve an internal hostname from your private network, Unbound will query the BIND server locally for the DNS resolution and cache the response. On the other hand, if a client requests to resolve an external domain name, Unbound itself will recursively query or forward other remote DNS servers and cache the response. The integration of both DNS server systems makes it the perfect all-round DNS server solution.

To Start With: What Do You Need?

To complete this process, you will require a working installation of the CentOS 7 operating system and a console-based text editor of your choice. It is expected that a caching-only Unbound server (port 53) and an authoritative-only BIND server (port 8053) have been installed and are already running using process found in this chapter division.

The Process

In this process, we will show you how to configure Unbound so it will be able to query our locally running authoritative-only BIND service whenever a client requests an internal hostname. Any other request should go out as a recursive DNS request to a remote root server to construct an answer:

  1. Log in as root on our server running the Unbound and BIND service and open Unbound’s main configuration file:
    vi /etc/unbound/unbound.conf
  2. First put the following line somewhere in the server: clause:
    local-zone: "168.192.in-addr.arpa." nodefault
  3. Next, we will have to allow Unbound to connect to localhost which is disabled by default, search for the line that reads: # do-not-query-localhost: yes, then activate and set it to no:
    do-not-query-localhost: no
  4. Next, since our BIND server is not configured using DNSSEC, we need to tell Unbound to use it anyway (Unbound by default refuses to connect to DNS servers not using DNSSEC). Search for the line that starts with # domain-insecure: "example.com", then activate it and change it so it reads as follows:
    domain-insecure: "centos7.home."
    domain-insecure: "168.192.in-addr.arpa."
  5. Next, we need to tell Unbound to forward all the requests for our internal domain centos7.home. to the locally running BIND server (on port 8053). Append the following at the file’s end:
    stub-zone:
             name: "centos7.home."
             stub-addr: 127.0.0.1@8053
  6. Also, we need to tell Unbound to do the same for any reverse lookup to our internal domain using BIND:
    stub-zone:
            name: "1.168.192.in-addr.arpa."
            stub-addr: 127.0.0.1@8053
  7. Save and close the file, and then restart the Unbound service:
    unbound-checkconf && systemctl restart unbound

How Does It Work?

Congratulations! You now have a full authoritative and very secure DNS server solution using an integrated approach combining all the good parts from Unbound and BIND. In this process, we have shown you how to configure the Unbound service using stub-zones to connect to an internally running BIND service for both forward and reverse requests. A stub-zone is a special Unbound feature to configure authoritative data to be used that cannot be accessed using the public Internet servers. Its name field defines the zone name for which Unbound will forward any incoming DNS requests and the stub-addr field configures the location (IP address and a port) of the DNS server to access; in our example, this is the locally running BIND server on port 8053. For Unbound to be able to connect to the localhost, we first had to allow this using the do-not-query-localhost: no directive, had to mark our forward and reverse domain as being insecure, and also had to define a new local-zone, which is necessary that Unbound knows that clients can send queries to a stub-zone authoritative server.

There's more…

In order to test our new Unbound/BIND DNS cluster, make one public and one internal hostname DNS request to the Unbound service from another computer in the same network (you can also run similar tests locally on the DNS server itself). If our Unbound/BIND DNS cluster has the IP 192.168.1.7, you should be able to get correct answers for both dig @192.168.1.7 www.packtpub.com and dig @192.168.1.7 client1.centos7.home from any other computer in your network.

If you have to troubleshoot service problems or need to monitor the DNS queries of your new Unbound/BIND DNS server, you can configure logging parameters. For BIND, in the main configuration file named.conf you can set the verbosity of the logging output (or log level). This parameter is called severity and can be found within the logging directive. It is already set to dynamic; which gives the highest amount of logging messages possible. You can then read your current log using tail -f /var/named/data/named.run. For Unbound, you can set the level of verbosity in its main configuration file unbound.conf using the verbosity directive which is set to the lowest level of 1 but can be increased to 5. To learn more about the different levels, use man unbound.conf. Use journald to read the Unbound logging information using the command journalctl -f -u unbound.service (press Ctrl+c key to exit the command).

We can not only log the system and service information but can also enable query logs. For Unbound just use a verbosity of 3 or above to record query information. For BIND, in order to activate the query log (query output will go to the log file named.run), use the command rndc querylog on (to turn it off, use rndc querylog off). Remember to turn off any excessive logging information, such as the query log, when configuring your DNS server on a productive system as it can decrease your service’s performance. You can also install other third-party tools such as dnstop (from the EPEL repository) to monitor your DNS activity.

 

 

CentOS firewall

A firewall is a program that monitors and controls your system’s network interfaces’ incoming and outgoing network traffic and can restrict the transmission to only useful and non-harmful data into and out of a computer system or network. By default, CentOS is made available with an extremely powerful firewall, built right into the kernel, called netfilter. While, in older versions of CentOS, we used the famous iptables application to control it, in version 7, the new standard netfilter management program has changed to a service called firewalld, which is already installed and enabled on every CentOS 7 server by default.

It is a very powerful service to take full control over your server’s firewall security and is much easier to work with than iptables. Its main advantages are that it features a better structured and more logical approach to managing and configuring every aspect of a modern firewall solution. Therefore, it will be the foundation of your server’s security, and for this reason, it is the purpose of this process to get you started on the fundamentals of firewalld quickly.

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 and a console-based text editor of your choice.

The Process

As the firewalld service is running on every CentOS 7 server by default, we can start directly working with the service by logging in to your server using the root user.

  1. Type the following commands to query zone-related information:
    firewall-cmd --get-zones | tr " " "\n"
    firewall-cmd --list-all-zones
    firewall-cmd --get-default-zone
    firewall-cmd --list-all
  2. We can switch to a different firewall default zone by using the following line:
    firewall-cmd --set-default-zone=internal
  3. Add a network interface to a zone temporarily:
    firewall-cmd --zone=work --add-interface=enp0s8
  4. Now, add a service to a zone temporarily:
    firewall-cmd --zone=work --add-service=ftp
  5. Test if adding the interface and service has been successful:
    firewall-cmd --zone=work --list-all
  6. Now, add the service permanently:
    firewall-cmd --permanent --zone=work --add-service=ftp
    firewall-cmd --reload
    firewall-cmd --zone=work --list-all
  7. Finally, let’s create a new firewall zone by opening the following file:
    vi /etc/firewalld/zones/seccon.xml
  8. Now put in the following content:

     
    security-congress For use at the security congress.  

  9. Save and close, then reload the firewall config so that we can see the new zone:
    firewall-cmd --reload
  10. Finally, check that the new zone is available:
    firewall-cmd --get-zones

How Does It Work?

In comparison to iptables, the new firewalld system hides away the creation of sophisticated networking rules and has a very easy syntax that is less error-prone. It can dynamically reload netfilter settings at runtime without having to restart the complete service and we can have more than one firewall configuration set per system, which makes it great for working in changing network environments, such as for mobile devices like laptops. In this process, we have given you an introduction to the two fundamental building blocks of firewalld: the zone and the service.

So, what did we learn from this experience?

We started this process using firewall-cmd to get information about available firewall zones on the system. Firewalld introduces the new concept of network or firewall zones, which assigns different levels of trust to your server’s network interfaces and their associated connections. In CentOS 7, there already exist a number of predefined firewalld zones, and all of these (for example, private, home, public, and so on, with the exception of the trusted zone) will block any form of incoming network connection to the server unless they are explicitly allowed using special rules attached to the zone (these rules are called firewalld services, which we will see later). We queried zone information using firewall-cmd with --get-zones or (more detailed) with the --list-all-zones parameter. Each of these zones acts as a complete and full firewall that you can use, depending on your system’s environment and location. For example, as the name implies, the home zone is for use if your computer is located in home areas. If this is selected, you mostly trust all other computers and services on the networks to not harm your computer, whereas the public zone is more for use in public areas such as public access points and so on. Here, you do not trust the other computers and services on the network to not harm you. On CentOS 7, the standard default zone configuration set after installation is the public zone, which we displayed using the command’s --get-default-zone parameter, and in more detail using --list-all.

Note
Simply put, firewalld zones are all about controlling incoming connections to the server. Limiting outgoing connections with firewalld is also possible but is outside the scope of this book.

Also, to get more technical information about all currently available zones, we used the firewall client’s --list-all-zones parameter. In the command’s output, you will notice that a zone can have some associated networking interfaces and a list of services belonging to it, which are special firewall rules applied to incoming network connections. You may also notice that, while listing details of all zones and their associated services by default, all firewalld zones are very restrictive and barely allow anything to connect to the server at all. Also, another very important concept can be seen in the command’s output from the above. Our public zone is marked as default and active. While the active zone is the one that is directly associated with a network interface, the default zone can really get important if you have multiple network adapters available. Here, it acts as a standard minimum firewall protection and fallback strategy, in case you missed to assign some active zone for every interface. For systems with only one network interface setting, the default zone will set the active zone automatically as well. To set a default zone, we used the --set-default-zone parameter and, to mark a zone as active for an interface, we used --add-interface. Please note that, if you don’t specify the --zone parameter, most firewall-cmd commands will use the default zone to apply settings. Firewalld is listening on every network interface in your system and waiting for new network packets to arrive. In summary we can say that if there is a new packet coming into a specific interface, the next thing firewalld has to do is find out which zone is the correct one associated with our network interface (using its active or if not available its default configuration); after finding it, it will apply all the service rules against the network packets belonging to it.

Next, we showed you how to work with firewalld services. Simply put, firewalld services are rules that open and allow a certain connection within our firewall to our server. Using such service file definitions allows the reusability of the containing rules because they can be added or removed to any zone. Also, using the predefined firewalld services already available in your system, as opposed to manually finding out and opening protocols, ports, or port ranges using a complicated iptables syntax for your system services of interest, can make your administrative life much easier. We added the ftp service to the work zone by invoking --add-service. Afterward, we printed out details of the work zone using -list-all. Firewalld is designed to have a separated runtime and permanent configuration. While any change to the runtime configuration has an immediate effect but will be gone, the permanent configuration will survive to reload or restart of the firewalld service. Some commands such as switching the default zone are writing the changes into both configurations which mean they are immediately applied at runtime and are persistent over service restart. Other configuration settings such as adding a service to a zone are only writing to the runtime configuration. If you restart firewalld, reload its configuration, or reboot your computer, these temporary changes will be lost. To make those temporary changes permanent, we can use the --permanent flag with the firewall-cmd program call to write it to the permanent configuration file as well.

Other than with the runtime options, here the changes are not effective immediately, but only after a service restart/reload or system reboot. Therefore, the most common approach to apply permanent settings for such runtime-only commands is to first apply the setting with the --permanent parameter, and afterward reload the firewall’s configuration file to actually activate them.

Finally, we showed you how to create your own zone, which is just a XML file you have to create in the /etc/firewalld/zones/ directory, and where we specified a name, description, and all the services that you want to activate. If you change something in any firewall configuration file, don’t forget to reload the firewall config afterward.

To finish this process, we will revert our permanent changes made to the work zone and reload firewalld to reset all the non-permanent changes we applied in this process:
firewall-cmd --permanent --zone=work --remove-service=ftp
firewall-cmd --reload

There's more…

To troubleshoot blocking services, instead of turning off the firewall completely, you should just switch zone to trusted, which will open all the incoming ports to the firewall:
firewall-cmd --set-default-zone=trusted

Once you have finished your tests, just switch back to the zone that you were in before, for example:
firewall-cmd --set-default-zone=public

 

 

Taking control in CentOS with GIT and Subversion

Document revision control systems or version control systems, as they are sometimes called, are used for the management of changes to documents. These systems get more and more important these days as modern work often connects people from around the globe to collaborate and work together on all kinds of documents (for example, software source code) making it important to manage the file changes by different people using revisions. In this process, we will show you how to use modern version control systems such as GIT and Subversion to manage the versioning of config files.

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 connection to the Internet in order to facilitate the download of additional packages.

The Process:

Here in this process, we will put the complete main Linux configuration directory, /etc/, under version control of a Git repository to keep track of all our changes to configuration files:

  1. To begin, log in as root, install Git, and configure it by providing an email address and username (please substitute your_username and your_email_address with real names):
    yum install git
    git config --global user.email "your_email_address"
    git config --global user.name "your_username"
  2. Now, let’s create a new repository in the /etc directory:
    cd /etc/
    git init
  3. Now, after we have our new repository, let’s add all the files in the /etc/ directory under version control:
    git add *
  4. To commit the files to the repository creating your first revision, type the following:
    git commit -a -m "inital commit of the full /etc/ directory"
  5. Now, let’s change a file:
    echo "FILE HAS CHANGED" >> yum.conf
  6. Next, show the changes to your repository:
    git status
  7. Next, we will commit these changes and create a new revision of it:
    git commit -a -m "changing yum.conf files"
  8. Next, show all the commits so far:
    git log --pretty=oneline --abbrev-commit
  9. This will output the following commits on my system (the number hashes will be different on yours):
    8069c4a changing yum.conf
    5f0d50a inital commit of the full /etc directory
  10. Based on the output from the earlier step, we will now show all the differences between the two revision numbers (change the number hashes on your system based on the output from the earlier step):
    git diff 8069c4a 5f0d50a
  11. To complete this process, we will revert our changes to the original file revision (the initial commit):
    git checkout 5f0d50a

How Does It Work?

Here, in this process, we showed you how to use Git to manage changes to system config files in the /etc directory. This can be important, for example, if you are testing things out, so a lot of changes will be made to some configuration files and you will want to keep track of your changes, which is nice because you don’t need to memorize every single step you have taken if you later have to revert the changes or go back to a specific revision or  compare different file versions.

So, what did we learn from this experience?

We started by installing Git and added a username and an e-mail address to its configuration, which is essential for using it later in the process. Then, we changed to the /etc directory and initialized (using the init parameter) a new empty Git project there, which is called repository and keeps track of all the files associated to it. This command will add a hidden .git directory to it, which will contain the complete file changes and revision information. Next, we added all the files (using the wildcard * operator) from this directory, including all sub-directories to the next revision. A revision is like a state the files are in at a given time point and is identified by a unique hash ID such as 8069c4a.

Then, we actually created a new revision using the commit parameter and supplied a meaningful message using the -m parameter. After we set up the Git repository and added all the files to it, every change to the files gets watched in the /etc directory. Next, we changed the main YUM configuration file in our repository by adding a random string to

the end of it using the echo >> command. If we now use git’s status parameter again, we see in the output that the Git system has notified that this file has been changed. We can now create a new revision with the changed file by using git’s commit parameter again, using another meaningful message here stating that yum.conf has been changed. We then used the git log command. This will show us all the committed revisions with their unique md5 hash string IDs. With this ID, we can fuel the git diff command to see all the file changes between two revisions. To learn more about the output format, use man gitdiff- files and read its section COMBINED DIFF FORMAT. In our last step, we used the checkout command to go to a specific file revision; here we reverted all our changes and went back to the original file state.

Git is a very powerful version management tool, and in this process, we just scratched the surface of what can be done with it. To learn more about Git’s wonderful techniques, such as branching, merging, pull requests, and so on, start with the Git tutorial pages by typing in man gittutorial.

There’s More:

You can also use the program Subversion to bring your /etc directory under version control. Subversion is another common document revision control system whose main difference from Git is that it uses a centralized server to keep track of the file changes. Git is distributed, meaning that everybody working on a Git project will have the complete repository locally on their computer. Here, we will show you the exact steps necessary to use Subversion instead of Git for this purpose:

  1. First, install Subversion and configure a new server directory for our /etc repository:
    yum install subversion
    mkdir -p /var/local/svn/etc-repos
    svnadmin create --fs-type fsfs /var/local/svn/etc-repos
  2. Now, make an in-place import of the /etc filesystem to our new repository:
    svn mkdir file:///var/local/svn/etc-repos/etc
    -m "Make a directory in the repository to correspond to /etc"
  3. Now, switch to the /etc directory and add all the files to a new revision:
    cd /etc
    svn checkout file:///var/local/svn/etc-repos/etc ./
    svn add *
  4. Now, create your first commit:
    svn commit -m "inital commit of the full /etc/ directory"
  5. Next, change the yum.conf file:
    echo "FILE HAS CHANGED" >> yum.conf
  6. Commit your changes to a new file revision:
    svn commit -m "changing yum.conf files"
  7. Now, show the change log:
    svn log -r 1:HEAD
  8. Show the file differences between our two commits (the first commit was the /etc import):
    svn diff -r 2:3
  9. Finally, revert to the first revision of our yum.conf file:
    svn update -r 2 yum.conf

 

 

 

Speaking the right language in CentOS

In this process, we will show you how to change the language settings of your CentOS 7 installation for the whole system and for single users. The need to change this is rare but can be important, for example, if we accidentally chose the wrong language during installation.

To Start With: What Do You Need?

For the successful implementation of 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 Navigating text files with less process because some commands in this process will use less for printing output.

The Process

There are two categories of settings that you have to adjust if you want to change the system-wide language settings of your CentOS 7 system. We begin by changing the system locale information and then the keyboard settings:

  1. To begin, log in as root and type the following command to show the current locale settings for the console, graphical window managers (X11 layout), and also the current keyboard layout:
    localectl status
  2. Next, to change these settings, we first need to know all the available locale and keyboard settings on this system (both commands use less navigation):
    localectl list-locales localectl list-keymaps
  3. If you have picked the right locale from the output above in our example, de_DE.utf8 and keymap de-mac (change to your own appropriate needs), you can change your locale and keyboard settings using:
    localectl set-locale LANG=de_DE.utf8 localectl set-keymap de-mac
  4. Now, verify the persistence of your changes using the same command again:
    localectl status

How it works…

As we have seen, the localectl command is a very convenient tool that can take care of managing all important language settings in a CentOS 7 system.

So what have we learned from this experience?

We started by logging in to our command line with the root user. Then, we ran the localectl command with the parameter status, which gave us an overview of the current language settings in the system. The output of this command showed us that language properties in a CentOS 7 system can be separated into locale (system locale) and keymap (VC keymap and all X11 layout properties) settings.

Locales on Linux are used to set the system’s language as well as other language-specific properties. This can include texts from error messages, log output, user interfaces, and if you are using a window manager such as Gnome, even Graphical User Interfaces (GUI). Locale settings can also define region-specific formatting such as paper sizes, numbers, and their natural sorting, currency information, and so on. They also define character encoding, which can be important if you choose a language that has characters that cannot be found in the standard ASCII encoding.

Keymap settings, on the other hand, define the exact layout of each key on your keyboard.

Next, to change these settings, we first issued the localectl command with the list-locales parameter to retrieve a full list of all locales on the system, and list-keymaps to show a list of all keyboard settings available in the system. Locales as outputted from the list-locales parameter use a very compact annotation for defining a language:
Language[_Region][.Encoding][@Modificator]

Only the Language part is mandatory, all the rest is optional. Examples for language and region are: en_US for English and region the United States or American English, es_CU would be language Spanish and Region Cuba or Cuban Spanish.

Encodings are important for special characters such as German umlaut or accents in the French language. The memory representation of these special characters can be interpreted differently depending on the used encoding type. In general, UTF-8 should be used as it is capable of encoding almost any character in every language.

Modificators are used to change settings defined by the locale. For example, sr_RS.utf8@latin is used if you want to have Latin settings for serbian Serbia, which normally uses Cyrillic definitions. This will change to western settings such as sorting, currency information, and so on.

To change the actual locale, we used the set-locale LANG=de_DE.utf8 parameter. Here, the encoding was selected to display proper German umlauts. Please note that we used the LANG option to set the same locale value (for example, de_DE.utf8) for all available locale options. If you don’t want to have the same locale value for all available options, you can use a more fine-grained control over single locale options. Please refer to the locale description using the man page, man 7 locale (on minimal installation; you need to install all Linux documentation man pages before using the yum install man-pages command). You can set these additional options using a similar syntax, for example, to set the time locale use:
localectl set-locale LC_TIME="de_DE.utf8"

Next, we showed all available keymap codes using the list-keymaps parameter. As we have seen from running localectl status, the keymaps can be separated in non-graphical (VC keymap) and graphical (X11 layout) settings, which allows the flexible configuration of different keyboard layouts when using a window manager such as Gnome and for the console. Running localectl with the parameter, set-keymap de-mac, sets the current keymap to a German Apple Macintosh keyboard model. This command applies the given keyboard type to both the normal VC and the X11 keyboard mappings. If you want different mappings for X11 than for the console, use localectl --no-convert set-x11keymap cz-querty, where we use cz-querty for the keymap code to a Czech querty keyboard model (change this accordingly).

There's more…

Sometimes, single system users need different language settings than the system’s locale (which can only be set by the root user), according to their regional keyboard differences and for interacting with the system in their preferred human language. System-wide locales get inherited by every user as long as they are not overwritten by local environment variables.

Note

Changing system-wide locales does not necessarily have an effect on your user’s locales if they have already defined something else for themselves.

To print all the current locale environment variables for any system user, we can use the command, locale. To set single environment variables with the appropriate variable name; for example, to set the time locale to US time we would use the following line:
export LC_TIME="en_US.UTF-8"

But, most likely we would want to change all the locales to the same value; this can be done by setting LANG. For example, to set all the locales to American English, use the following line:
export LANG="en_US.UTF-8"

To test the effect of locale changes, we can now produce an error message that will be shown in the language set by the locale command. Here is the different language output for changing the locale from English to German:
export LANG="en_US.UTF-8"
ls !

The following output will be printed:
ls: cannot access !: No such file or directory

Now, change to German locale settings:
export LANG="de_DE.UTF-8"
ls !

The following output will be printed:
ls: Zugriff auf ! nicht möglich: Datei oder Verzeichnis nicht gefunden

Setting a locale in an active console using the export command will not survive closing the window or opening a new terminal session. If you want to make those changes permanent, you can set any locale environment variables, such as the LANG variable, in a file called .bashrc in your home directory, which will be read every time a shell is opened. To change the locale settings permanently to de_DE.UTF-8 in our example (change this to your own needs) use the following line:
echo "export LANG='de_DE.UTF-8'" >> ~/.bashrc