server adminstration

Installing and setting up Apache in Ubuntu

published on
Apache
https://httpd.apache.org/

This post aims to cover how I will install typically install Apache. There will be things that you may decide to learn more about, change, update or even leave out.

My main reason for using Apache these days is that mod_security, mod_evasive and modpagespeed are all so easy to get set up. Other web servers either don't support this functionality or it is more difficult to install.

Install Apache

We will start by install Apache, mod_security and mod_evasive.

sudo add-apt-repository ppa:ondrej/apache2
sudo apt-get update
sudo apt-get install apache2 apache2-utils
sudo apt-get install libapache2-mod-security2 libapache2-mod-evasive
sudo a2enmod mime http2 rewrite deflate expires headers ssl

Install the firewall

sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw logging low
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable

Install PHP (if you need it)

This will install PHP 7.4 using the mpm_event module in Apache. If you want a different version of PHP change the version numbers in the following commands.

sudo apt-get install libapache2-mod-php7.4 libapache2-mod-fcgid
sudo a2enmod mpm_event
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php7.4-fpm
sudo systemctl restart php7.4-fpm

Modpagespeed

Modpagespeed is a module developed by Google for Apache and Nginx. It is quite old now but it still works well at helping to speed up your site as will be evidenced in Google Pagespeed.

It isn't perfect and only works with certain content but can be quite useful. If you want to include it in your Apache installation then do the following.

wget https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_amd64.deb
sudo dpkg -i mod-pagespeed-stable_current_amd64.deb
sudo apt-get -f install

Modpagespeed comes with a useful default configuration but if you do wish to change yours the configuration file can be found at /etc/apache2/mods-available/pagespeed.conf.

Setting up mod_security

This is a web application firewall (or WAF). It can help to protect your site from online threats. Tuning mod_security for your unique site is beyond the scope of this simple post and will be covered in Working with ModSecurity in the Apache web server.

Start by editing the configuration file

sudo mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
sudo nano /etc/modsecurity/modsecurity.conf

I like to leave it set to 'DetectionOnly' at first for a short time. I will then look through the logs to find which rules my site is tripping. I can then choose to make changes to my site to avoid these rules or disable these rules when I turn detection to 'on'. Before disabling any rules I will make sure I understand why the rule was being tripped and what the consequences of disabling it are.

Change the SecAuditLogParts ABDEFHIJZ line to read SecAuditLogParts ABCEFHJKZ. If you would prefer to have mod_security blocking immediately change the SecRuleEngine line to read SecRuleEngine On.

Install the rulesets

These are the rules that mod_security will use to decide whether to allow or block certain traffic.

wget https://github.com/coreruleset/coreruleset/archive/refs/tags/v3.3.2.tar.gz
tar xvf v3.3.2.tar.gz
sudo mkdir /etc/apache2/modsecurity-crs/
sudo mv coreruleset-3.3.2/ /etc/apache2/modsecurity-crs/
cd /etc/apache2/modsecurity-crs/coreruleset-3.3.2/
sudo mv crs-setup.conf.example crs-setup.conf
sudo nano /etc/apache2/mods-enabled/security2.conf

