apache

Table of Contents

  1. Module description - What is the apache module, and what does it do?
  2. Setup - The basics of getting started with apache
  3. Usage - The classes and defined types available for configuration
  4. Reference - An under-the-hood peek at what the module is doing and how
  5. Limitations - OS compatibility, etc.
  6. Development - Guide for contributing to the module

Module description

Apache HTTP Server (also called Apache HTTPD, or simply Apache) is a widely used web server. This Puppet module simplifies the task of creating configurations to manage Apache servers in your infrastructure. It can configure and manage a range of virtual host setups and provides a streamlined way to install and configure Apache modules.

Setup

What the apache module affects:

  • Configuration files and directories (created and written to)
    • WARNING: Configurations not managed by Puppet will be purged.
  • Package/service/configuration files for Apache
  • Apache modules
  • Virtual hosts
  • Listened-to ports
  • /etc/make.conf on FreeBSD and Gentoo

On Gentoo, this module depends on the gentoo/puppet-portage Puppet module. Note that while several options apply or enable certain features and settings for Gentoo, it is not a supported operating system for this module.

Warning: This module modifies Apache configuration files and directories and purges any configuration not managed by Puppet. Apache configuration should be managed by Puppet, as unmanaged configuration files can cause unexpected failures.

To temporarily disable full Puppet management, set the purge_configs parameter in the apache class declaration to false. We recommend this only as a temporary means of saving and relocating customized configurations.

Beginning with Apache

To have Puppet install Apache with the default parameters, declare the apache class:

class { 'apache': }

When you declare this class with the default options, the module:

  • Installs the appropriate Apache software package and required Apache modules for your operating system.
  • Places the required configuration files in a directory, with the default location Depends on operating system.
  • Configures the server with a default virtual host and standard port ('80') and address ('*') bindings.
  • Creates a document root directory Depends on operating system, typically /var/www.
  • Starts the Apache service.

Apache defaults depend on your operating system. These defaults work in testing environments but are not suggested for production. We recommend customizing the class's parameters to suit your site.

For instance, this declaration installs Apache without the apache module's default virtual host configuration, allowing you to customize all Apache virtual hosts:

class { 'apache':
  default_vhost => false,
}

Note: When default_vhost is set to false, you have to add at least one apache::vhost resource or Apache will not start. To establish a default virtual host, either set the default_vhost in the apache class or use the apache::vhost defined type. You can also configure additional specific virtual hosts with the apache::vhost defined type.

Usage

Configuring virtual hosts

The default apache class sets up a virtual host on port 80, listening on all interfaces and serving the docroot parameter's default directory of /var/www.

To configure basic name-based virtual hosts, specify the port and docroot parameters in the apache::vhost defined type:

apache::vhost { 'vhost.example.com':
  port    => '80',
  docroot => '/var/www/vhost',
}

See the apache::vhost defined type's reference for a list of all virtual host parameters.

Note: Apache processes virtual hosts in alphabetical order, and server administrators can prioritize Apache's virtual host processing by prefixing a virtual host's configuration file name with a number. The apache::vhost defined type applies a default priority of 25, which Puppet interprets by prefixing the virtual host's file name with 25-. This means that if multiple sites have the same priority, or if you disable priority numbers by setting the priority parameter's value to false, Apache still processes virtual hosts in alphabetical order.

To configure user and group ownership for docroot, use the docroot_owner and docroot_group parameters:

apache::vhost { 'user.example.com':
  port          => '80',
  docroot       => '/var/www/user',
  docroot_owner => 'www-data',
  docroot_group => 'www-data',
}

Configuring virtual hosts with SSL

To configure a virtual host to use SSL encryption and default SSL certificates, set the ssl parameter. You must also specify the port parameter, typically with a value of '443', to accommodate HTTPS requests:

apache::vhost { 'ssl.example.com':
  port    => '443',
  docroot => '/var/www/ssl',
  ssl     => true,
}

To configure a virtual host to use SSL and specific SSL certificates, use the paths to the certificate and key in the ssl_cert and ssl_key parameters, respectively:

apache::vhost { 'cert.example.com':
  port     => '443',
  docroot  => '/var/www/cert',
  ssl      => true,
  ssl_cert => '/etc/ssl/fourth.example.com.cert',
  ssl_key  => '/etc/ssl/fourth.example.com.key',
}

To configure a mix of SSL and unencrypted virtual hosts at the same domain, declare them with separate apache::vhost defined types:

# The non-ssl virtual host
apache::vhost { 'mix.example.com non-ssl':
  servername => 'mix.example.com',
  port       => '80',
  docroot    => '/var/www/mix',
}

