Hi there! Today I'd like to show you how I install and configure Apache httpd on CentOS. I like to have it installed in minimal and secure way. First part is about installation, second about configuration. Last part is about setting up Virtual Hosts.
How to install Apache httpd on CentOS - easy way
There are two ways to install Apache httpd on CentOS. First is with yum and it is the simplest version:
sudo yum install httpd -y
Volia! You have httpd installed. However, if you check the version:
You will most probably get
2.4.6 version or slightly newer. If you check Apache website, you will note, that they have
2.4.23 version available. So, if you want to have access to latest features such as HTTP/2 support or latest bugfixes, you will have to try more difficult method which is installing Apache httpd from source.
How to install Apache httpd from source on CentOS?
Installing and compiling software from the source code might sound scary. But trust me, it's not. It takes more time to have Apache httpd up and running, than installing it with yum. However it comes with some benefits that I will mention during this tutorial.
Remove old Apache httpd
Before you will even begin, make sure that you don't have Apache httpd installed. In general you don't want to have two version installed on the same machine, unless you are doing some A/B testing or testing versions on different ports etc. But for this tutorial I want to start clean, so I remove installed Apache httpd:
sudo yum remove httpd -y
Compile and install Apache httpd
Required tools for building
You need to install some tools that will help us compile Apache. It's basic stuff like compiler, required libraries etc:
sudo yum install autoconf libtool openssl-devel pcre-devel -y
Download and unpack source code
Next thing that you need are packages with source files. For compiling Apache, you will need 3 different packages -
apr-util. Last two are Apache Runtime libraries. They are required for Apache httpd. When you install Apache httpd with yum they come as dependencies.
There are two ways of getting them. Either you can clone them from git repository or you can download them as
tar.gz package. I must say that as I love git, for downloading sources I prefer downloading compressed package. Why? When you clone repository it usually downloads whole history, branches etc. Apache is for instance around 290MB of files. Compressed package is about 10MB. So it is much faster to download just required files instead of cloning whole repo.
I like to download packages from GitHub releases. Here are the links to the packages:
Click on tar.gz icon, copy the link to package and download them with curl or wget. Or simply copy commands below:
curl -O -L https://github.com/apache/httpd/archive/2.4.23.tar.gz
curl -O -L https://github.com/apache/apr/archive/1.5.2.tar.gz
curl -O -L https://github.com/apache/apr-util/archive/1.5.4.tar.gz
Unpack downloaded sources:
tar -zxvf 2.4.23.tar.gz
tar -zxvf 1.5.2.tar.gz
tar -zxvf 1.5.4.tar.gz
APR and APR-Util
Apache requires APR library to be present in the system. You can manually compile and install APR and APR-util first and then do the same with httpd. But I prefer to do it in one shot. First you need to copy the source codes to correct directory:
cp -r apr-1.5.2 httpd-2.4.23/srclib/apr
cp -r apr-util-1.5.4 httpd-2.4.23/srclib/apr-util
It's important to not to include version number in APR directories. If you just copy
apr-1.5.2 without changing the name, it will give you a warning about missing
Now you are ready to compile Apache httpd. It's important that you should not use root user for compilation. It can lead to serious security issues. I described it more on my other tutorial about installing GIT. In short words, imagine that you downloaded package from wrong source with malicious code. If you would compile it as root user, anything can happen to your server. Including cutting of your root access. I'm not saying that it's not possible to compile packages as root, because it is. It's just not safe. If you want to create separate user with sudo powers, you can read this tutorial.
So get inside httpd directory and compile your Apache httpd version:
./configure --enable-ssl --enable-so --with-mpm=event --witn-included-apr --prefix=/usr/local/apache2
./buildconf will build
./configure file required for configuration of the build.
./configure command will setup everything for compilation of Apache httpd. Here are the options that I use:
--enable-ssl will build Apache with SSL support, so you can enable HTTPS on your websites.
--enable-so will enable dynamically loaded modules. So you can enable and disable modules without recompilation (I will describe modules in configuration part)
--with-mpm will set multiprocessing modules for Apache. I'm using
event, but you can use
event works best for me and I think that it is mpm that will give you most performance.
--with-included-apr It will use APR library that you copied to
--prefix is the installation path for Apache httpd compiled package
Whole process might take a while. It depends how fast your server is.
After it's compiled you can install it. For that you need sudo or root account:
sudo make install
Apache should be installed in the directory you specified with --prefix option.
Last thing you can do now is to remove downloaded files. You won't need them now. It's not mandatory, but it's nice to keep server clean.
rm -rf 1.5.2.tar.gz 1.5.4.tar.gz 2.4.23.tar.gz apr-1.5.2 apr-util-1.5.4 httpd-2.4.23
Set system scripts for Apache httpd
Before I will show you how I configure my Apache httpd server, I want to show you two really helpful scripts.
Add Apache httpd to $PATH
If you try to type
httpd -v in your command line, it will result in command not found. That's because httpd is not on your
$PATH. I'd like to have all executables from Apache available from everywhere. In order to achieve that, create file
sudo vi /etc/profile.d/httpd.sh
and paste there following contents:
Save the file, log out and log in from your current session to reload your profile. After that you should be able to use
httpd -v command:)
Second really useful script is SystemD entry. It will allow you to start, restart and stop Apache httpd from
systemctl. You need to create another file:
sudo vi /etc/systemd/system/httpd.service
and paste there following contents:
Description=The Apache HTTP Server
ExecStart=/usr/local/apache2/bin/apachectl -k start
ExecReload=/usr/local/apache2/bin/apachectl -k graceful
ExecStop=/usr/local/apache2/bin/apachectl -k graceful-stop
Save the file and reload the systemctl daemon
sudo systemctl daemon-reload
Now you can try to start your Apache httpd server with following command:
sudo systemctl start httpd
It should start properly. If you will have any warnings, don't bother with them now. I will show you proper configuration in next step.
Once it's up and running you can try to type your server IP address in your browser like
http://126.96.36.199/ and check if you see
It works! message:) If so, you have Apache httpd running fine!
How to configure Apache httpd properly
Although Apache httpd is working and you can use it's default configuration it's good to tune it up a bit. It's always nice to gain additional milliseconds and security.
Apache user and group
Before I will show you how to change configuration I usually create additional user and group for httpd daemon. It's good practice from security side. Each service should operate as separate user. It limits possible damage during attacks, httpd exploitation etc.
If you want to learn more about creating user and groups I recommend reading this tutorial. Here I'll just simply create group and user without shell.
sudo groupadd www
sudo useradd httpd -g www --no-create-home --shell /sbin/nologin
You can change the names as you wish. I like to use
www group instead of
httpd group for example. I usually add there other services as well, like
Configuration of httpd.conf
httpd.conf is main Apache httpd configuration file. You should start by editing this file:
sudo vi /usr/local/apache2/conf/httpd.conf
There are couple of options that we should set. Just scroll the file and edit what you need. Values in
code blocks are the values that I use:
Make sure that
ServerRoots direct to the same path as you set via
.configure It needs to point to installation directory.
This is Apache port under which it should listen for incoming connections.
List of modules is pretty long. Some of the are disabled (they have
# at the beginning of the line). Some of them are enabled. You can leave them as they are. Eventually you can enable additional modules.
You should know, that the more modules are enabled the "slower" Apache httpd is. I'm not saying that it's super slow, but you can google for some benchmarks showing different configurations.
Here is what I like to do. First of all, I comment out all modules = everything is disabled. I enable only that modules that I really use + the modules that are required for proper functioning of Apache httpd. It has few benefits - Apache is faster, eats less resources (CPU and RAM) and it's more resistant for given attacks. Usually when new security issue pops out, it's rather connected to one of the modules, than whole httpd. So you can have more chances to avoid potential security risk with having some stuff disabled.
So here is what I'm using. First part are essential modules that must be enabled for proper Apache functioning under UNIX systems:
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule dir_module modules/mod_dir.so
Next thing are optional modules that you might want or might not want to enable.
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
I'm using php-fpm for running PHP on my servers. I'm using proxy for that purpose. More about that topic in next part of the article.
LoadModule alias_module modules/mod_alias.so
Alias command. Super useful when you are running WordPress with composer and wpackagist for setting up alias to wp-content directory.
LoadModule access_compat_module modules/mod_access_compat.so
Also useful for WordPress pages. With Apache 2.4
Order command is disabled by default in favor of
Require. However some WordPress plugins are still using
Order. If you have any issues with that, just enabled
LoadModule rewrite_module modules/mod_rewrite.so
Most popular module for almost all CMSes and Framworks. It allows pretty urls and so on. I still wonder why it's note enabled by default?
And that is the whole list of the modules I'm using. Sometimes when I can see that website is not working properly I check error logs. You can figure out that there is some module that is required. Simply enable it, restart the server and check if it's working fine.
User and group
User and group that you created in previous step. It should be set to corresponding values.
Simplest to set it to
localhost here. It will suppress the warning during Apache start for default value.
DirectoryIndex index.php index.html
This is the file that should be loaded when accessing directory. If you are using PHP, you should add
index.php at first place, like in example above. However if you just using node.js or plain HTML,
index.html is enough.
Save the changes to file and try to restart httpd.
sudo systemctl restart httpd
Check if everything is working fine. That was just some basic configuration. Here are some additional parameters that will increase security on the server. They are not present in httpd.conf file, so you need to add them manually. I like to add them at the end of the file.
By default in headers that are full information about Apache version, PHP version etc. I set it to
prod, so it will only show, that it's powered by Apache. No versions etc.
Disable server signature in internal Apache document's footer. It will hide Apache version in those files as well
Disable tagging files with tags. Usually there are additional headers added with information that should not be visible outside (ie. Inode)
Remember that after the changes you need to restart Apache. Otherwise changes won't be applied!
Last thing from configuration I would like to show you is enabling MPM settings. At the bottom of
httpd.conf you need to uncomment the line:
It will enable advanced Apache httpd MPM configuration and it will override the defaults.
Now edit enabled file:
sudo vi /usr/local/apache2/conf/extra/httpd-mpm.conf
There are configuration for each MPM module, so make sure that you are configuring correct values. I enabled
event mode, so this is the section I care about:
Important thing that you need to know - there is no one config to rule them all. What I want to say that configuration that works on one server, will work on second server. There are dozens of factors like application specific, CPU and RAM, traffic etc. I encourage you to play around with these values to find the optimal settings for your server.
Here is great post that explains in depth MPM configuration. I have two advice's about performance tuning.
First one, that you probably don't even need to change anything if you have regular website without huge amount of traffic. It's just good to know what settings are applied by mpm configuration. When httpd-mpm.conf file was commented out, you didn't have any idea what the settings are. Once it's enabled, you at least know what is configured.
Second advice is - do it slowly. Performance tuning is lengthy process, and as I said, it highly depends on various factors. I like to change one settings, like
StartServers for instance and I wait day or two and monitor response times, CPU and RAM usage etc. Sometimes even if you increase something you won't see a difference in response time, but you will get higher CPU usage. Then you just can rollback the changes. If you modify 3 or 4 values at one time, it's hard to say which comes with best (or any) result.
Remember to restart Apache httpd after making changes:)
Setting up Virtual Hosts for websites
I want to show you how I setup VirtualHosts for my websites. There are tons of different ways of storing Vhost files. Some of people like to keep everything in one file, some likes symbolic links etc. It actually doesn't really matter how you do it. But it's nice to keep it consistent and easy to manage.
First I make sure that I have
/var/www directory present in my system. If you don't have one, create it. Make sure that it has root as an owner and
sudo mkdir /var/www
sudo chmod 755 /var/www
sudo chown root:root /var/www
Second thing are websites directories. I create such directory, even if I have only one website on my server. For directory name I'm using domain name. In each directory I create two subdirectories -
htdocs for storing website files and
logs for storing logs. So for instance:
sudo mkdir /var/www/blacksaildivision.com
sudo mkdir /var/www/blacksaildivision.com/htdocs
sudo mkdir /var/www/blacksaildivision.com/logs
When it comes to ownership to main directory I set root:root. When it comes to subdirectories I set owner as
developer or any other user account (other than root) that can clone repositories, use files etc. As group, I'm using
www group. As you might remember Apache httpd is added to this group as well.
sudo chown root:root /var/www/blacksaildivision.com
sudo chown developer:www /var/www/blacksaildivision.com/htdocs
sudo chown developer:www /var/www/blacksaildivision.com/logs
Permissions to website directory is the same as for
/var/www. For htdocs and logs I'm using
2775. So each user in
www group will be able to write to these files.
2 at the beginning means that every new subdirectory created will have the same ownership as parent directory (
sudo chmod 755 /var/www/blacksaildivision.com
sudo chmod 2775 /var/www/blacksaildivision.com/htdocs
sudo chmod 2775 /var/www/blacksaildivision.com/logs
Once you have your directory structure ready, you can create VirtualHost files. I create one file per domain. All files are stored in
conf/extra directory with the same name scheme as other files there. So let's create file there:
sudo vi /usr/local/apache2/conf/extra/httpd-vhost-blacksaildivision.com.conf
and paste there following contents:
# Directory settings
Require all granted
Options +FollowSymLinks -Indexes -Includes
# PHP-FPM settings
ProxyPassMatch "^/(.*\.php(/.*)?)$" "fcgi://127.0.0.1:9000/var/www/blacksaildivision.com/htdocs"
CustomLog "/var/www/blacksaildivision.com/logs/httpd-access.log" common
File has few sections. Everything is wrapped with
VirtualHost block with Apache httpd port.
ServerName stands for domain name. Each file has to have different domain name to avoid conflicts.
Next are directory config.
DocumentRoot is basically the path to directory you created before. Now you need to specify settings of this directory.
AllowOverride All means that I'm allowing
.htaccess files to override all settings.
Require all granted is a must here if you want to have access to this directory. Last thing are
Options. I disable
Includes for security reasons.
FollowSymLinks is usually required by frameworks and CMSes.
I'm using PHP in PHP-FPM mode, so I need to pass all requests to PHP files via Proxy to FPM daemon.
Last parts are logs. Error log will contain information about errors. Custom log is like access log. All requests to your domain will be stored there.
Save the changes to the file. Now you need to include this file in main Apache httpd config file. So edit it:
sudo vi /usr/local/apache2/conf/httpd.conf
and at the end of the file include newly created file:
Restart Apache httpd daemon and try to access your website. It should work fine. If not, please check
logs directory for possible errors.
Run Apache httpd on system start
Last thing is to add Apache httpd daemon to start with system boot. So after server start/restart httpd will run automatically:
sudo systemctl enable httpd
So that's it. You have fully working Apache httpd in latest version installed on your system 🙂 This process might take some time, but you will have full control over httpd.
As always you can use our LampOnSteroids project (based on Ansible) to speed and automate everything up!