Find the IncludeOptional /usr/share/modsecurity-crs/*.load line, and replace it with the following two lines

IncludeOptional /etc/apache2/modsecurity-crs/coreruleset-3.3.2/crs-setup.conf
IncludeOptional /etc/apache2/modsecurity-crs/coreruleset-3.3.2/rules/*.conf

Set up logrotate

Create the /etc/logrotate.d/modsecurity file and add the following lines

{
 rotate 14
 daily
 missingok
 compress
 delaycompress
 notifempty
}

Now enable it

  sudo a2enmod security2

Setting up mod_evasive

Edit the configuration file at /etc/apache2/mods-enabled/evasive.conf and uncomment all the lines. Make sure to add your email address to the DOSEmailNotify line.

Now set up the directory necessary for the logs and enable the module

sudo mkdir /var/log/mod_evasive 
sudo chown -R www-data:www-data /var/log/mod_evasive
sudo a2enmod evasive

Restart the server

After making changes the server must be restarted

  sudo systemctl restart apache2

Apache should be set up to automatically start on reboot and run once installed. If it isn't run the following commands

sudo systemctl enable apache2
sudo systemctl start apache2

Update some configuration files

There are now a few files that we need to make changes to in order to secure your server and get your site online.

security.conf

Open the file at /etc/apache2/conf-enabled/security.conf and add, or modify, the following lines

ServerTokens Prod
ServerSignature Off
SecServerSignature " "
TraceEnable Off
Header unset Server
Header unset X-Powered-By
Header unset X-CF-Powered-By
Header unset X-Mod-Pagespeed
Header unset X-Pingback

Some of these may not be relevant to you so it is a good idea to research what each of these do before adding them.

php.ini

Edit your php.ini file which, for this tutorial, will be found at /etc/php/7.4/fpm/php.ini. Find the line expose_php = on and change it to expose_php = off.

apache2.conf

The apache2.conf file can be found at /etc/apache2/apache2.conf and I tend to use the one below initially

# This is the main Apache server configuration file.  It contains the
# configuration directives that give the server its instructions.
# See http://httpd.apache.org/docs/2.4/ for detailed information about
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
# hints.
#
# * apache2.conf is the main configuration file (this file). It puts the pieces
#   together by including all remaining configuration files when starting up the
#   web server.
#
# * ports.conf is always included from the main configuration file. It is
#   supposed to determine listening ports for incoming connections which can be
#   customized anytime.
#
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
#   directories contain particular configuration snippets which manage modules,
#   global configuration fragments, or virtual host configurations,
#   respectively.
#
#   They are activated by symlinking available configuration files from their
#   respective *-available/ counterparts. These should be managed by using our
#   helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
#   their respective man pages for detailed information.
#
# * The binary is called apache2. Due to the use of environment variables, in
#   the default configuration, apache2 needs to be started/stopped with
#   /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
#   work with the default configuration.


# Global configuration
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# Do NOT add a slash at the end of the directory path.
#
#ServerRoot "/etc/apache2"

Mutex file:${APACHE_LOCK_DIR} default

PidFile ${APACHE_PID_FILE}

Timeout 120
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 10

# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}

HostnameLookups Off

ErrorLog ${APACHE_LOG_DIR}/error.log

LogLevel warn

# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf

# Include list of ports to listen on
Include ports.conf

<Directory />
 Options None
 AllowOverride None
 Require all denied
</Directory>

<Directory /usr/share>
 AllowOverride None
 Require all granted
</Directory>

<Directory /var/www/>
 Options -Indexes +FollowSymLinks
 AllowOverride None
 Require all granted
</Directory>

#<Directory /srv/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>

AccessFileName .htaccess
<FilesMatch "^\.ht">
 Require all denied
</FilesMatch>

Header unset ETag
FileETag None

LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf

# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf

ServerName 127.0.0.1

Apache virtual host configuration

Before a site can appear online it needs a virtual host configuartion file. Initially I will disable the default one (which only needs doing once and then set up the necessary directories before adding the actual configuration settings.

Remember that were you see [domain] you should replace it with your own domain name (e.g. example.com).

sudo a2dissite 000-default.conf
sudo mkdir /var/www/[domain]
sudo chown -R www-data:www-data /var/www/[domain]
sudo chmod -R 755 /var/www/[domain]

Now create the virtual host file and add the following lines

sudo nano /etc/apache2/sites-available/[domain].conf
<VirtualHost *:80>
   ServerAdmin [email address]
   ServerName www.[domain]
   ServerAlias [domain]
   DocumentRoot /var/www/[domain]

   # enable HTTP/2, if available
   Protocols h2 http/1.1

   SetEnv TZ Europe/London
   AddDefaultCharset UTF-8
   DefaultLanguage en
   FileETag none

   # if site uses PHP then put index.php first; if site is static only don't include index.php at all
   DirectoryIndex index.html index.php

   ErrorLog ${APACHE_LOG_DIR}/[domain]-error.log
   CustomLog ${APACHE_LOG_DIR}/[domain]-access.log combined

   # Set values to match what you need
   <Directory /var/www/[domain]>
      Options +SymLinksIfOwnerMatch -MultiViews -Indexes -Includes -ExecCGI
      AllowOverride All
      Require all granted
   </Directory>

   # if custom error pages are needed add a new line per error code
   # using the example as a guide
   # e.g. ErrorDocument [error code] [filename]

   #if using Cloudflare or other proxy then uncomment the following line
   #RemoteIPHeader CF-Connecting-IP

   # if using PHP then uncomment the following three lines and update to relevant version
   #<FilesMatch \.php$>
   #   SetHandler "proxy:unix:/var/run/php/php7.4-fpm.sock|fcgi://localhost"
   #</FilesMatch>

   # set up cache times - HTML and CSS not cached by these settings
   # add them below if they won't be updated often
   <FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|swf)$">
      # 2592000 = one month
      Header set Cache-Control "max-age=2592000, public"
   </FilesMatch>

    # some of these will need there own unique settings depending on what the site needs
    Header set X-XSS-Protection "1; mode=block"
    Header set X-Content-Type-Options nosniff
    Header set X-Frame-Options DENY
    Header set Referrer-Policy: no-referrer
    Header set X-Permitted-Cross-Domain-Policies "none"
    Header set Content-Security-Policy "default-src 'self';"
    Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
    Header set X-Download-Options "noopen"
    Header set Permissions-Policy "fullscreen=(self)"  
    Header set Access-Control-Allow-Origin *
    # The following line is an example only
    # and allows the use of Google Fonts
    #Content-Security-Policy default-src 'self'; style-src 'self' fonts.googleapis.com; font-src fonts.gstatic.com
    # or use the below if your site doesn't connect to anything else
    ###Header set Content-Security-Policy "default-src 'self';"
</VirtualHost>

Some things to note:

  • [email address] and [domain] should be replaced by your site email address and domain name.
  • The default language and timezone may need changing depending on where you live.
  • Some of the cache settings may not work for you. Make sure to change them to something more suitable.
  • The headers may not be suitable for your site either. You should make sure to read up about them before using them.

Make sure to enable your site with sudo a2ensite [domain].conf and restart Apache using sudo systemctl restart apache2. If you need to test your configuration to see if it works try sudo apache2ctl configtest.

Finishing off the virtual host configuration

Now that the initial virtual host has been created we want to create a version that is secured with a SSL certificate.

Start by installing certbot

sudo apt-get install snapd
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Now install a certificate for your site

sudo certbot -d [domain] -d www.[domain] --apache

Once you have answered a few questins your certificate should be installed. Certbot will craete a new configuration file and add a few lines to the one you created above to redirect visitors to the secure version of your site.

Open the new configuration file called [domain]-le-ssl.conf and add the following lines

SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite        ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder     off
SSLSessionTickets       off
SSLUseStapling On
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"

Finally make sure to restart Apache using sudo systemctl restart apache2.

Final notes

There are quite a few things that can be changed or left out of this configuration. Doing it this way I can make sure that the site is pretty secure when I get it online. However, it will be useful for you to research what different parts do and whether you need them or not.

All that should be left for you to do now is upload your site to /var/www/[domain] and begin sharing it with the world.