# The SSL virtual host at the same domain
apache::vhost { 'mix.example.com ssl':
  servername => 'mix.example.com',
  port       => '443',
  docroot    => '/var/www/mix',
  ssl        => true,
}

To configure a virtual host to redirect unencrypted connections to SSL, declare them with separate apache::vhost defined types and redirect unencrypted requests to the virtual host with SSL enabled:

apache::vhost { 'redirect.example.com non-ssl':
  servername      => 'redirect.example.com',
  port            => '80',
  docroot         => '/var/www/redirect',
  redirect_status => 'permanent',
  redirect_dest   => 'https://redirect.example.com/'
}

apache::vhost { 'redirect.example.com ssl':
  servername => 'redirect.example.com',
  port       => '443',
  docroot    => '/var/www/redirect',
  ssl        => true,
}

Configuring virtual host port and address bindings

Virtual hosts listen on all IP addresses ('*') by default. To configure the virtual host to listen on a specific IP address, use the ip parameter:

apache::vhost { 'ip.example.com':
  ip      => '127.0.0.1',
  port    => '80',
  docroot => '/var/www/ip',
}

You can also configure more than one IP address per virtual host by using an array of IP addresses for the ip parameter:

apache::vhost { 'ip.example.com':
  ip      => ['127.0.0.1','169.254.1.1'],
  port    => '80',
  docroot => '/var/www/ip',
}

You can configure multiple ports per virtual host by using an array of ports for the port parameter:

apache::vhost { 'ip.example.com':
  ip      => ['127.0.0.1'],
  port    => ['80','8080']
  docroot => '/var/www/ip',
}

To configure a virtual host with aliased servers, refer to the aliases using the serveraliases parameter:

apache::vhost { 'aliases.example.com':
  serveraliases => [
    'aliases.example.org',
    'aliases.example.net',
  ],
  port          => '80',
  docroot       => '/var/www/aliases',
}

To set up a virtual host with a wildcard alias for the subdomain mapped to a directory of the same name, such as 'http://example.com.loc' mapped to /var/www/example.com, define the wildcard alias using the serveraliases parameter and the document root with the virtual_docroot parameter:

apache::vhost { 'subdomain.loc':
  vhost_name      => '*',
  port            => '80',
  virtual_docroot => '/var/www/%-2+',
  docroot         => '/var/www',
  serveraliases   => ['*.loc',],
}

To configure a virtual host with filter rules, pass the filter directives as an array using the filters parameter:

apache::vhost { 'subdomain.loc':
  port    => '80',
  filters => [
    'FilterDeclare  COMPRESS',
    'FilterProvider COMPRESS DEFLATE resp=Content-Type $text/html',
    'FilterChain    COMPRESS',
    'FilterProtocol COMPRESS DEFLATE change=yes;byteranges=no',
  ],
  docroot => '/var/www/html',
}

Configuring virtual hosts for apps and processors

To set up a virtual host with suPHP, use the following parameters:

For example:

apache::vhost { 'suphp.example.com':
  port             => '80',
  docroot          => '/home/appuser/myphpapp',
  suphp_addhandler => 'x-httpd-php',
  suphp_engine     => 'on',
  suphp_configpath => '/etc/php5/apache2',
  directories      => [
    { 'path'  => '/home/appuser/myphpapp',
      'suphp' => {
        user  => 'myappuser',
        group => 'myappgroup',
      },
    },
  ],
}

To configure a virtual host to use the Web Server Gateway Interface (WSGI) for Python applications, use the wsgi set of parameters:

apache::vhost { 'wsgi.example.com':
  port                        => '80',
  docroot                     => '/var/www/pythonapp',
  wsgi_application_group      => '%{GLOBAL}',
  wsgi_daemon_process         => 'wsgi',
  wsgi_daemon_process_options => {
    processes    => '2',
    threads      => '15',
    display-name => '%{GROUP}',
  },
  wsgi_import_script          => '/var/www/demo.wsgi',
  wsgi_import_script_options  => {
    process-group     => 'wsgi',
    application-group => '%{GLOBAL}',
  },
  wsgi_process_group          => 'wsgi',
  wsgi_script_aliases         => { '/' => '/var/www/demo.wsgi' },
}

As of Apache 2.2.16, Apache supports FallbackResource, a simple replacement for common RewriteRules. You can set a FallbackResource using the fallbackresource parameter:

apache::vhost { 'wordpress.example.com':
  port             => '80',
  docroot          => '/var/www/wordpress',
  fallbackresource => '/index.php',
}

Note: The fallbackresource parameter only supports the 'disabled' value since Apache 2.2.24.

