This tutorial will guide you through deploying an Apache web server on CentOS 6. With security a top priority for public-facing web servers, I’ll show you how to do the configuration with SELinux enabled, using customized policies to ensure we’re protected at all times. Does the thought of SELinux scare you? If so, you’ll be surprised by how easy it is to actually use, when done properly.
The scope of this tutorial will be on Apache and PHP only. Databases will not be covered, as it is expected that service will be hosted on another server. This server will be ideal for either simple applications or load-balanced web farms.
- Install and configure Apache
- Install and configure PHP
- Use Non-default Apache Web Directories
- Create SELinux Policies for Web Application
The lab server used has the following configuration, for those following along. It’s used for example purposes only. As each application has its own requirements, you should size your server accordingly.
|Processor||2 Cores||Web Server||Apache 2.2.15|
|RAM||1 GB||Database Server||MySQL Server 5.1|
|Hard Disk||1 x 48 GB||Web Server||Apache 2.2.15|
|Network Interfaces||1||Web Application||WordPress|
|Mount Point||File System||Size||Notes|
|MBR – Standard Partitions|
|/boot||EXT2||200 MB||The boot image is small and it doesn’t need the overhead added by EXT4’s journaling. Other than minimizing the complexity of the file system used by /boot, there are very few benefits for placing it on its own partition with a large majority of today’s Linux distros.|
|Mount Point||Volume Group||Volume Name||File System||Size|
|LVM – Logical Volumes|
We have our mount points defined, but we need to configure them in /etc/fstab with security in mind for some of them.
- Open fstab into a text editor, like VIM, for example.
- Following along with the disk layout above, find the following lines in fstab and add the highlighted options.
/dev/mapper/vg01-lv_home /home ext4 defaults,nosuid,nodev,noexec 1 2 /dev/mapper/vg01-lv_logs /var/log ext4 defaults,nosuid,nodev 1 2 /dev/mapper/vg01-lv_webapps /srv/webapps ext4 defaults,nodev,noexec 1 2
nodev Prevents device files from existing on the mount point’s file system. Unless you have some special requirements, device files should only exist in /dev. noexec Prevents executable files from running on the mount points file system. In this tutorial, we have it set for our web app mount. If your web application requires cgi, this will break the application and you should not add it.
- Save the modified fstab file and exit the text editor.
- Reboot the server or unmount and then remount the modified mount points to apply the changes.
Prepare the Server
The following steps are designed to help you prepare the server before the server for Apache and your web applications.
Creating Users and Groups
After the deployment is complete, no one should use the Root account unless absolutely required. We need to create two user accounts and two groups, one for day-to-day maintenance of the web applications and another for system administration. After we’ve created our users and groups, we’ll then secure SSH to only allow our non-administrative accounts remote access. This separation adds another layer of security to help prevent hackers from gaining complete control, if they were successfully in remotely logging in with someone’s account.
- Create your day-to-day user account.
- Set your password for this account
- Create your server admin account.
- Set your admin account’s password
- Create your webadmins group.
- Create your system administrator group.
- Create a remote administration group for which we’ll grant SSH access.
- Add your day-to-day account to the webadmins group.
usermod -G webadmins -a jsmith
- Add your server admin account the system administrator group.
usermod -G sysadmins -a jsmith-admin
- Add the Apache account to the webadmins group to grant it access to our /webapps directory, which will be needed after we secure it below.
usermod -G webadmins -a apache
- Since we want jsmith, being us, remote access into our web server, we need to add the account to the remoteadmins group.
usermod -G remoateadmins -a jsmith
Granting System Administration Rights
We’re now going to assign accounts who need system administration rights to our sysadmins group. Through sudo, the sysadmins group will have full administrative rights. Root will then be given a very complex password to protect it from misuse.
- Open the sudoers file editor
- Navigate to the bottom of the file and add the following line:
%sysadmins ALL=(ALL) ALL
- To save our settings, press ESC and then type colon (:) and ‘w’.
- Type colon (:) and ‘q’ to exit the editor.
- Set a complex password for the Root account. The longer, more complex it is, the better.
Locking Down SSH Access
SSH is a great tool for remote administration of your Linux servers; however, left unprotected using default settings is very risky. Brute forcing into any server is a two step process: find a user account and discover the user account’s password. And what account is known to exist on every Linux server? Root. For this reason, it is best practice to prevent Root from having remote access to the server. Another concern is ‘who has access rights into the server?’ By default, SSH will grant access to all accounts. Since not every user should have the ability to SSH into the server, we want to ensure only authorized users can do so. To do this, we are going to configure SSH to only allow users in the remoteadmins group permission to remotely access the server.
- Open the SSH Server configuration file into a text editor, like VIM.
- Find the line that permits Root logon
#PermitRootLogin yesUncomment it by removing the hash mark ‘#’ and replacing ‘yes’ with ‘no’. Note: despite this option being commented out, by default SSH grants Root login permissions. This is why it is important we uncomment the option and explicitly set it to ‘no’.
- Now, we just want authorized users to have access on our server through SSH. Add the ‘AllowGroup’ option to the configuration file, and then append the groups we want to allow access to.
- Save the configuration file and exit the editor.
- Restart the SSH daemon to apply our changes.
service sshd restart
To add additional security hardening to SSH, use keys instead of passwords. Learn how by reading Passwordless SSH Logons on CentOS 6 using RSA Authentication Keys.
Prepare the Webapps Directory Structure
The default location for an Apache website on CentOS servers is /var/www/html. This is fine if you do not expect to ever add addtional web applications using Apache’s virtual hosts. Otherwise, it’s best to create your own directory structure.
Before we install Apache and start defining web sites, we need to prepare our webapps directory. Inside of the /srv/webapps directory, we’re going to create separate directories for each of our applications and their logs (see example below), starting with what we’ll call App1.
/srv |---/webapps |---/app1 |---/public_html |---/logs
- Create application directory
mkdir -p /srv/webapps/app1/public_html
- Create application log directory
mkdir -p /srv/webapps/app1/logs
- Change /webapps group ownership to our webadmins.
chgrp -Rv webadmins /srv/webapps
- Set the guid bit recursively for the webapps directory to ensure all new files and directories are owned by the webadmins group. Also, we’re going to grant read/write access to the webadmins group and file owners, and no access to anyone else.
chmod 2770 -Rv /srv/webapps
- With the public_html directory, we’re going to grant read access to everyone.
chmod 2775 -Rv /srv/webapps/app1/public_html
Creating SELinux Policies
Install Required Packages
Before we can create our own policies, we need to ensure SEMANAGE is installed. This application allows us to browse through the existing, default context policies, and create our own.
- Open a console with root privileges
- Install the policycoreutils-python package, which contains SEMANAGE.
yum install -y policycoreutils-python
- For troubleshooting SELinux issues, download the setroubleshooting package. This step is actually optional, but you’ll be thankful for it when you are able quickly diagnose SELinux problems with it.
yum install -y setroubleshooting
Apache Context Types
Before we can start creating our own policies for applying Apache’s context types, we need to understand which are available to us out of the box. The following table shows the ones we are primarily interested in, however there are several others available.
|httpd_sys_content_t||Read-only directories and files used by Apache|
|httpd_sys_rw_content_t||Readable and writable directories and files used by Apache. Assign this to directories where files can be created or modified by your application, or assign it to files directory to allow your application to modify them.|
|httpd_log_t||Used by Apache to generate and append to web application log files.|
|httpd_cache_t||Assign to a directory used by Apache for caching, if you are using mod_cache.|
Create the Policies
- Create a policy to assign the httpd_sys_content_t context to the /webapps directory, and all child directories and files.
semanage fcontext -a http_sys_content_t "/srv/webapps(/.*)?"
- Create a policy to assign the httpd_log_t context to the logging directories.
semanage fcontext -a httpd_log_t "/srv/webapps/logs(/.*)?"
Assign Policies to Application Directory
With the policies defined, it’s time to assign them to our web application directories. To do so we use the restorecon command against our webapp’s parent directory.
- Apply the SELinux policies
restorecon -Rv /srv/webapps
That’s it! We’re done. I bet it was a lot easier than you expected. Too many tutorials disable SELinux, because everyone seems to be afraid. Although complicated underneath the covers, it’s actually very simplistic to administer.
Installing and Configuring Apache
- Install Apache 2
yum install httpd
- Open Apache’s configuration file into a text editor, like VIM.
- Prevent Apache from advertising its version by turning Server Signature off. To do so, locate the following line
ServerSignature Onand replace it with
- Prevent Apache from advertising operating system info. To do so, locate the following line
ServerTokens OSand replace it with
- Change the location of the web applications root directory from /var/www to our new location. Find the following line
<Directory "/var/www/html">and replace it with
- Prevent directories from showing their contents in a web browser by removing the Indexes option. To do so, find the following, located just under the line we modified above.
Options Indexes FollowSymLinksand replace it with
- Change the location of the error log by locating the following line
ErrorLog logs/error_logand replace it with
- Change the location of the access log by locating the following line
CustomLog logs/access_log combinedand replace it with
CustomLog /srv/webapps/app1/logs/access_log combined
- Save the changes and exit the text editor.
- Add the Apache user account to our webadmins group, to grant Apache rights to our application directories.
usermod -G webadmins -a apache
- Start the Apache daemon.
service httpd start
- Configure the Apache daemon to start automatically after boot.
chkconfig httpd on
Installing and Configuring PHP
Although MySQL isn’t being installed on this server, if you application requires database connectivity we need to install php-mysql.
- Install PHP5 and extensions for MySQL.
yum install php php-mysql
- Open PHP’s configuration file into a text editor, like VIM.
- There are a few functions that should be disabled to security reasons, unless you know for sure that your web application requires them. Find the following line.
disable_functions =and replace it with
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
- Find the line containing option display_errors and ensure it is set to ‘off’.
display_errors = Off
- Find the line containing option register_globals and ensure it is set to ‘off’.
register_globals = Off
- Find the line containing option magic_quotes_gpc and ensure it is set to ‘off’.
magic_quotes_gpc = Off
- Save your changes and exit the text editor.
- Restart Apache to apply the new PHP settings.
service httpd restart
Open the Firewall
Before users can access our web application through a web browser port 80 will have to be opened up. By default, IPtables – a Linux firewall service – blocks this port.
- Run the following command to configure IPTables through a basic GUI-like interface.
- Ensure that the firewall is enabled.
- Press Tab to navigate to Customize, and press Enter.
- Scroll down the trusted services list until you see WWW (HTTP).
- Enable access to it by pressing the Spacebar.
- Press Tab to navigate to the Close button, and press Enter.
- Press Tab to navigate to the OK button, and press Enter.
We now have a secured, role-specific web server. Your next step is going to be deploying a database server for your application. The benefit of using role specific servers is they are more secure and a lot easier to scale out.