This file contains the Apache Server installation section of my personal guide to set up an Ubuntu server. The introduction to this guide as well as its full Table of Contents can be found on the README.md file of this repository. The Table of Contents of this section is listed below.
-
Software Installation
- Apache Server installation
- Install Apache
- Set up the firewall
- Check the Apache Server
- Change the Apache Server web root folder
- Set up the default directory to be served by Apache Web Server
- Set permissions for the Apache Server root folder
- Keep the Apache Server root folder access permissions consistent with a cron job
- Install & Configure ModSecurity
- Apache Server installation
Install the Apache Server with the following commands:
sudo apt update && sudo apt install apache2
To confirm that the installation was successful and to get the installed Apache Server version, execute the following command:
apache2 -vList the ufw application profiles wit the following command:
sudo ufw app listCheck the firewall status with the following command:
sudo ufw statusEnable the ufw profile that opens both port 80 (normal, unencrypted web traffic) and port 443 (TLS/SSL encrypted traffic) with the following command:
sudo ufw allow 'Apache Full'Check again the firewall status with the following command:
sudo ufw statusCheck if the Apache Server service is active with the following command:
sudo systemctl status apache2.service -l --no-pagerIf the Apache AH00558 configuration error is shown, it's necessary to edit the configuration
file /etc/apache2/apache2.conf. Open the file with the following command:
sudo nano /etc/apache2/apache2.confWithin this file, use the command CTRL + W to search for the directive ServerName. If it isn't
present, as instructed on this Digital Ocean Tutorial,
add to the bottom of the file the following snippet:
# Fix the Apache AH00558 configuration error
ServerName localhost
Save the changes with the command CTRL + O and then exit the
nano text editor with the command CTRL + X.
After making the above-mentioned modifications in the Apache Server configuration, validate it with the following command:
sudo apachectl configtestIf everything is correct, make the changes effective, running the following command:
sudo systemctl restart apache2Check if the Apache Server service is active with the following command:
sudo systemctl status apache2.service -l --no-pagerTo check if Apache Server is running correctly, replace the placeholder in the below URL as appropriate and enter it into a browser’s address bar.
http://{SERVER_IP_ADDRESS}/
Palceholder Definition
- {SERVER_IP_ADDRESS} : IP Address of the server that can be obtained with the command
hostname -Ior the commandcurl -4 icanhazip.com
By default, the Apache Server root folder (where the
Virtual Hosts are stored) is the folder /var/www/
but I prefer to use the folder /srv/www/ instead. To create this folder,
execute the following commands:
sudo mkdir /srv/wwwCheck the output of the below command to verify that the folder was properly created.
ls --group-directories-first -la /srv/The file /etc/apache2/apache2.conf must be edited to allow the Apache Server to access
the folder /srv/www/. Use the nano text editor to edit the file
apache2.conf with the following command:
sudo nano /etc/apache2/apache2.confWithin the file, use the command CTRL + W to search for the <Directory directives and comment
out the /var/www/ folder directive. When finished, it must look like the below snippet.
#<Directory /var/www/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>
And then add the following directive:
<Directory /srv/www/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
In the above directive, AllowOverride is set to All to allow .htaccess files
in the virtual hosts.
Still within the file /etc/apache2/apache2.conf, add the bellow snippet immediately
after the ServerName directive.
# Configure the DocumentRoot directive
DocumentRoot /srv/www
After introducing all the changes, save the file with the command CTRL + O and then exit
the nano text editor with the command CTRL + X.
Validate the Apache Server configuration with the following command:
sudo apachectl configtestIf everything is correct, make the changes effective, running the following command:
sudo systemctl restart apache2Check if the Apache Server service is active with the following commands:
sudo systemctl status apache2.service -l --no-pager
apachectl -SThe directory /srv/www will be used as parent directory of all Virtual Hosts on the server,
but the directory /var/www/html will be moved to /srv/www/ to serve as the default directory
that is served if a client request doesn’t match any other sites.
Disable the Apache Server default Virtual Host, with the following commands:
sudo a2dissite 000-default.conf
sudo systemctl restart apache2Copy the content of the Apache Server default server block to the folder /srv/www
with the following command:
sudo rsync -av /var/www/html /srv/wwwTo back up the default Virtual Host configuration file, execute the following command:
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-default.conf.originalStart editing the Apache Server default Virtual Host configuration file with the following command:
sudo nano /etc/apache2/sites-available/000-default.confReplace the placeholder* in the below snippet as appropriate and use it to replace the existing directives in the default Virtual Host configuration file.
ServerAdmin {SERVER_ADMIN_EMAIL}
DocumentRoot /srv/www/html
Placeholder Definition
- {SERVER_ADMIN_EMAIL} : The server's admin e-mail
After introducing all the changes, save the file with the command CTRL + O and then exit
the nano text editor with the command CTRL + X.
Validate the Apache Server configuration with the following command:
sudo apachectl configtestEnable the default Virtual Host configuration file with the following commands:
sudo a2ensite 000-default.conf
sudo systemctl restart apache2Check if the Apache Server service is active with the following command:
sudo systemctl status apache2.service -l --no-pagerTo check if Apache Server is running correctly, replace the placeholder in the below URL as appropriate and enter it into a browser’s address bar.
http://{SERVER_IP_ADDRESS}/Placeholder Definition
- {SERVER_IP_ADDRESS} : IP Address of the server that can be obtained with the command
hostname -Ior the commandcurl -4 icanhazip.com
To customize Apache Server default landing page, download the custom index.html file to
/srv/www/html with the following command:
sudo wget -O /srv/www/html/index.html https://raw.githubusercontent.com/EnduranceCode/server-setup-guide/master/system/srv/www/html/index.htmlTo check if the Apache Server default landing page was set correctly, replace the placeholder in the below URL as appropriate and enter it into a browser’s address bar.
http://{SERVER_IP_ADDRESS}/
Placeholder Definition
- {SERVER_IP_ADDRESS} : IP Address of the server that can be obtained with the command
hostname -Ior the commandcurl -4 icanhazip.com
The default owner and group of Apache Server root folder is root:root and that is fine
if the server is only serving static content. But, if server is intended to serve dynamic content,
this needs to be changed. There's no absolute right way to set this configurations but
this answer on ServerFault
and this other answer on SuperUser
were taken in consideration to set my own configuration.
A good solution for this problem is to use the Apache Server user and group as the owner
and group of the server web root folder. On Ubuntu, the Apache Server user and group
is www-data. Check the output of the below command to get the user and group
of the Apache Server.
apachectl -SAssuming that www-data is indeed the user that runs Apache Server, set the owner
and group of the Apache Server root folder to www-data with the following command:
sudo chown -R www-data:www-data /srv/wwwSet the file permissions for the server root folder with the following commands:
sudo find /srv/www -type d -exec chmod -c 2755 {} +
sudo find /srv/www -type f -exec chmod -c 644 {} +The umask has to be set accordingly the permissions level set with above command,
therefore it must be set to 022. To check the current umaskvalue, execute the following command:
umaskTo permanently set the umask value
system-wide, open the /etc/profile file with nano text editor
using the following command:
sudo nano /etc/profileWithin /etc/profile file, add the below snippet at the beginning of the file.
umask 022To make the modifications effective, execute the following commands:
source /etc/profile
source ~/.bashrcTo verify if the new umask settings are working as intended, execute the below commands to create
a new file and a new directory and then check its listed permissions.
mkdir /tmp/newfolder
touch /tmp/newfile
ls --group-directories-first -la /tmpWith the standard permissions for the Apache Server root folder set as described above,
a regular user won't have writing permissions on the Apache Server root folder. To give a user
writing permissions on the Apache Server root folder it's now necessary to add the user to the
www-data group. Replace the placeholder in the below command as appropriate and then execute it:
sudo usermod -aG www-data {USER}Label Definition
- {USER} : The user account to be added to the
www-datagroup
As explained in this answer on StackExchange, changes to the user's group membership only takes effect when the user logs in. So the user needs to log out and log back in to make these modifications effective. If it is really necessary to force the previous group assignment to take effect without logging out, use the trick explained on this answer on StackExchange and execute the below commands. Otherwise, just logout the server and log back in.
newgrp www-data
newgrp $USERThen, add writing permissions to the group of the Apache Server root folder with the following commands:
sudo find /srv/www -type d -exec chmod -c 2775 {} +
sudo find /srv/www -type f -exec chmod -c 664 {} +The umask has to be set accordingly the permissions level set with above command,
therefore it must be set to 002. To check the current umaskvalue, execute the following command:
umaskTo permanently set the umask value
system-wide, open the /etc/profile file with nano text editor
using the following command:
sudo nano /etc/profileWithin /etc/profile file, add the below snippet at the beginning of the file.
umask 002For the changes to take effect, execute the following commands:
source /etc/profile
source ~/.bashrcTo verify if the new settings are working as intended, execute the below commands to create a new file and a new directory and then check its listed permissions.
mkdir /tmp/newfolder
touch /tmp/newfile
ls --group-directories-first -la /tmpOver the time, there will be some inconsistencies on the permissions of the Apache Server root
folder. On the folder system/usr/local/bin of this repository there are two scripts
(fixApacheWebRootPermissions.sh
and cronJobFixApacheWebRootPermissions.sh) that resets the chosen permissions
on the Apache Server root folder.
To download and make these scripts executable and available on the system
start by downloading it to the /usr/local/bin folder with the following commands:
sudo wget -P /usr/local/bin/ https://raw.githubusercontent.com/EnduranceCode/server-setup-guide/master/system/usr/local/bin/fixApacheWebRootPermissions.sh
sudo wget -P /usr/local/bin/ https://raw.githubusercontent.com/EnduranceCode/server-setup-guide/master/system/usr/local/bin/cronJobFixApacheWebRootPermissions.shTo check if the files were properly copied, check the output of the following command:
ls --group-directories-first -la /usr/local/bin/The file /usr/local/bin/fixApacheWebRootPermissions.sh will probably need some modifications
to ensure its compatibility with the desired Apache Server root folder permissions.
Use the below command to open the file fixApacheWebRootPermissions.sh
with the nano text editor.
sudo nano /usr/local/bin/cronJobFixApacheWebRootPermissions.shCheck if the script is correct, make all the needed (if any) modifications and then save the file
with the command CTRL + O and exit the nano text editor
with the command CTRL + X.
Repeat the previous process for the file /usr/local/bin/cronJobFixApacheWebRootPermissions.sh
with the following command:
sudo nano /usr/local/bin/cronJobFixApacheWebRootPermissions.shMake these scripts executable with the following commands:
sudo chmod +x /usr/local/bin/fixApacheWebRootPermissions.sh
sudo chmod +x /usr/local/bin/cronJobFixApacheWebRootPermissions.shCheck the output of the below command to confirm that the files were properly made executable.
ls --group-directories-first -la /usr/local/bin/If everything was properly set, both scripts are available to be executed from anywhere in the system.
With these two scripts made executable, it's time to create a cronjob to automate the execution of the script (cronJobFixApacheWebRootPermissions.sh) everyday at 3:00. Edit the root's crontab with the following command:
sudo crontab -eThe above command will open a text editor in the terminal. Append the below snippet to the file opened with the previous command.
#
#
# Daily fix of the Apache's root folder permissions
0 3 * * * /usr/local/bin/cronJobFixApacheWebRootPermissions.sh
After checking that the added commands are correct and well suited for the system, save and close the file. To list the cron jobs created, execute the following command:
sudo crontab -lInstall the Apache ModSecurity module:
sudo apt update
sudo apt install libapache2-mod-security2Enable the ModSecurity module:
sudo a2enmod security2Restart Apache to apply the changes into effect:
sudo systemctl restart apache2Check if the module is loaded:
apachectl -M | grep securityIf the output prints security2_module, it indicates that ModSecurity has been successfully
installed and enabled.
By default, ModSecurity runs in a passive "DetectionOnly" mode, so we need to set it to blocking mode:
sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.confEdit file /etc/modsecurity/modsecurity.conf with the
nano text editor to set ModSecurity to blocking mode:
sudo nano /etc/modsecurity/modsecurity.confWithin the file, use the command CTRL + W to search for the SecRuleEngine directive and change
its value from DetectionOnly to On. When finished, it must look like the following snippet:
SecRuleEngine On
After introducing all the changes, save the file with the command CTRL + O and then exit the
nano text editor with the command CTRL + X.
While the default package installation may include an old version of CRS, it is safer to use
the files provided by the OWASP CRS Project and available at the
OWASP CRS repository. Move to folder
/etc/modsecurity/ and clone the repository:
cd /etc/modsecurity/
sudo git clone https://github.com/coreruleset/coreruleset.gitCopy and rename the repository's example configuration file so ModSecurity knows to load it:
sudo cp /etc/modsecurity/coreruleset/crs-setup.conf.example /etc/modsecurity/coreruleset/crs-setup.confTo ensure that Apache is instructed to load the main ModSecurity configuration (modsecurity.conf),
the new CRS setup file (crs-setup.conf) and all the individual attack rules (rules/*.conf), edit
the file /etc/modsecurity/modsecurity.conf with the
nano text editor:
sudo nano /etc/apache2/mods-enabled/security2.confWithin the file, use the command CTRL + W to search for the block
and update its content in order to look like the following snippet:
<IfModule security2_module>
# Default Debian dir for modsecurity's persistent data
SecDataDir /var/cache/modsecurity
# Include the main ModSecurity configuration
IncludeOptional /etc/modsecurity/modsecurity.conf
# CRITICAL: Include the CRS setup file FIRST
IncludeOptional /etc/modsecurity/coreruleset/crs-setup.conf
# CRITICAL: Include all the actual attack rules
IncludeOptional /etc/modsecurity/coreruleset/rules/*.conf
</IfModule>
Note: Remove (or comment) the previous
IncludeOptionallines that point to the default package CRS rules and configuration
After introducing all the changes, save the file with the command CTRL + O and then exit the
nano text editor with the command CTRL + X.
The crs-setup.conf file available defines several Paranoia Levels that determines
how aggressively the CRS blocks traffic. To start low and increase slowly, edit the file
crs-setup.conf with the nano text editor:
sudo nano /etc/modsecurity/coreruleset/crs-setup.confWithin the file, use the command CTRL + W to search for the rule tx.blocking_paranoia_level
and uncomment it to set the Paranoia Level 1. It should be similar to the following snippet:
SecAction \
"id:900000,\
phase:1,\
pass,\
t:none,\
nolog,\
tag:'OWASP_CRS',\
ver:'OWASP_CRS/4.22.0-dev',\
setvar:tx.blocking_paranoia_level=1"
Use the command CTRL + W to search for the rule tx.allowed_methods and uncomment it. The rule
should be similar to the following snippet:
SecAction \
"id:900200,\
phase:1,\
pass,\
t:none,\
nolog,\
tag:'OWASP_CRS',\
ver:'OWASP_CRS/4.22.0-dev',\
setvar:'tx.allowed_methods=GET HEAD POST OPTIONS'"
Note: If necessary, edit the list for the tx.allowed_methods variable
Use the command CTRL + W to search for the rule tx.max_num_args and uncomment it. The rule
should be similar to the following snippet:
SecAction \
"id:900300,\
phase:1,\
pass,\
t:none,\
nolog,\
tag:'OWASP_CRS',\
ver:'OWASP_CRS/4.22.0-dev',\
setvar:tx.max_num_args=255"
Use the command CTRL + W to search for the rule tx.arg_length and uncomment it. The rule
should be similar to the following snippet:
SecAction \
"id:900320,\
phase:1,\
pass,\
t:none,\
nolog,\
tag:'OWASP_CRS',\
ver:'OWASP_CRS/4.22.0-dev',\
setvar:tx.arg_length=400"
Use the command CTRL + W to search for the rule tx.total_arg_length and uncomment it. The rule
should be similar to the following snippet:
SecAction \
"id:900330,\
phase:1,\
pass,\
t:none,\
nolog,\
tag:'OWASP_CRS',\
ver:'OWASP_CRS/4.22.0-dev',\
setvar:tx.total_arg_length=64000"
Use the command CTRL + W to search for the rule tx.max_file_size and uncomment it. The rule
should be similar to the following snippet:
SecAction \
"id:900340,\
phase:1,\
pass,\
t:none,\
nolog,\
tag:'OWASP_CRS',\
ver:'OWASP_CRS/4.22.0-dev',\
setvar:tx.max_file_size=1048576"
Note: If necessary, edit the value for the tx.max_file_size variable
Use the command CTRL + W to search for the rule tx.combined_file_sizes and uncomment it.
The rule should be similar to the following snippet:
SecAction \
"id:900350,\
phase:1,\
pass,\
t:none,\
nolog,\
tag:'OWASP_CRS',\
ver:'OWASP_CRS/4.22.0-dev',\
setvar:tx.combined_file_sizes=1048576"
Note: If necessary, edit the value for the tx.combined_file_sizes variable
Go through the rest of the configuration, with special care on the HTTP Policy Settings, and, if necessary, change the defaults to comply with the server's traffic requirement.
After introducing all the changes, save the file with the command CTRL + O and then exit the
nano text editor with the command CTRL + X.
Test the configuration syntax:
sudo apachectl configtestIf you see errors, double-check the file paths and the other modifications made in the previous steps. If you see Syntax OK, proceed and restart the Apache web server:
sudo systemctl restart apache2Replace the placeholders in the below command as appropriate and verify if ModSecurity is functioning as intended:
curl -I {URL}/?test='1+OR+1=1'Placeholder Definition
- {URL} : The domain served by the Apache Server;