To configure a virtual host with a designated directory for Common Gateway Interface (CGI) files, use the scriptalias parameter to define the cgi-bin path:

apache::vhost { 'cgi.example.com':
  port        => '80',
  docroot     => '/var/www/cgi',
  scriptalias => '/usr/lib/cgi-bin',
}

To configure a virtual host for Rack, use the rack_base_uris parameter:

apache::vhost { 'rack.example.com':
  port           => '80',
  docroot        => '/var/www/rack',
  rack_base_uris => ['/rackapp1', '/rackapp2'],
}

Configuring IP-based virtual hosts

You can configure IP-based virtual hosts to listen on any port and have them respond to requests on specific IP addresses. In this example, the server listens on ports 80 and 81, because the example virtual hosts are not declared with a port parameter:

apache::listen { '80': }

apache::listen { '81': }

Configure the IP-based virtual hosts with the ip_based parameter:

apache::vhost { 'first.example.com':
  ip       => '10.0.0.10',
  docroot  => '/var/www/first',
  ip_based => true,
}

apache::vhost { 'second.example.com':
  ip       => '10.0.0.11',
  docroot  => '/var/www/second',
  ip_based => true,
}

You can also configure a mix of IP- and name-based virtual hosts in any combination of SSL and unencrypted configurations.

In this example, we add two IP-based virtual hosts on an IP address (in this example, 10.0.0.10). One uses SSL and the other is unencrypted:

apache::vhost { 'The first IP-based virtual host, non-ssl':
  servername => 'first.example.com',
  ip         => '10.0.0.10',
  port       => '80',
  ip_based   => true,
  docroot    => '/var/www/first',
}

apache::vhost { 'The first IP-based vhost, ssl':
  servername => 'first.example.com',
  ip         => '10.0.0.10',
  port       => '443',
  ip_based   => true,
  docroot    => '/var/www/first-ssl',
  ssl        => true,
}

Next, we add two name-based virtual hosts listening on a second IP address (10.0.0.20):

apache::vhost { 'second.example.com':
  ip      => '10.0.0.20',
  port    => '80',
  docroot => '/var/www/second',
}

apache::vhost { 'third.example.com':
  ip      => '10.0.0.20',
  port    => '80',
  docroot => '/var/www/third',
}

To add name-based virtual hosts that answer on either 10.0.0.10 or 10.0.0.20, you must disable the Apache default Listen 80, as it conflicts with the preceding IP-based virtual hosts. To do this, set the add_listen parameter to false:

apache::vhost { 'fourth.example.com':
  port       => '80',
  docroot    => '/var/www/fourth',
  add_listen => false,
}

apache::vhost { 'fifth.example.com':
  port       => '80',
  docroot    => '/var/www/fifth',
  add_listen => false,
}

Installing Apache modules

There are two ways to install Apache modules using the Puppet apache module:

Installing specific modules

The Puppet apache module supports installing many common Apache modules, often with parameterized configuration options. For a list of supported Apache modules, see the apache::mod::<MODULE NAME> class references.

For example, you can install the mod_ssl Apache module with default settings by declaring the apache::mod::ssl class:

class { 'apache::mod::ssl': }

apache::mod::ssl has several parameterized options that you can set when declaring it. For instance, to enable mod_ssl with compression enabled, set the ssl_compression parameter to true:

class { 'apache::mod::ssl':
  ssl_compression => true,
}

Note that some modules have prerequisites, which are documented in their references under apache::mod::<MODULE NAME>.

Installing arbitrary modules

You can pass the name of any module that your operating system's package manager can install to the apache::mod defined type to install it. Unlike the specific-module classes, the apache::mod defined type doesn't tailor the installation based on other installed modules or with specific parameters---Puppet only grabs and installs the module's package, leaving detailed configuration up to you.

For example, to install the mod_authnz_external Apache module, declare the defined type with the 'mod_authnz_external' name:

apache::mod { 'mod_authnz_external': }

There are several optional parameters you can specify when defining Apache modules this way. See the defined type's reference for details.

Configuring FastCGI servers to handle PHP files

FastCGI on Ubuntu 18.04

On Ubuntu 18.04, mod_fastcgi is no longer supported. So considering:

  • an Apache Vhost with docroot set to /var/www/html
  • a FastCGI server listening on 127.0.0.1:9000

you can then use the custom_fragment parameter to configure the virtual host to have the FastCGI server handle the specified file type:

apache::vhost { 'www':
  ...
  docroot         => '/var/www/html/',
  custom_fragment => 'ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/html/$1',
  ...
}

Please note you have to adjust the second ProxyPassMatch parameter to you docroot value (here /var/www/html/).

Other OSes

