Ansible Role linuxfabrik.lfops.apache_httpd¶
This role installs and configures a CIS-compliant Apache httpd.
Available since LFOps 2.0.0.
How the Role Behaves¶
This role configures Apache using a Debian-style layout with conf-available/conf-enabled, mods-available/mods-enabled, and sites-available/sites-enabled directories. On Red Hat-based systems, this means a significant restructuring of the default Apache configuration. The goal is to make adding and removing mods, virtual hosts, and extra configuration directives as flexible as possible, regardless of the underlying platform.
The config is split into several files forming the configuration hierarchy outlined below, all located in the /etc/httpd/ directory:
/etc/httpd/
`-- httpd.conf
`-- conf-available/
`-- conf-enabled/
`-- mods-available/
`-- mods-enabled/
`-- sites-available/
`-- sites-enabled/
We avoid using <IfModule> in vHost definitions and in the global httpd.conf to facilitate debugging. Without <IfModule>, a missing module causes a clear startup error instead of silently dropping configuration. <IfModule> is only used in mods-available/ and conf-available/ where it is necessary to guard module-specific configuration.
mod_info is not enabled. It serves the complete configuration on /server-info, including the credentials other modules carry in their directives. The endpoint stays configured in the localhost vHost and answers with an empty response until the info module is enabled via apache_httpd__mods__group_var / apache_httpd__mods__host_var.
For flexibility, use the raw variable to configure the following topics (see EXAMPLES.md for vHost configuration examples):
- SSL/TLS Certificates.
- Quality of Service (
mod_qosdirectives). - Proxy passing rules.
- Any other configuration instructions not covered in the "Role Variables" chapters.
This role supports both Red Hat and Debian-based systems. The following paths and service names differ between platforms; the differences are handled automatically and all documentation below uses Red Hat paths:
- Config path: Red Hat
/etc/httpd, Debian/etc/apache2 - Service name: Red Hat
httpd, Debianapache2 - User/Group: Red Hat
apache/apache, Debianwww-data/www-data - PHP-FPM socket: Red Hat
/run/php-fpm/www.sock, Debian/run/php/www.sock
The OWASP ModSecurity Core Rule Set (CRS) is downloaded on the Ansible controller and copied to the target, so only the controller needs access to GitHub. The role checks the archive against a SHA-256 checksum it carries for each supported release, taken from an archive whose signature by the CRS project was verified, and aborts on a mismatch. The role deploys the rules to /etc/httpd/modsecurity.d/crs/, but does not activate them: include modsecurity.d/crs/crs-setup.conf and modsecurity.d/crs/rules/*.conf in a vHost (see EXAMPLES.md). Each version is kept in its own directory, so a change of apache_httpd__mod_security_coreruleset_version switches the symlink and reloads Apache, and setting the previous version again rolls back. crs-setup.conf is reset to the shipped example on every run; put your CRS settings into the vHost.
A vHost that references a certificate file that does not exist yet keeps Apache from starting. For every entry in apache_httpd__placeholder_certificates__*_var whose certificate is missing, the role therefore creates a self-signed placeholder (<name>.crt, <name>-chain.crt, <name>-fullchain.crt and <name>.key, valid for 365 days) before it deploys the vHosts. An existing file is never touched. The playbooks that run acme_sh together with this role fill the list with the certificates of acme_sh__certificates, and acme_sh replaces the placeholders once the certificates are issued.
This role does NOT:
- change the owner of what lies below the document root. Apache only reads it by default, and what an application has to write is handed to the web server user by the role that installs the application (
nextcloud,wordpress,grav,moodle, ...). Content placed by hand below a vHost that has to be writable needs its owner set by hand, for the writable directories only. - install PHP or PHP-FPM. It prefers PHP-FPM over mod_php, but installs neither.
Known Limitations¶
- The OWASP Core Rule Set needs ModSecurity 2.9.6 or newer. Ubuntu 22.04 ships 2.9.5, so
apache_httpd__skip_mod_security_corerulesethas to staytruethere.
Dependent Roles¶
Any LFOps playbook that installs this role runs these for you. Optional ones can be disabled via the playbook's skip variables.
- On RHEL-compatible systems, the EPEL repository must be enabled (role: linuxfabrik.lfops.repo_epel).
- The
python3-passliblibrary must be installed (role: linuxfabrik.lfops.python).
Requirements¶
Manual steps:
- Optional: deploy PHP and configure PHP-FPM by running the php playbook (role: linuxfabrik.lfops.php).
Tags¶
apache_httpd
- Installs base packages and Apache packages/modules.
- Creates the
conf-available/conf-enabled,mods-available/mods-enabled,sites-available/sites-enableddirectory structure. - Creates symlink for the log directory.
- Sets ownership on everything below the document root (
chown --no-dereference apache:apache), not on the document root itself. - Hardens permissions on the config directory (
chmod -R g-w). - Creates missing placeholder certificates (see
apache_httpd:certs). - Ensures httpd service is in the desired state.
- Triggers: httpd.service reload, or restart when a module is enabled or disabled (see
apache_httpd:mods).
apache_httpd:certs
- Installs
openssland creates a self-signed placeholder for every certificate inapache_httpd__placeholder_certificates__*_varthat does not exist yet. - Triggers: none.
apache_httpd:configure
- Creates or updates the global Apache configuration (
httpd.conf). - Removes rpmnew/rpmsave files (and Debian equivalents).
- Removes, creates, disables, and enables conf-available configs.
- Triggers: httpd.service reload, or a restart on Debian and Ubuntu where Apache still runs with the PID file of an earlier version of the role (
/run/apache2.pid).
apache_httpd:htpasswd
- Creates or updates htpasswd flat-files for basic authentication.
- Triggers: none.
apache_httpd:mod_security_coreruleset
- Aborts if the installed ModSecurity is older than 2.9.6, which the Core Rule Set 4 needs.
- Installs
tar. - Downloads the OWASP ModSecurity Core Rule Set (CRS) on the Ansible controller.
- Extracts the archive to
/etc/httpd/modsecurity.d/and points themodsecurity.d/crssymlink at it. - Copies the default
crs-setup.conf.exampletocrs-setup.conf. - Triggers: httpd.service reload.
apache_httpd:mods
- Installs base packages and Apache packages/modules.
- Creates the
conf-available/conf-enabled,mods-available/mods-enabled,sites-available/sites-enableddirectory structure. - Removes, creates, disables, and enables mods-available configs.
- Triggers: httpd.service restart. A reload loads a newly enabled module but skips its initialization, leaving it loaded and inactive without an error.
apache_httpd:state
- Ensures httpd service is in the desired state.
- Triggers: none.
apache_httpd:vhosts
- Creates missing placeholder certificates (see
apache_httpd:certs). - Disables and removes sites-available vHosts.
- Creates DocumentRoot directories for all vHosts.
- Creates and enables sites-available vHosts.
- Supports
apache_httpd__limit_vhoststo deploy only specific vHosts. - Triggers: httpd.service reload.
Tip:
- To deploy a single vHost only, supplement the
apache_httpd:vhoststag with the extra variable--extra-vars='apache_httpd__limit_vhosts=["www.example.com"]'. See Optional Role Variables - Specific to this role.
Mandatory Role Variables - Global Apache Config (core)¶
apache_httpd__conf_server_admin
- See ServerAdmin.
- Type: String.
Example:
# mandatory
apache_httpd__conf_server_admin: 'webmaster@example.com'
Optional Role Variables - Global Apache Config (core)¶
apache_httpd__conf_add_default_charset
- See AddDefaultCharset.
- Type: String.
- Default:
'UTF-8'
apache_httpd__conf_document_root
- See DocumentRoot.
- Type: String.
- Default:
'/var/www/html'
apache_httpd__conf_enable_send_file
- See EnableSendfile.
- Type: String.
- Default:
'On'
apache_httpd__conf_error_log
- See ErrorLog.
- Type: String.
- Default:
'syslog:local1'
apache_httpd__conf_graceful_shutdown_timeout
- Seconds the server waits for in-flight requests to finish when it is stopped or restarted. Apache closes its listening sockets before it starts waiting, so the whole wait is downtime for new clients, not just for the requests still running.
0waits until the last connection closes by itself, which never happens on a host proxying WebSockets or other long-lived connections: systemd then terminates the server afterTimeoutStopSec(90 seconds by default). Raise it on a host with legitimately long-running requests, which are cut off when the timeout expires. See GracefulShutdownTimeout. - Type: Number.
- Default:
3 - Deviates from the upstream default
0(wait forever), which turns every restart into a 90 second outage on a host that holds long-lived connections. - Only bounds the graceful part of the stop. Apache then escalates to any child that has not exited, sending SIGTERM at 3, 5 and 7 seconds and SIGKILL at 9; that schedule is compiled into httpd and cannot be configured.
apache_httpd__systemd_timeout_stop_secis what bounds the total.
apache_httpd__conf_hostname_lookups
- See HostnameLookups.
- Type: String.
- Default:
'Off'
apache_httpd__conf_keep_alive
- See KeepAlive.
- Type: String.
- Default:
'On'
apache_httpd__conf_keep_alive_timeout
- See KeepAliveTimeout.
- Type: Number.
- CIS: Do not set it above
15seconds. - Default:
5
apache_httpd__conf_limit_request_body
- See LimitRequestBody.
- Type: Number.
- CIS: Do not set it above
102400. - Default:
102400
apache_httpd__conf_limit_request_field_size
- See LimitRequestFieldSize.
- Type: Number.
- CIS: Do not set it above
1024- but this might be too small for any modern application which sets cookies in its Header. - Default:
8190
apache_httpd__conf_limit_request_fields
- See LimitRequestFields.
- Type: Number.
- CIS: Do not set it above
100. - Default:
100
apache_httpd__conf_limit_request_line
- See LimitRequestLine.
- Type: Number.
- CIS: Do not set it above
512- but this might be too small for any modern application which sets cookies in its Header. - Default:
8190
apache_httpd__conf_log_level
- See LogLevel.
- Type: String.
- Default:
'warn'
apache_httpd__conf_max_keep_alive_requests
- See MaxKeepAliveRequests.
- Type: Number.
- Default:
500
apache_httpd__conf_server_name
- See ServerName.
- Type: String.
- Default:
'localhost'
apache_httpd__conf_timeout
- See Timeout.
- Type: Number.
- CIS: Do not set it above
10seconds. - Default:
10
apache_httpd__conf_trace_enable
- See TraceEnable.
- Type: String.
- CIS: Do not set it to
'On'. - Default:
'Off'
Example:
# optional - core
apache_httpd__conf_add_default_charset: 'UTF-8'
apache_httpd__conf_document_root: '/var/www/html'
apache_httpd__conf_enable_send_file: 'On'
apache_httpd__conf_error_log: 'syslog:local1'
apache_httpd__conf_hostname_lookups: 'Off'
apache_httpd__conf_keep_alive: 'On'
apache_httpd__conf_keep_alive_timeout: 5
apache_httpd__conf_limit_request_body: 102400
apache_httpd__conf_limit_request_field_size: 8190
apache_httpd__conf_limit_request_fields: 100
apache_httpd__conf_limit_request_line: 8190
apache_httpd__conf_log_level: 'warn'
apache_httpd__conf_max_keep_alive_requests: 500
apache_httpd__conf_server_name: 'localhost'
apache_httpd__conf_timeout: 10
apache_httpd__conf_trace_enable: 'Off'
Optional Role Variables - Specific to this role¶
apache_httpd__conf__group_var / apache_httpd__conf__host_var
- conf-available/conf-enabled files. See example below.
- Type: List of dictionaries.
-
Default: See defaults/main.yml
-
Subkeys:
-
enabled:- Optional. Creates a symlink to conf-available/filename.conf in conf-enabled (true), otherwise the link is removed (false).
- Type: Bool.
- Default:
true
-
filename:- Mandatory. Destination filename in conf-available/, normally equal to the name of the source template used. Suffixed with
.conf. - Type: String.
- Mandatory. Destination filename in conf-available/, normally equal to the name of the source template used. Suffixed with
-
state:- Optional. conf-available/filename.conf is created (
present), otherwise file is removed (absent). - Type: String.
- Optional. conf-available/filename.conf is created (
-
template:- Mandatory. Name of the Jinja template source file to use.
- Type: String.
-
apache_httpd__htpasswd__group_var / apache_httpd__htpasswd__host_var
- Create and update flat-files for basic authentication of HTTP users.
- Type: List of dictionaries.
-
Default:
[] -
Subkeys:
-
password:- Mandatory. Password.
- Type: String.
-
path:- Mandatory. Path to the htpasswd file. Part of the entry's unique identity, so the same user can be kept in several files (commonly
'/etc/httpd/.htpasswd'on RedHat,'/etc/apache2/.htpasswd'on Debian and Ubuntu). - Type: String.
- Mandatory. Path to the htpasswd file. Part of the entry's unique identity, so the same user can be kept in several files (commonly
-
state:- Optional. Either
presentorabsent. - Type: String.
- Default:
'present'
- Optional. Either
-
username:- Mandatory. Username.
- Type: String.
-
apache_httpd__limit_vhosts
- Checks if the
conf_server_nameis in the list and only deploys those. Can be used on the CLI to speed up the deployment on large proxy servers, e.g.--extra-vars='apache_httpd__limit_vhosts=["test.example.com"]'. - Type: List.
- Default: unset
apache_httpd__mods__group_var / apache_httpd__mods__host_var
- mods-available/mods-enabled files. See example below.
- Type: List of dictionaries.
-
Default: See defaults/main.yml
-
Subkeys:
-
enabled:- Optional. Creates a symlink to mods-available/filename.mods in mods-enabled (true), otherwise the link is removed (false).
- Type: Bool.
- Default:
true
-
filename:- Mandatory. Destination filename in mods-available/, normally equal to the name of the source template used. Suffixed with
.conf. - Type: String.
- Mandatory. Destination filename in mods-available/, normally equal to the name of the source template used. Suffixed with
-
state:- Optional. mods-available/filename.conf is created (
present), otherwise file is removed (absent). - Type: String.
- Optional. mods-available/filename.conf is created (
-
template:- Optional. Name of the Ansible Jinja template source file to use. If omitted,
filenameis used. - Type: String.
- Optional. Name of the Ansible Jinja template source file to use. If omitted,
-
apache_httpd__packages__group_var / apache_httpd__packages__host_var
- Packages to install using the OS package manager. Packages are removed first and then added.
- Type: List of dictionaries.
-
Default: See defaults/main.yml
-
Subkeys:
-
name:- Mandatory. The package name.
- Type: String.
-
state:- Optional. State of the package, one of
present,absent. - Type: String.
- Optional. State of the package, one of
-
apache_httpd__placeholder_certificates__group_var / apache_httpd__placeholder_certificates__host_var
- Certificates for which the role creates a self-signed placeholder if the certificate file does not exist yet, so that a vHost referencing it can start before the certificate is issued. The files are named like the ones
acme_shinstalls:<cert_path>/<name>.crt,<cert_path>/<name>-chain.crt,<cert_path>/<name>-fullchain.crtand<key_path>/<name>.key. - Type: List of dictionaries.
- Default:
[] -
Subkeys:
-
cert_path:- Mandatory. Directory of the certificate files.
- Type: String.
-
key_path:- Mandatory. Directory of the private key.
- Type: String.
-
name:- Mandatory. Name of the certificate, also used as its CN.
- Type: String.
-
state:- Optional.
presentorabsent.absentonly stops the role from creating a placeholder, it does not remove any file. - Type: String.
- Default:
'present'
- Optional.
-
apache_httpd__skip_php_fpm
- Skip PHP-FPM configuration globally and in each vHost within Apache. When set to
false(default), the role automatically injects PHP-FPMProxyPassdirectives into app, localhost, and wordpress vHosts. - Type: Bool.
- Default:
false
apache_httpd__systemd_enabled
- Whether the Apache webserver service should start on boot (true) or not (false).
- Type: Bool.
- Default:
true
apache_httpd__systemd_state
- Make sure Apache webserver service is in a specific state. Possible options:
reloaded,restarted,started,stopped. - Type: String.
- Default:
'started'
apache_httpd__systemd_timeout_stop_sec
- Seconds systemd waits for Apache to stop before terminating the service with SIGKILL, deployed as a
TimeoutStopSecdrop-in of the Apache service unit. Apache closes its listening sockets at the very start of a stop, so the whole wait is downtime for new clients, not just for the requests still running. Keep this slightly aboveapache_httpd__conf_graceful_shutdown_timeoutso requests still get their graceful window. See TimeoutStopSec. - Type: Number.
- Default:
5 - Deviates from systemd's default of 90 seconds (
DefaultTimeoutStopSec), which a host holding connections that never close by themselves pays in full on every restart. - The SIGKILL reaches Apache's parent process, which then cannot release its semaphore arrays: a host leaks roughly three of them per restart (
ipcs -s). With aSEMMNIof 32000 that is on the order of ten thousand restarts before it matters, and a reboot clears them, but it is worth monitoring on a host that restarts Apache often.
Example:
# optional - role-specific
apache_httpd__conf__host_var:
- filename: 'deflate'
enabled: true
state: 'present'
template: 'deflate'
apache_httpd__htpasswd__host_var:
- username: 'test-user'
password: 'linuxfabrik'
path: '/etc/httpd/.htpasswd'
state: 'present'
apache_httpd__limit_vhosts:
- 'test.example.com'
apache_httpd__mods__host_var:
- filename: 'alias'
enabled: true
state: 'present'
template: 'alias'
- filename: 'authn_core'
enabled: false # overwrite the default
state: 'absent' # overwrite the default
template: 'authn_core'
apache_httpd__packages__host_var:
- name: 'mod_qos'
state: 'present'
apache_httpd__placeholder_certificates__host_var:
- name: 'www.example.com'
cert_path: '/etc/pki/tls/certs'
key_path: '/etc/pki/tls/private'
apache_httpd__skip_php_fpm: false
apache_httpd__systemd_enabled: true
apache_httpd__systemd_state: 'started'
Mandatory Role Variables - vHosts¶
vHosts are defined as a list of dictionaries in apache_httpd__vhosts__group_var or apache_httpd__vhosts__host_var. Their mandatory subkeys are documented here, the optional ones in the next section.
apache_httpd__vhosts__group_var / apache_httpd__vhosts__host_var
- vHost definitions for Apache. See the "Optional Role Variables - vHosts" section below for all optional subkeys.
- Type: List of dictionaries.
-
Subkeys, mandatory for every vHost regardless of its template:
-
conf_server_name:- Set this variable for each vHost definition. Part of the vHost's unique identity. See ServerName.
- Type: String.
-
template:- Selects which kind of vHost is rendered. See the "Types of vHosts" section below for the available values.
- Type: String.
-
virtualhost_port:- Used within the
<VirtualHost {{ virtualhost_ip }}:{{ virtualhost_port }}>directive. Part of the vHost's unique identity, so it must be set explicitly (443, or80for a redirect vHost). - Type: Number.
- Used within the
-
Example:
# mandatory
apache_httpd__vhosts__host_var:
# Application vHosts
- template: 'app'
conf_server_name: 'myapp.example.com'
virtualhost_port: 443
Optional Role Variables - vHosts¶
Every vHost is rendered from the template selected via its template subkey. A template only honours the subkeys listed in its own Applies to: line below; a subkey a template does not know is silently ignored.
Types of vHosts:
- app: A hardened vHost running an application like Nextcloud, etc. with the most common options. Can be extended by using the
rawvariable. -
localhost: A hardened, pre-defined VirtualHost just listening on https://localhost, and only accessible from localhost. Due to its naming, it is the first defined vHost. Can be extended by using the
rawvariable. The following URLs are pre-configured and only accessible from localhost:/fpm-ping- PHP-FPM health check of thewwwpool/fpm-status- PHP-FPM status page of thewwwpool/monitoring.php- Linuxfabrik monitoring endpoint/server-info- Apache server info (mod_inforequired, disabled by default)/server-status- Apache server status (mod_statusrequired)
Both PHP-FPM URLs are proxied to
__apache_httpd__php_socket, the socket of thewwwpool. Every pool answers on the same FPM-internal paths/fpm-statusand/fpm-ping, so a host running further pools (see the php role) exposes them by adding oneLocationper pool via the vHost'srawvariable, each pointing at that pool's socket:text <Location "/app1-fpm-status"> Require local ProxyPass unix:/run/php-fpm/app1.sock|fcgi://localhost/fpm-status </Location> -
proxy: A typical hardened reverse proxy vHost. Can be extended by using the
rawvariable. This proxy vHost definition prevents Apache from functioning as a forward proxy server (inside > out). - raw: If none of the above vHost templates fit, use the
rawone and define everything except<VirtualHost>and</VirtualHost>completely from scratch. - redirect: A vHost that redirects every request to
https://on the same host, keeping the requested hostname and path. Setvirtualhost_port: 80to redirect the plain HTTP port. Requests below/.well-known/acme-challenge/are excluded, so ACME/Let's Encrypt HTTP-01 challenges keep working. Therawvariable replaces the redirect rule instead of extending it. - wordpress: A hardened vHost for a WordPress instance, adding WordPress-specific rules on top of the app-vHost hardening: hotlink protection, blocked access to
wp-config.php,xmlrpc.phpand the other WordPress metadata files, blocked direct access towp-includes, no PHP execution belowwp-content/uploads, blocked author scans, comment-spam mitigation, and theReferrer-PolicyandX-Content-Type-Optionsheaders. The rules also cover WordPress installations in sub-paths of the document root, such as/blog. It is usually injected by the wordpress role; define it by hand only when running WordPress without that role, and then setwordpress_url.
"Hardened" means among other things:
- Old HTTP protocol (< HTTP/1.1) versions are disallowed.
- IP address based requests are disallowed.
- Number of bytes that are allowed in a request are limited.
- Access to dotfiles (files starting with
.) is blocked, except.well-known(for ACME/Let's Encrypt challenges). - Forbidden HTTP methods return a
405 Method Not AllowedviaRewriteRule.
This role creates a vHost named localhost by default. See defaults/main.yml
The following subkeys control whether and where the vHost file is deployed. They are evaluated by the role itself, so they work with every template:
enabled
- Enable this vHost.
- Type: Bool.
- Default:
true
filename
- The filename of the vHost definition. If not set it defaults to the
conf_server_namevariable. The filename is automatically suffixed by.virtualhost_port.conf. - Type: String.
- Default:
conf_server_name.virtualhost_port.conf
state
- Should the vhost definition file be created (
present) or deleted (absent). - Type: String.
- Default:
'present'
The remaining subkeys configure the contents of the vHost and are only honoured by the templates named in their Applies to: line:
allow_accessing_dotfiles
- Access to files that begin with a period is blocked. With this setting you can disable this behavior.
- Applies to: app, localhost, wordpress.
- Type: Bool.
- Default:
false
allow_requests_without_hostname
- Accessing the vHost without a hostname / just by IP is forbidden. With this setting you can disable this behavior.
- Applies to: app, localhost, proxy, wordpress.
- Type: Bool.
- Default:
false
allowed_file_extensions
- ALL file extensions are blocked by default, unless specifically allowed. The patterns use Apache regex syntax (e.g.
html?matches bothhtmlandhtm,jpe?gmatches bothjpegandjpg). Files and folders starting with a dot are always forbidden. Useskip_allowed_file_extensionsto allow all file extensions. wordpress-vHosts have no file extension allowlist at all. - To compile a list of file extensions present in your application, run:
find {{ apache_httpd__conf_document_root }} -type f -name '*.*' | awk -F. '{print $NF }' | sort --unique | sed -e 's/^/- \x27/' -e 's/$/\x27/' - Applies to: app, localhost.
- Type: List.
- Default:
['css', 'gif', 'html?', 'ico', 'jpe?g', 'js', 'pdf', 'php', 'png', 'svg', 'ttf', 'txt', 'woff2?']
allowed_http_methods
- Restrict allowed HTTP methods. Only the explicitly listed ones are allowed; all others return 405 Method Not Allowed. This does not disable TRACE. Always enable GET and OPTIONS at least. For an OPTIONS request, Apache always returns
Allow: GET,POST,OPTIONS,HEAD, no matter what. We are NOT using LimitExcept, because this directive is not allowed in a VirtualHost context. Useskip_allowed_http_methodsto allow all HTTP methods. -
Available HTTP methods:
- CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
-
Available WebDAV methods:
- COPY, LOCK, MKCOL, MOVE, PROPFIND, PROPPATCH, UNLOCK
- Applies to: app, localhost, proxy, wordpress.
- Type: List.
- Default:
['GET', 'OPTIONS']
authz_document_root
- Authorization statement for the
DocumentRoot {{ apache_httpd__conf_document_root }}/{{ conf_server_name }}directive. - Applies to: app, localhost, wordpress.
- Type: String.
- Default:
'Require all granted'
by_role
- If defined it results in a comment
# Generated by Ansible role: {{ by_role }}at the beginning of a vHost definition. - Applies to: all templates.
- Type: String.
- Default: unset
comment
- Describes the vHost and results in a comment right above the
<VirtualHost>section. - Applies to: app, localhost, proxy, raw, wordpress.
- Type: String.
- Default:
'no description available'
conf_allow_override
- Will be set in the
<Directory>directive of the vHost. See AllowOverride. - Applies to: app, localhost, wordpress.
- Type: String.
- Default:
'None'
conf_custom_log
- The log format has to be one of:
agent,combined,combinedio,common,debug,fail2ban,linuxfabrikio,matomo,referer,vhost_common. Set it to an empty string to disable the access log. See CustomLog. - Applies to: app, localhost, proxy, wordpress.
- Type: String.
- Default:
'logs/{{ conf_server_name }}-access.log linuxfabrikio'
conf_directory_index
- See DirectoryIndex.
- Applies to: app, wordpress.
- Type: String.
- Default:
{{ apache_httpd__mod_dir_directory_index }}
conf_document_root
- See DocumentRoot. The role creates this directory for app- and localhost-vHosts only; for a wordpress-vHost the directory is created by the wordpress role.
- Applies to: app, localhost, wordpress.
- Type: String.
- Default:
'{{ apache_httpd__conf_document_root }}/{{ conf_server_name }}'
conf_error_log
- See ErrorLog.
- Applies to: app, localhost, proxy, wordpress.
- Type: String.
- Default:
'logs/{{ conf_server_name }}-error.log'
conf_keep_alive_timeout
- See KeepAliveTimeout.
- Applies to: app, localhost, proxy, wordpress.
- Type: Number.
- CIS: Do not set it above
15seconds. - Default:
5
conf_log_level
- See LogLevel.
- Applies to: app, localhost, proxy, wordpress.
- Type: String.
- Default:
'notice core:info'
conf_options
- Sets the
Optionsfor the<Directory>directive. See Options. - Applies to: app, localhost, wordpress.
- Type: String.
- Default:
'None'
conf_protocols
- The protocols offered on this vHost, most preferred first, overriding
apache_httpd__mod_http2_protocolsfor this vHost only.h2takes effect only on a vHost that terminates TLS, since that is where ALPN happens. The same WebSocket caveat applies as for the server-wide variable: droppinghttp/1.1breakswss://on this vHost. See Protocols. - Applies to: app, proxy, wordpress.
- Type: String.
- Default: unset, which leaves the server-wide setting in place.
conf_proxy_error_override
- If you want to have a common look and feel on the error pages seen by the end user, set this to "On" and define them on the reverse proxy server. See ProxyErrorOverride.
- Applies to: proxy.
- Type: String.
- Default:
'On'
conf_proxy_preserve_host
- When enabled, this option will pass the
Host:line from the incoming request to the proxied host, instead of the hostname specified in theProxyPassline. See ProxyPreserveHost. - Applies to: proxy.
- Type: String.
- Default:
'Off'
conf_proxy_timeout
- See ProxyTimeout.
- Applies to: proxy.
- Type: Number.
- Default:
5
conf_request_read_timeout
- See RequestReadTimeout.
- Applies to: app, localhost, proxy, wordpress.
- Type: Number.
- CIS: Do not set the Timeout Limits for Request Headers above 40. Do not set the Timeout Limits for the Request Body above 20.
- Default:
'header=20-40,MinRate=500 body=20,MinRate=500'
conf_server_admin
- See ServerAdmin.
- Applies to: app, localhost, proxy, wordpress.
- Type: String.
- Default:
{{ apache_httpd__conf_server_admin }}
conf_server_alias
- Set this only if you need more than one
conf_server_name. See ServerAlias. - Applies to: all templates.
- Type: List.
- Default: unset
conf_timeout
- See Timeout.
- Applies to: app, localhost, proxy, wordpress.
- Type: Number.
- Default:
{{ apache_httpd__conf_timeout }}
php_set_handler
- Set the handler for PHP. Socket-based:
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost". Network-based:SetHandler "proxy:fcgi://127.0.0.1:9000/". Only rendered ifapache_httpd__skip_php_fpmisfalse. - The handler only applies to PHP files that exist below the
DocumentRootof this host. For any other.phprequest Apache answers 404 itself instead of passing it to PHP-FPM, so a scanner probing for PHP files ties up no pool worker. A network-based handler therefore needs the scripts on this host as well, under the same path. - Applies to: app, localhost, wordpress.
- Type: String.
- Default:
'SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"'
raw
- It is sometimes desirable to pass variable content that Jinja would handle as variables or blocks. The best and safest solution is to declare
rawvariables as!unsafe, to prevent templating errors and information disclosure. - Applies to: all templates.
- Type: String.
- Default: unset
skip_allowed_file_extensions
- Skips checking file extensions, allowing essentially all file extensions.
- Applies to: app, localhost.
- Type: Bool.
- Default:
false
skip_allowed_http_methods
- Skips checking the HTTP methods, allowing essentially all HTTP methods.
- Applies to: app, localhost, proxy, wordpress.
- Type: Bool.
- Default:
false
virtualhost_ip
- Used within the
<VirtualHost {{ virtualhost_ip }}:{{ virtualhost_port }}>directive. - Applies to: all templates.
- Type: String.
- Default:
'*'
wordpress_url
- The URL of the WordPress site, with or without the scheme, for example
https://blog.example.com. The hotlink protection and the comment-spam rules use its host part to recognize requests originating from the site itself. Set this when the vHost is defined by hand; the wordpress role provides the fallbackwordpress__url, and without either the vHost fails to render. - Applies to: wordpress.
- Type: String.
- Default:
{{ wordpress__url }}
Example: See EXAMPLES.md.
Optional Role Variables - mod_dir¶
apache_httpd__mod_dir_directory_index
- See DirectoryIndex.
- Type: String.
- Default:
'index.html index.htm index.txt'
Example:
# optional - mod_dir
apache_httpd__mod_dir_directory_index: 'index.html'
Optional Role Variables - mod_http2¶
HTTP/2 is enabled, and h2 is the preferred protocol on every TLS connection. Browsers speak HTTP/2 only over TLS, so a vHost without a certificate keeps serving HTTP/1.1 either way. HTTP/2 is negotiated per connection, so it applies between a browser and the reverse proxy in front of an application; the hop from that proxy to the backend stays HTTP/1.1, because mod_proxy_http speaks nothing else.
HTTP/2 hands every request to a worker thread of its own. That pool is separate from the MPM workers documented below: it is not counted against apache_httpd__mpm_event_threads_per_child and does not appear in mod_status. Budget for the additional threads and for the per-connection buffers when sizing a busy host. See the upstream HTTP/2 dimensioning notes.
apache_httpd__mod_http2_early_hints
- Whether to send a "103 Early Hints" response carrying the
Linkheaders ofH2PushResourceas soon as the request starts being processed. This is the replacement for HTTP/2 Server Push, which RFC 9113 deprecated and which Chrome and Edge removed in version 106. See H2EarlyHints. - Type: String.
- Default:
'off'
apache_httpd__mod_http2_max_session_streams
- Number of requests a client may have in flight on a single HTTP/2 connection. See H2MaxSessionStreams.
- Type: Number.
- Default:
100
apache_httpd__mod_http2_max_workers
- Upper bound of the HTTP/2 worker thread pool per child process. Unset lets it default to
ThreadsPerChild. See H2MaxWorkers. - Type: Number.
- Default: unset
apache_httpd__mod_http2_min_workers
- Lower bound of the HTTP/2 worker thread pool per child process. Unset lets it default to
ThreadsPerChild. See H2MinWorkers. - Type: Number.
- Default: unset
apache_httpd__mod_http2_protocols
- The protocols offered to clients, most preferred first.
h2is HTTP/2 over TLS,h2cis HTTP/2 over cleartext TCP. Addh2cfor a client that asks for it, such as a load balancer orcurl --http2; no browser implements it. A protocol no loaded module implements is ignored rather than rejected. See Protocols. - Type: String.
- Default:
'h2 http/1.1' - Deviates from the upstream default
http/1.1: withouth2in the list, loading the module changes nothing and every connection stays on HTTP/1.1, so this is what turns HTTP/2 on. - Keep
http/1.1in the list if anything on the host serves WebSockets. HTTP/2 has noUpgrademechanism, and the role does not setH2WebSockets, so the server never offers the RFC 8441 handshake and a browser opens a separate HTTP/1.1 connection forwss://. A list of justh2leaves that connection nothing to negotiate and WebSocket clients fail to connect.
apache_httpd__mod_http2_stream_max_mem_size
- Amount of response data buffered per request before the worker producing it is suspended. See H2StreamMaxMemSize.
- Type: Number.
- Default:
65536
apache_httpd__mod_http2_window_size
- Amount of request body the server buffers per request before the client has to wait. See H2WindowSize.
- Type: Number.
- Default:
65535
Example:
# optional - mod_http2
apache_httpd__mod_http2_early_hints: 'off'
apache_httpd__mod_http2_max_session_streams: 100
apache_httpd__mod_http2_protocols: 'h2 h2c http/1.1'
apache_httpd__mod_http2_stream_max_mem_size: 65536
apache_httpd__mod_http2_window_size: 65535
To turn HTTP/2 off entirely on a host, disable the module and its configuration. Both, or neither: the conf-available/http2.conf snippet carries the H2* directives, which Apache rejects with Invalid command 'H2MaxSessionStreams' when the module is not loaded. That is intended, a missing module has to surface as a startup error rather than as silently dropped configuration.
apache_httpd__conf__host_var:
- filename: 'http2'
enabled: false
state: 'present'
template: 'http2'
apache_httpd__mods__host_var:
- filename: 'http2'
enabled: false
state: 'present'
template: 'http2'
Optional Role Variables - mod_log_config¶
This module is for flexible logging of client requests. Logs are written in a customizable format, and may be written directly to a file, or to an external program. Conditional logging is provided so that individual requests may be included or excluded from the logs based on characteristics of the request.
apache_httpd__mod_log_config_custom_log
- Global log directive that applies to requests not handled by any vHost. Each vHost defines its own log via
conf_custom_log. One of:agent,combined,combinedio,common,debug,fail2ban,linuxfabrikio,matomo,referer,vhost_common. See CustomLog. - Type: String.
- Default: unset
Example:
# optional - mod_log_config
apache_httpd__mod_log_config_custom_log: 'logs/access.log combined'
Optional Role Variables - mod_remoteip¶
apache_httpd__mod_remoteip_internal_proxy
- List of reverse proxies (IP addresses or CIDR ranges, IPv4 and IPv6) in front of this server. As soon as it lists one, the role enables
mod_remoteipand takes the client address from theX-Forwarded-Forheader of requests that come from these proxies, so the access log, the error log,Require ipand fail2ban see the client instead of the proxy. See RemoteIPInternalProxy. - Every address listed here can claim any client address,
127.0.0.1included, which passesRequire local. List the proxies only, never a whole client network. - Type: List.
- Default:
lfops__trusted_proxies, otherwise[](mod_remoteipstays disabled)
Example:
# optional - mod_remoteip
apache_httpd__mod_remoteip_internal_proxy:
- '192.0.2.4'
- '2001:db8::4'
Mandatory Role Variables - mod_security (security2)¶
Only mandatory if apache_httpd__skip_mod_security_coreruleset is false.
apache_httpd__mod_security_coreruleset_version
- The OWASP ModSecurity Core Rule Set (CRS) version number without "v". The role deploys the releases the CRS project supports with security fixes:
4.25.2(LTS),4.29.0and4.30.0. - Type: String.
Example:
# mandatory - mod_security
apache_httpd__mod_security_coreruleset_version: '4.30.0'
Optional Role Variables - mod_security (security2)¶
apache_httpd__mod_security_coreruleset_url
- The OWASP ModSecurity Core Rule Set (CRS) Download URL. Change this if you are running your own mirror servers. The archive has to be identical to the one GitHub serves, since the role checks its SHA-256 checksum.
- Type: String.
- Default:
'https://github.com/coreruleset/coreruleset/archive'
apache_httpd__skip_mod_security_coreruleset
- Skip the installation of the OWASP ModSecurity Core Rule Set (CRS).
- Type: Bool.
- Default:
true
Example:
# optional - mod_security
apache_httpd__mod_security_coreruleset_url: 'https://github.com/coreruleset/coreruleset/archive'
apache_httpd__skip_mod_security_coreruleset: false
Optional Role Variables - mod_ssl¶
apache_httpd__mod_ssl_ssl_use_stapling
- See SSLUseStapling.
- Stapling only does something for a certificate whose issuer runs an OCSP responder. Let's Encrypt, which the
acme_shrole obtains certificates from, no longer publishes one, so its certificates carry no OCSP URI at all. With stapling on, mod_ssl logsAH02218andAH02604at error level once per certificate and vHost on every start and every reload, and staples nothing. Switch it on for a CA that still answers, or pointSSLStaplingForceURLat a responder from a vHost of your own. - Type: String.
- Default:
'off'
Example:
# optional - mod_ssl
apache_httpd__mod_ssl_ssl_use_stapling: 'off'
Optional Role Variables - mpm_common¶
apache_httpd__mpm_common_listen
- See Listen.
- Type: List of numbers or strings.
- Default:
[80]
Example:
# optional - mpm_common
apache_httpd__mpm_common_listen:
- 80
- '192.0.2.10:80'
Optional Role Variables - mpm_event_module¶
TLDR: event MPM: A variant of the worker MPM with the goal of consuming threads only for connections with active processing. See: http://httpd.apache.org/docs/2.4/mod/event.html
Event: Based on worker, this MPM goes one step further by optimizing how the parent process schedules tasks to the child processes and the threads associated to those. A connection stays open for 5 seconds by default and closes if no new event happens; this is the keep-alive directive default value, which retains the thread associated to it. The Event MPM enables the process to manage threads so that some threads are free to handle new incoming connections while others are kept bound to the live connections. Allowing re-distribution of assigned tasks to threads will make for better resource utilization and performance.
Best for PHP-FPM. Default.
apache_httpd__mpm_event_max_connections_per_child
- See MaxConnectionsPerChild.
- Type: Number.
- Default:
0
apache_httpd__mpm_event_max_request_workers
- See MaxRequestWorkers.
- Type: Number.
- Default:
400
apache_httpd__mpm_event_max_spare_threads
- See MaxSpareThreads.
- Type: Number.
- Default:
250
apache_httpd__mpm_event_min_spare_threads
- See MinSpareThreads.
- Type: Number.
- Default:
75
apache_httpd__mpm_event_start_servers
- See StartServers.
- Type: Number.
- Default:
3
apache_httpd__mpm_event_thread_limit
- See ThreadLimit.
- Type: Number.
- Default:
64
apache_httpd__mpm_event_threads_per_child
- See ThreadsPerChild.
- Type: Number.
- Default:
25
Example:
# optional - mpm_event_module
apache_httpd__mpm_event_max_connections_per_child: 0
apache_httpd__mpm_event_max_request_workers: 400
apache_httpd__mpm_event_max_spare_threads: 250
apache_httpd__mpm_event_min_spare_threads: 75
apache_httpd__mpm_event_start_servers: 3
apache_httpd__mpm_event_thread_limit: 64
apache_httpd__mpm_event_threads_per_child: 25
Optional Role Variables - mpm_prefork_module¶
TLDR: prefork MPM: Implements a non-threaded, pre-forking web server. See: http://httpd.apache.org/docs/2.4/mod/prefork.html
Pre-fork: A new process is created for each incoming connection reaching the server. Each process is isolated from the others, so no memory is shared between them, even if they are performing identical calls at some point in their execution. This is a safe way to run applications linked to libraries that do not support threading—typically older applications or libraries.
NOTE: If enabling prefork, the httpd_graceful_shutdown SELinux boolean should be enabled, to allow graceful stop/shutdown.
This MPM is very self-regulating, so it is rarely necessary to adjust its configuration directives. Most important is that apache_httpd__mpm_prefork_max_request_workers be big enough to handle as many simultaneous requests as you expect to receive, but small enough to assure that there is enough physical RAM for all processes.
Best for Standard PHP running any version of mod_php. Does not work with http2.
apache_httpd__mpm_prefork_max_connections_per_child
- See MaxConnectionsPerChild.
- Type: Number.
- Default:
0
apache_httpd__mpm_prefork_max_request_workers
- See MaxRequestWorkers.
- Type: Number.
- Default:
256
apache_httpd__mpm_prefork_max_spare_servers
- See MaxSpareServers.
- Type: Number.
- Default:
10
apache_httpd__mpm_prefork_min_spare_servers
- See MinSpareServers.
- Type: Number.
- Default:
5
apache_httpd__mpm_prefork_start_servers
- See StartServers.
- Type: Number.
- Default:
5
Example:
# optional - mpm_prefork_module
apache_httpd__mpm_prefork_max_connections_per_child: 0
apache_httpd__mpm_prefork_max_request_workers: 256
apache_httpd__mpm_prefork_max_spare_servers: 10
apache_httpd__mpm_prefork_min_spare_servers: 5
apache_httpd__mpm_prefork_start_servers: 5
Optional Role Variables - mpm_worker_module¶
TLDR: worker MPM: Multi-Processing Module implementing a hybrid multi-threaded multi-process web server. See: http://httpd.apache.org/docs/2.4/mod/worker.html
Worker: A parent process is responsible for launching a pool of child processes, some of which are listening for new incoming connections, and others are serving the requested content. Each process is threaded (a single thread can handle one connection) so one process can handle several requests concurrently. This method of treating connections encourages better resource utilization, while still maintaining stability. This is a result of the pool of available processes, which often has free available threads ready to immediately serve new connections.
The most important directives used to control this MPM are apache_httpd__mpm_worker_threads_per_child, which controls the number of threads deployed by each child process and apache_httpd__mpm_worker_max_request_workers, which controls the maximum total number of threads that may be launched.
Best for mod_qos if you intend to use any connection level control directive ("QS_Srv*"), which is normally done on a Reverse Proxy. Works with PHP-FPM, too.
apache_httpd__mpm_worker_max_connections_per_child
- See MaxConnectionsPerChild.
- Type: Number.
- Default:
0
apache_httpd__mpm_worker_max_request_workers
- See MaxRequestWorkers.
- Type: Number.
- Default:
400
apache_httpd__mpm_worker_max_spare_threads
- See MaxSpareThreads.
- Type: Number.
- Default:
250
apache_httpd__mpm_worker_min_spare_threads
- See MinSpareThreads.
- Type: Number.
- Default:
75
apache_httpd__mpm_worker_start_servers
- See StartServers.
- Type: Number.
- Default:
3
apache_httpd__mpm_worker_thread_limit
- See ThreadLimit.
- Type: Number.
- Default:
64
apache_httpd__mpm_worker_threads_per_child
- See ThreadsPerChild.
- Type: Number.
- Default:
25
Example:
# optional - mpm_worker_module
apache_httpd__mpm_worker_max_connections_per_child: 0
apache_httpd__mpm_worker_max_request_workers: 400
apache_httpd__mpm_worker_max_spare_threads: 250
apache_httpd__mpm_worker_min_spare_threads: 75
apache_httpd__mpm_worker_start_servers: 3
apache_httpd__mpm_worker_thread_limit: 64
apache_httpd__mpm_worker_threads_per_child: 25
Optional Role Variables - wsgi_python3_module¶
apache_httpd__wsgi_python_home
- See WSGIPythonHome.
- Type: String.
- Default:
'/opt/python'
apache_httpd__wsgi_python_path
- See WSGIPythonPath.
- Type: String.
- Default:
'/var/www/html/python/'
apache_httpd__wsgi_script_alias
- See WSGIScriptAlias.
- Type: String.
- Default:
'/ /var/www/html/python/index.py'
Example:
# optional - wsgi_python3_module
apache_httpd__wsgi_python_home: '/opt/python'
apache_httpd__wsgi_python_path: '/var/www/html/python/'
apache_httpd__wsgi_script_alias: '/ /var/www/html/python/index.py'
Troubleshooting¶
The run aborts with Set `apache_httpd__mod_security_coreruleset_version` to a version this role supports
- The OWASP Core Rule Set is deployed (
apache_httpd__skip_mod_security_coreruleset: false), but its version is not set, or the role carries no checksum for it. Set one of the listed versions, or skip the deployment.
The CRS download fails with The checksum for /tmp/ansible.coreruleset-v<version>.tar.gz did not match
- The archive differs from the one the role knows for this release. Do not deploy it. Check
apache_httpd__mod_security_coreruleset_url(a mirror has to serve the unmodified GitHub archive) and verify the archive against the release signature as described in the CRS installation guide.