main.append(addHeader("Where is Apache's Configuration"))
main.append(addParagraph("The primary documentation describing how to configure Apache can be found at <a href=\"http://httpd.apache.org/docs/current/configuring.html\">apache.org</a>."))
main.append(addParagraph("Ubuntu and CentOS (or I should really say Debian and RedHat) take a slightly different approach to configuration. Both have a major configuration file, but Ubuntu is more modular and more of the configuration is found in other files. This is summarised in the image below."))
main.append(addImageWithCaption("./images/image6.png","RedHat and Ubuntu - different approaches to configuration of Apache"))
main.append(addParagraph("The main configuration file can also specify additional configuration files."))
main.append(addParagraph("On most systems, you will find the configuration file in the default location which, for Ubuntu, is"))
main.append(addParagraph("The location is set at compile time but it is also possible, though not common, to override the location when starting the server. That is, on startup, you can tell the server to look elsewhere for the configuration file."))
main.append(addParagraph("If you are trying to work out where the config file is, it makes sense to start by looking in the default location, but we can also use apachectl to help locate it by using the command"))
main.append(addSyntax("apachectl -V"))
main.append(addParagraph("This should give you output similar to the following:"))
main.append(addImageWithCaption("./images/screen8.png","The output from the apachectl -v command."))
main.append(addParagraph("The location is given under HTTPD_ROOT with the name of the file given as SERVER_CONFIG_FILE and together they give"))
main.append(addParagraph("would search every location on the Ubuntu machine and return anything that matches the pattern. This does tend to give quite a few results as shown below."))
main.append(addImageWithCaption("./images/screen9.png","The results from searching for apache2.conf with the command sudo find / | grep apache2.conf"))
main.append(addParagraph("Simliarly, we can issue a similar command to look for httpd.conf, if we are using a RedHat-based system and the results are similar too."))
main.append(addImageWithCaption("./images/screen10.png","The results from searching for httpd.conf with the command sudo find / | grep httpd.conf on a RedHat system."))
main.append(addParagraph("Note that in the search terms on both machines, we escaped the dot character which makes sense, but doesn't seem to have any effect. On the Ubuntu, I ran the command with the dot escaped and then not escaped and returned 21 results both times. On the CentOS machine, I got 22 results with and without the escape on the dot."))
main.append(addHeader("Apache Directives and Arguments"))
main.append(addParagraph("The Apache configuration file is a plain text file containing a series of directives. Typically, a directive takes one argument which is the setting. For example"))
main.append(addSyntax("ServerName apache"))
main.append(addParagraph("sets the name of the server to apache. We can say that this is the ServerName directive and it has a value of apache. Note that the directive name is case-insensitive but in most cases (pardon the pun) the argument is case-sensitive so it is considered best practice to treat everything as being case-sensitive."))
main.append(addParagraph("There is also a verbose description of the file at the start and this also provides the URL for the online documentation. The online documentation provides examples of usage, default and acceptable values for the directives. To demonstrate this, I will search for the directive, DocumentRoot in the documentation. A full list of these is provided at <a href=\"http://httpd.apache.org/docs/current/mod/directives.html\">apache.org</a>."))
main.append(addParagraph("We can scroll down or search in the page to find the DocumentRoot directive and click the link. This leads to the following."))
main.append(addImageWithCaption("./images/screen11.png","Part of the documentation for the DocumentRoot Directive from apache.org."))
main.append(addParagraph("If we look in the apache2.conf file, we will not find this directive. Recall that RedHat distros tend to have everything in the main config file, but Debian distros tend to have additional config files so we may need to search for a specific directive."))
main.append(addParagraph("We can be fairly sure that it will be in the /etc/apache2 directory or a subdirectory, so we can cd into this directory and search from there with"))
main.append(addSyntax("grep -Ri documentroot ."))
main.append(addParagraph("This gives the following results"))
main.append(addParagraph("We can see that there are 4 results in files found in the sites-enabled and sites-available directories. It may be worth noting that grep filters by line so what we are seeing returned here is the filename and the line that contains the search term."))
main.append(addParagraph("We can see this if we look at the 000-default.conf file, for example, which includes the line"))
main.append(addParagraph("Remember that the default web page served up on the Ubuntu machine is Alice's Adventures in Wonderland, so there is a fair chance that the config for this site is in the alice.conf directory. We can check the contents of that directory with "))
main.append(addSyntax("ls -la /srv/web"))
main.append(addParagraph("There is one file there, index.html, and if we inspect this with"))
main.append(addSyntax("vim /srv/web/index.html"))
main.append(addParagraph("we can see this is the html file containing that text. "))
main.append(addHeader(".htaccess files for Access and Configuration"))
main.append(addParagraph("The .htaccess files provide directory level configuration that supplement the main config file. They were originally intended to provide authentication security for directories, as the name suggests, but they can also override and extend the configuration settings. "))
main.append(addParagraph("They are read for every request so if you update them, you don't need to restart Apache. They can give greater flexibility for underprivileged users who can't access the main config file, but may want to deny access or make minor changes in their own folder. "))
main.append(addParagraph("They can be a security risk and they are slower to load than a system that uses only the main configuration, so their use is not recommended. "))
main.append(addHeader("Anatomy of a Virtual Host"))
main.append(addParagraph("Apache provides two types of virtual hosting"))
main.append(addSubHeader("Name based hosting"))
main.append(addInsetBulletList(["Routes requests based on the domain names applied by the client (usually the browser)","This is the easiest type to implement","It can cause problems with the SSL certificate as the server doesn't know which certificate to be using"]))
main.append(addSubHeader("IP based hosting"))
main.append(addInsetBulletList(["Requires a separate ip address for each site which makes it more expensive","It does solve the SSL problem"]))
main.append(addParagraph("It might be helpful to look at an example so let's take a look at the configuration for the alice website, as shown in the image below."))
main.append(addParagraph("The first line is a directive that confirms this is a virtual host and it includes an IP address so it is an IP-based virtual host and it is listening on port 80. This can also be a fully qualified domain name but that's not recommended."))
main.append(addParagraph("The server admin directive sets the email address to which any error messages returned to the client are sent. This is optional and you might omit it if, for example, you are using custom error messages and perhaps you don't want to expose contact information to the outside world."))
main.append(addParagraph("The server name is usually set globally, but it is very important for a virtual host since this uniquely identifies this particular host, and in this example, it is alice.example.com."))
main.append(addParagraph("There are several config options in the Directory directive and note that this takes the sites directory as an argument, you may recall that /srv/web is where we store the files for the Alice site."))
main.append(addInsetBulletList(["Order - controls the default access site and defines the order in which allow and deny directives are evaluated.","Allow from all - access is allowed from all but this could also be from a specific host name, IP address or even an environment variable.","Require all granted - grants all users unconditional access."]))
main.append(addParagraph("The first two are deprecated in Apache 2.4 but are very common and are included here for compatibility. These directory permissions are very important. If they are missing, Apache will be unable to determine what permissions to grant a user and will not serve any content from this directory."))
main.append(addParagraph("At the bottom, we have the DocumentRoot and again, this is the directory from which Apache will be serving content."))
main.append(addParagraph("We can test the syntax of our site using"))
main.append(addSyntax("apachectl -t"))
main.append(addParagraph("If there are no errors, we will see a message"))
main.append(addSyntax("Syntax OK"))
main.append(addParagraph("We can also use apachectl -t to check the configuration of our virtual hosts using the syntax."))
main.append(addParagraph("If everything is configured correctly, we should see output similar to that shown below."))
main.append(addImageWithCaption("./images/image8.png","The output from apachectl -t -D DUMP_VHOSTS"))
main.append(addParagraph("This is showing the IP address and the server name and also confirms the file name containg the configuration for this host and even the line number that it starts on."))
main.append(addParagraph("The course doesn't really cover setting up name based Virtual Hosts, but you can get some useful guidance on how to do that along with a sample config file on the Apache HTTP Server Project website under <a href=\"https://httpd.apache.org/docs/2.4/vhosts/examples.html\">VirtualHost Examples</a>."))
main.append(addHeader("What are Modules, and Why Use Them?"))
main.append(addParagraph("Apache (or HTTPD) is a modular web server and a lot of its functionality comes from modules that may have been included with the base installation or may have been added later."))
main.append(addParagraph("Static modules are compiled and are loaded when apache starts up. Shared modules are more dynamic and can be added without recompiling the core server and can be loaded while it is running. This means that static modules are a little faster but shared modules are more flexible and can be, in effect, turned on or off as required."))
main.append(addParagraph("Modules have their own configuration directives. Note that if Apache detects module directives for a module that it cannot locate, this can prevent the server from starting. That is, if the module configuration is conditional on the module being available, the server can still start without that module, if it isn't conditional, the server won't start."))
main.append(addParagraph("To make it conditional, the module directive needs to be wrapped in an IfModule like this"))
main.append(addParagraph("Running this on my web server gives the following results."))
main.append(addImageWithCaption("./images/screen12.png","Getting a list of apache modules on my Raspberry Pi"))
main.append(addParagraph("There are more than two dozen modules there and we can see which modules are static (the first 8 in the list) and which modules are shared. In order to switch a shared module on or off, we do that via its configuration directives."))
main.append(addParagraph("How that is done can vary between systems, particularly between Debian and RedHat systems so we will look at how to do that on Ubunutu (a Debian system). In a Debian-based system, the module configuration is located in the following directories."))
main.append(addParagraph("On my web server, there are 32 listed in mods-enabled (these are not actual files but symbolic links to the files in the mods-available folder), so this is a few more than actually seem to be available from the list we saw earlier. As you might expect, there are more in the mods-available folder and we have 144 files there."))
main.append(addParagraph("We are going to look at a specific module, the status module. In the mods-available folder, we have these files relating to the status module."))
main.append(addParagraph("The configuration starts with IfModule so the server would still be able to start even if the module couldn't be found. We also have a location directive which limits the scope of the configuration by the URL path."))
main.append(addParagraph("To disable the module, we can make use of one of two commands available in Debian."))
main.append(addSyntax("• a2enmod - creates a symbolic link from the mods-available to the mode-enabled directory"))
main.append(addSyntax("• a2dismod - removes a symbolic link from the mode-enabled directory"))
main.append(addParagraph("We want to disable the module so we will use the second of these commands."))
main.append(addSyntax("sudo a2dismod status"))
main.append(addParagraph("Since this affects the functionality of the server, we need to restart apache with"))
main.append(addParagraph("If we then look at the contents of the mods-enabled directory, we can see that status.conf and status.load are no longer there. We can also try using the module."))
main.append(addSyntax("apachectl status"))
main.append(addParagraph("This will give us an error message."))
main.append(addInsetList(["philip@raspberrypi:/etc/apache2/mods-enabled $ apachectl status","/usr/sbin/apachectl: 113: www-browser: not found","'www-browser -dump http://localhost:80/server-status' failed.","Maybe you need to install a package providing www-browser or you","need to adjust the APACHE_LYNX variable in /etc/apache2/envvars"]))
main.append(addParagraph("We can re-enable the status mod with"))