Add the apache::fastcgi::server defined type to allow FastCGI servers to handle requests for specific files. For example, the following defines a FastCGI server at 127.0.0.1 (localhost) on port 9000 to handle PHP requests:

apache::fastcgi::server { 'php':
  host       => '127.0.0.1:9000',
  timeout    => 15,
  flush      => false,
  faux_path  => '/var/www/php.fcgi',
  fcgi_alias => '/php.fcgi',
  file_type  => 'application/x-httpd-php'
}

You can then use the custom_fragment parameter to configure the virtual host to have the FastCGI server handle the specified file type:

apache::vhost { 'www':
  ...
  custom_fragment => 'AddType application/x-httpd-php .php'
  ...
}

Load balancing examples

Apache supports load balancing across groups of servers through the mod_proxy Apache module. Puppet supports configuring Apache load balancing groups (also known as balancer clusters) through the apache::balancer and apache::balancermember defined types.

To enable load balancing with exported resources, export the apache::balancermember defined type from the load balancer member server:

@@apache::balancermember { "${::fqdn}-puppet00":
  balancer_cluster => 'puppet00',
  url              => "ajp://${::fqdn}:8009",
  options          => ['ping=5', 'disablereuse=on', 'retry=5', 'ttl=120'],
}

Then, on the proxy server, create the load balancing group:

apache::balancer { 'puppet00': }

To enable load balancing without exporting resources, declare the following on the proxy server:

apache::balancer { 'puppet00': }

apache::balancermember { "${::fqdn}-puppet00":
  balancer_cluster => 'puppet00',
  url              => "ajp://${::fqdn}:8009",
  options          => ['ping=5', 'disablereuse=on', 'retry=5', 'ttl=120'],
}

Then declare the apache::balancer and apache::balancermember defined types on the proxy server.

To use the ProxySet directive on the balancer, use the proxy_set parameter of apache::balancer:

apache::balancer { 'puppet01':
  proxy_set => {
    'stickysession' => 'JSESSIONID',
    'lbmethod'      => 'bytraffic',
  },
}

Load balancing scheduler algorithms (lbmethod) are listed in mod_proxy_balancer documentation.

Reference

For information on classes, types and functions see the REFERENCE.md

Templates

The Apache module relies heavily on templates to enable the apache::vhost and apache::mod defined types. These templates are built based on Facter facts that are specific to your operating system. Unless explicitly called out, most templates are not meant for configuration.

Tasks

The Apache module has a task that allows a user to reload the Apache config without restarting the service. Please refer to to the PE documentation or Bolt documentation on how to execute a task.

Limitations

For an extensive list of supported operating systems, see metadata.json

FreeBSD

In order to use this module on FreeBSD, you must use apache24-2.4.12 (www/apache24) or newer.

Gentoo

On Gentoo, this module depends on the gentoo/puppet-portage Puppet module. Although several options apply or enable certain features and settings for Gentoo, it is not a supported operating system for this module.

RHEL/CentOS

The apache::mod::auth_cas, apache::mod::passenger, apache::mod::proxy_html and apache::mod::shib classes are not functional on RH/CentOS without providing dependency packages from extra repositories.

See their respective documentation below for related repositories and packages.

RHEL/CentOS 5

The apache::mod::passenger and apache::mod::proxy_html classes are untested because repositories are missing compatible packages.

RHEL/CentOS 6

The apache::mod::passenger class is not installing, because the EL6 repository is missing compatible packages.

RHEL/CentOS 7

The apache::mod::passenger and apache::mod::proxy_html classes are untested because the EL7 repository is missing compatible packages, which also blocks us from testing the apache::vhost defined type's rack_base_uris parameter.

SELinux and custom paths

If SELinux is in enforcing mode and you want to use custom paths for logroot, mod_dir, vhost_dir, and docroot, you need to manage the files' context yourself.

You can do this with Puppet:

exec { 'set_apache_defaults':
  command => 'semanage fcontext -a -t httpd_sys_content_t "/custom/path(/.*)?"',
  path    => '/bin:/usr/bin/:/sbin:/usr/sbin',
  require => Package['policycoreutils-python'],
}

package { 'policycoreutils-python':
  ensure => installed,
}

exec { 'restorecon_apache':
  command => 'restorecon -Rv /apache_spec',
  path    => '/bin:/usr/bin/:/sbin:/usr/sbin',
  before  => Class['Apache::Service'],
  require => Class['apache'],
}

class { 'apache': }

host { 'test.server':
  ip => '127.0.0.1',
}

file { '/custom/path':
  ensure => directory,
}

file { '/custom/path/include':
  ensure  => present,
  content => '#additional_includes',
}

