Drupal 9 image field migration

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 .htaccess overrides
  • 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:

  1. Apache uses httpd.conf instead of Nginx's default.conf
  2. Directory permissions and options are handled differently
  3. .htaccess files are natively supported in Apache
  4. 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.