How to configure Apache httpd to serve dynamic database-driven web content
Most modern websites do not consist of purely static content. Most content served out is actually generated dynamically, on-demand. Integrating dynamic content with Apache HTTPD can be done in numerous ways. This section describes a number of the most common ways, but more ways exist.
COMMON GATEWAY INTERFACE
One of the oldest forms of generating dynamic content is by using Common Gateway Interface (CGI). When a CGI resource is requested, httpd does not simply read the resource and serve it out; instead, it executes the resource as a process, and serves the stdout of that process. Although CGI resources are mostly written in scripting languages like Perl, it is also quite common for CGI resources to be compiled C programs or Java executables.
Information from the request (including client information) is made available to the CGI program using environment variables.
Configuring httpd for CGI
To have httpd treat a location as CGI executables, the following syntax is used in the httpd configuration.
ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
This instructs httpd to redirect any request for files under the /cgi-bin/ URI to the /var/www/ cgi-bin/ directory, and treat the files in that directory as executable scripts.
A number of caveats exist when using CGI:
- CGI scripts will be executed as the apache user and group.
- CGI scripts should be executable by the apache user and group.
- CGI scripts should have the httpd_sys_script_exec_t SELinux context.
- The CGI directory should have Options None, and access should be granted using a normal <Directory> block.
Serving Dynamic PHP Content
A popular method of providing dynamic content is using the PHP scripting language. While PHP scripts can be served using old-fashioned CGI, both performance and security can be improved by having httpd run a PHP interpreter internally. By installing the php package, a special mod_php module is added to httpd. The default configuration for this module adds the following lines to the main httpd configuration:
<FilesMatch \.php$> SetHandler application/x-httpd-php <FilesMatch> DirectoryIndex index.php
The <FilesMatch> block instructs httpd to use mod_php for any file with a name ending in .php, and the DirectoryIndex directive adds index.php to the list of files that will be sought when a directory is requested.
Serving Dynamic Python Content
Also popular is generating dynamic content using Python scripts. Python scripts can be served out using regular CGI, but both python and httpd also support a newer protocol: Web Server Gateway Interface (WSGI).
WSGI support can be added to httpd by installing the mod_wsgi package.
Unlike the mod_php or CGI approach, WSGI does not start a new script/interpreter for every request. Instead, a main application is started, and all requests are routed into that application. Configuring httpd to support a WSGI application takes two steps:
1. Install the mod_wsgi package. 2. Add a WSGIScriptAlias line to a virtual host definition
The following is an example of a WSGIScriptAlias directive, which sends all requests for http://servername/myapp and any resources below it to the WSGI application /srv/myapp/www/myapp.py:
WSGIScriptAlias /myapp/ /srv/myapp/www/myapp.py
WSGI applications should be executable by the apache user and group, and their SELinux contexts should be set to httpd_sys_content_t.
Most web applications will need to store and retrieve persistent data. A common approach to this is to store the data in a database such as MariaDB or PostgreSQL. When the database is running on the same host as the web server, and the database is using a standard network port, SELinux will allow the network connection from the web application to happen.
When a database on a remote host is used, the SELinux Boolean httpd_can_network_connect_db must be set to 1 to allow the connection. When a network connection to another needs to be made from within the web application, and the target is not a well-known database port, the SELinux Boolean httpd_can_network_connect must be set to 1.
Various other SELinux Booleans can also affect the way in which web applications are executed by httpd.