Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/content/docs/2.image-variations/fpm-apache.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ services:
For production deployments, consider using a reverse proxy like Traefik or Caddy to handle SSL termination instead of managing certificates in the container.
::

## Static Asset Caching
Like the [`fpm-nginx`](/docs/image-variations/fpm-nginx) variation, Apache sends `Cache-Control: public, max-age=31536000, immutable` for static assets, media and fonts (`/etc/apache2/conf-available/performance.conf`). Fonts also get `Access-Control-Allow-Origin: *`. Compressed responses are sent without an `ETag`, so browsers revalidate them with `Last-Modified` and get a `304 Not Modified` (Apache's default `-gzip` ETag never matched).

The header is only set when the response has no `Cache-Control` yet, so your own rules take precedence: `mod_expires` rules or `Header set` in an `.htaccess` file. `mod_expires` is enabled, so the usual `<IfModule mod_expires.c>` blocks work. To opt out for some files, set your own `Cache-Control` for them; `Header unset` is not enough, as the default is added afterwards. With `DISABLE_DEFAULT_CONFIG=true`, `performance.conf` is not enabled; `mod_expires` still is.

::note
`immutable` tells browsers not to revalidate for a year. That suits assets whose URL changes with their content (a hash in the file name, or a `?ver=` query string as WordPress adds). If you replace files under the same URL, such as uploads in WordPress, set a shorter lifetime for them in your `.htaccess`.
::

## Environment Variables
The FPM-Apache variation supports extensive customization through environment variables.

Expand Down
2 changes: 1 addition & 1 deletion src/s6/etc/entrypoint.d/10-init-webserver-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ SERVER_TYPE=$(detect_web_server_type)

if [ "$DISABLE_DEFAULT_CONFIG" = false ]; then
if [ "$SERVER_TYPE" = "Apache" ]; then
enable_apache_conf remoteip security serversideup
enable_apache_conf performance remoteip security serversideup
enable_apache_site "$SSL_MODE"
elif [ "$SERVER_TYPE" = "NGINX" ]; then
process_template /etc/nginx/nginx.conf.template /etc/nginx/nginx.conf
Expand Down
2 changes: 1 addition & 1 deletion src/variations/fpm-apache/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ RUN docker-php-serversideup-dep-install-debian "${DEPENDENCY_PACKAGES_DEBIAN}"
ln -sf /dev/stderr /var/log/apache2/error.log && \
\
# enable Apache2 mods
a2enmod actions autoindex deflate headers http2 proxy proxy_fcgi remoteip rewrite setenvif ssl unique_id && \
a2enmod actions autoindex deflate expires headers http2 proxy proxy_fcgi remoteip rewrite setenvif ssl unique_id && \
\
# force Docker ENVs to handle the apache variables for the run user and group
echo "export APACHE_RUN_USER=${APACHE_RUN_USER}" >> /etc/apache2/envvars && \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
##
# Performance Configuration
##

# Static asset caching, matching the fpm-nginx variation
# (server-opts.d/performance.conf).
#
# Cache-Control is only set when the response has none yet, so an
# application's own rules win: mod_expires or "Header set" / "Header always
# set" rules in an .htaccess file. %{resp:...} reads both header tables;
# "setifempty" would only see the one "Header set" writes to.
#
# <FilesMatch> matches the file Apache serves. A request for a missing
# asset that a rewrite passes to index.php gets no header from here.

# Assets and media
<FilesMatch "\.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv|svgz?)$">
Header set Cache-Control "public, max-age=31536000, immutable" "expr=-z %{resp:Cache-Control}"
</FilesMatch>

# Fonts
<FilesMatch "\.(?:ttf|ttc|otf|eot|woff2?)$">
Header set Access-Control-Allow-Origin "*" "expr=-z %{resp:Access-Control-Allow-Origin}"
Header set Cache-Control "public, max-age=31536000, immutable" "expr=-z %{resp:Cache-Control}"
</FilesMatch>

# Remove the ETag of a compressed response. By default mod_deflate appends
# "-gzip" to it and then never matches that ETag in If-None-Match, so
# revalidating a compressed response always returns 200 with the full body.
# Without the ETag, browsers revalidate with If-Modified-Since and get 304.
# "NoChange" would give the gzip and identity responses one strong ETag,
# which lets an If-Range request mix their bytes.
# https://httpd.apache.org/docs/2.4/mod/mod_deflate.html#deflatealteretag
<IfModule mod_deflate.c>
DeflateAlterETag Remove
</IfModule>