apache::vhost { 'test.server':
  docroot             => '/custom/path',
  additional_includes => '/custom/path/include',
}

NOTE: On RHEL 8, the SELinux packages contained in policycoreutils-python have been replaced by the policycoreutils-python-utils package. See here for more details.

You must set the contexts using semanage fcontext instead of chcon because Puppet's file resources reset the values' context in the database if the resource doesn't specify it.

Ubuntu 10.04

The apache::vhost::WSGIImportScript parameter creates a statement inside the virtual host that is unsupported on older versions of Apache, causing it to fail. This will be remedied in a future refactoring.

Ubuntu 16.04

The [apache::mod::suphp][] class is untested since repositories are missing compatible packages.

Development

Testing

To run the unit tests, install the necessary gems:

bundle install

And then execute the command:

bundle exec rake parallel_spec

To check the code coverage, run:

COVERAGE=yes bundle exec rake parallel_spec

Acceptance tests for this module leverage puppet_litmus. To run the acceptance tests follow the instructions here. You can also find a tutorial and walkthrough of using Litmus and the PDK on YouTube.

Development Support

If you run into an issue with this module, or if you would like to request a feature, please file a ticket. Every Monday the Puppet IA Content Team has office hours in the Puppet Community Slack, alternating between an EMEA friendly time (1300 UTC) and an Americas friendly time (0900 Pacific, 1700 UTC).

If you have problems getting this module up and running, please contact Support.

If you submit a change to this module, be sure to regenerate the reference documentation as follows:

puppet strings generate --format markdown --out REFERENCE.md

Apache MOD Test & Support Lifecycle

Adding Support for a new Apache MOD

Support for new Apache Modules can be added under the apache::mod namespace. Acceptance tests should be added for each new Apache Module added. Ideally, the acceptance tests should run on all compatible platforms that this module is supported on (see metdata.json), however there are cases when a more niche module is difficult to set up and install on a particular Linux distro. This could be for one or more of the following reasons:

  • Package not available in default repositories of distro
  • Package dependencies not available in default repositories of distro
  • Package (and/or its dependencies) are only available in a specific version of an OS

In these cases, it is possible to exclude a module from a test platform using a specific tag, defined above the class declaration:

# @note Unsupported platforms: OS: ver, ver; OS: ver, ver, ver; OS: all
class apache::mod::foobar {
...
}

For example:

# @note Unsupported platforms: RedHat: 5, 6; Ubuntu: 14.04; SLES: all; Scientific: 11 SP1
class apache::mod::actions {
...
}

Please be aware of the following format guidelines for the tag:

  • All OS/Version declarations must be preceded with @note Unsupported platforms:
  • The tag must be declared ABOVE the class declaration (i.e. not as footer at the bottom of the file)
  • Each OS/Version declaration must be separated by semicolons (;)
  • Each version must be separated by a comma (,)
  • Versions CANNOT be declared in ranges (e.g. RedHat:5-7), they should be explicitly declared (e.g. RedHat:5,6,7)
  • However, to declare all versions of an OS as unsupported, use the word all (e.g. SLES:all)
  • OSs with word characters as part of their versions are acceptable (e.g. Scientific: 11 SP1, 11 SP2, 12, 13)
  • Spaces are permitted between OS/Version declarations and version numbers within a declaration
  • Refer to the operatingsystem_support values in the metadata.json to find the acceptable OS name and version syntax:
    • E.g. OracleLinux OR oraclelinux, not: Oracle or OraLinux
    • E.g. RedHat OR redhat, not: Red Hat Enterprise Linux, RHEL, or Red Hat

If the tag is incorrectly formatted, a warning will be printed out at the end of the test run, indicating what tag(s) could not be parsed. This will not halt the execution of other tests.

Once the class is tagged, it is possible to exclude a test for that particular Apache MOD using RSpec's filtering and a helper method:

describe 'auth_oidc', if: mod_supported_on_platform('apache::mod::auth_openidc') do

The mod_supported_on_platform helper method takes the Apache Module class definition as defined in the manifests under manifest/mod.

This functionality can be disabled by setting the DISABLE_MOD_TEST_EXCLUSION environment variable. When set, all exclusions will be ignored.

Test Support Lifecycle

The puppetlabs-apache module supports a large number of compatible platforms and Apache Modules. As a result, Apache Module tests can fail because a package or package dependency has been removed from a Linux distribution repository. The IAC Team will try to resolve these issues and keep instructions updated, but due to limited resources this won’t always be possible. In these cases, we will exclude test(s) from certain platforms. As always, we welcome help from our community members, and the IAC team is here to assist and answer questions.