Introduction
While Nginx is popular for Docker-based local development environments due to its ease of setup and performance, there are scenarios where testing with Apache and .htaccess files becomes necessary. Although solutions like Lando, Varnish, Woodby, or DDEV exist, this guide focuses on a custom setup that provides full control over container configuration, preferring Alpine-based containers for their lightweight nature.
Original Nginx Configuration
The typical Nginx setup in docker-compose.yml consists of two main services:
web:
build:
context: docker/nginx
container_name: "${PROJECT_NAME}-web"
expose:
- '80'
volumes:
- ./:/drupal
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
environment:
- SERVER_NAME=${PROJECT_NAME}-web.docker.localhost
links:
- php-fpm
labels:
- "traefik.frontend.rule=Host:${PROJECT_NAME}-web.docker.localhost"
depends_on:
- reverse-proxy
- php-fpm
networks:
- default
reverse-proxy:
image: traefik:v1.7
container_name: "${PROJECT_NAME}-rp"
command: --api --docker
ports:
- "80:80"
- "9090:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
labels:
- "traefik.enable=false"
Apache Configuration
To switch to Apache, we'll use the httpd:2.4-alpine image. The Apache configuration in docker-compose.yml is similar to Nginx:
web-apache:
build:
context: docker/apache
container_name: "${PROJECT_NAME}-web-apache"
expose:
- '80'
volumes:
- ./:/drupal
- ./docker/apache/httpd.conf:/usr/local/apache2/conf/httpd.conf
environment:
- SERVER_NAME=${PROJECT_NAME}-web.docker.localhost
links:
- php-fpm
labels:
- "traefik.frontend.rule=Host:${PROJECT_NAME}-web.docker.localhost"
depends_on:
- reverse-proxy
- php-fpm
networks:
- default
Apache Virtual Host Configuration
The default httpd.conf needs to be modified to include proper virtual host settings. Create a virtual host configuration with the following settings:
<VirtualHost *:80>
ServerAdmin admin@example.com
DocumentRoot /drupal/web
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 combined
<Directory /drupal/web>
Options -Indexes +Includes +FollowSymLinks -MultiViews
AllowOverride All
Require all granted
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:fcgi://php-fpm:9000"
</FilesMatch>
</VirtualHost>
This configuration:
- Sets the document root to
/drupal/web - Enables necessary directory options
- Allows
.htaccessoverrides - Configures PHP-FPM handling
- Routes logs to Docker's standard output/error
Container Management
To manage the containers efficiently, use a Makefile:
PROJECT_NAME = my-project
DRUPAL_ROOT=/drupal/
SERVER_ROOT=/drupal/web/
CURRENT_UID=$(shell id -u)
CURRENT_GID=$(shell id -g)
GATEWAY=$$(docker inspect -f "{{ (index .IPAM.Config 0).Gateway }}" $${PROJECT_NETWORK_ID}); \
SETTINGS='\
export PROJECT_NAME=${PROJECT_NAME}; \
export CURRENT_UID=${CURRENT_UID}; \
export CURRENT_GID=${CURRENT_GID}; \
export DOCKER_ENV="docker compose --project-name $${PROJECT_NAME}"; \
'
DOCKER_UP=' \
$${DOCKER_ENV} up --detach --build --remove-orphans ; \
'
up:
@bash -c $(SETTINGS)$(DOCKER_UP)
Key Differences from Nginx
When switching from Nginx to Apache, note these key differences:
- Apache uses
httpd.confinstead of Nginx'sdefault.conf - Directory permissions and options are handled differently
.htaccessfiles are natively supported in Apache- PHP-FPM configuration syntax differs between the servers
Source https://github.com/onesixromcom/drupal10_docker_apache
Conclusion
This setup provides a straightforward way to test Drupal sites with Apache in a Docker environment while maintaining full control over the configuration. The Alpine-based Apache image keeps the container lightweight, and the integration with Traefik ensures easy local domain handling.