apache-2.4 – Fix Apache Rewrite Issues in Docker PHP-Apache Container

apache-2.4dockerdocker-composemod-rewrite

I've followed suit to quite some instructions, tutorials, and also questions in this forum, but I can still not get this working. I've setup a REST API using a PHP Apache Docker container, and need to create a rewrite rule in my apache config to reroute API requests to index.php (the REST controller). Currently, with what's written below, I'm getting a 404:

File Structure on local machine (listed everything except php source code; not needed here):

php
  conf.d
    - error_reporting.ini
    - xdebug.ini
  Dockerfile
  index.php

apache
  - apache2.conf

docker-compose.yml

The content of the Dockerfile being:

FROM php:8.1-apache

WORKDIR /var/www/html/

RUN pecl install xdebug \
    && docker-php-ext-enable xdebug \
    && a2enmod rewrite

COPY . .

EXPOSE 80

And the content of docker-compose.yml being:

services:

  php:
    build: ./php
    depends_on:
      - db
    container_name: php-apache
    ports:
      - 80:80
    volumes:
      - ./php:/var/www/html
      - ./php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
      - ./php/conf.d/error_reporting.ini:/usr/local/etc/php/conf.d/error_reporting.ini
      - ./apache/apache2.conf:/etc/apache2/apache2.conf
    environment:
      MARIADB_HOST: localhost
      MARIADB_USER: root
      MARIADB_PASSWORD: top_very_secret
      MARIADB_DB: apidb

  adminer:
    image: adminer
    depends_on:
      - db
    restart: always
    ports:
      - 8080:8080

  db:
    image: mariadb
    container_name: db
    volumes:
      - maria-db-storage:/var/lib/mysql
    environment:
      MARIADB_ROOT_PASSWORD: top_very_secret
      MARIADB_DATABASE: apidb

volumes:
  maria-db-storage:

Regarding the contents of apache2.conf; I've done the following to create it on the local machine:

  1. Went into the container's virtual filesystem using docker exec -t -i <container_name> /bin/bash.
  2. Wandered to /etc/apache2
  3. Printed the file contents via cat apache2.conf
  4. Copy-pasted the contents into my local /apache/apache2.conf file
  5. Added the following directive lines to the end of that local file:
# Custom directives start here

# Set Server's name
ServerName 'localhost'

# Rewrite for routing of all requests through REST controller
RewriteEngine On

# If requested resource is index.php, do nothing
RewriteRule ^index\.php$ - [L]

# If requested resource is a file or directory that does not exist, reroute to REST 
# controller index.php
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteRule . /index.php [L]

After building the images and running the containers, I've checked within the container's virtual filesystem again via CLI. The /etc/apache2/apache2.conf successfully holds the contents of my local file, and I've also done a apachectl -M within the container, and can see rewrite_module (shared) getting printed.

Again, I'm simply getting a 404; for example if I search for http://localhost/xyz. Same if I do not omit the port (and search for http://localhost:80/xyz). Searching for http://localhost and http://localhost:80 both work; so it seems that my rewrite rules are simply not being applied.

When running apachectl configtest within the docker container, I also get Syntax OK.

Just guessing; does this maybe have something with xdebugs outgoing communication from the container's port 9003?

What am I missing?

Best Answer

I've actually figured it out. The problem seems to be that, when using docker, you must specify the rewrite rules within the Virtual Host context of the port you've specified. At least I've done what's written above, plus the following steps:

  1. Within the container, I've migrated (in CLI) to the folder etc/apache2/sites-enabled
  2. In there is the file 000-default.conf, holding the default configs for the sites that are currently enabled on the concerned apache unit. As far as this application is concerned, it's thus fine to modify the default configuration, as the container will exclusively be used for this API. At least that was my thought.
  3. So again I did the same; copy the file contents as they're shipped with an initiated docker container, via cat 000-default.conf.
  4. Copy-paste the contents within the local apache/sites-enabled/000-default.conf file (that you newly create)
  5. Now you take the following part that was previously in the local apache2.conf file (slightly improved):
# Rewrite for routing of all requests through REST controller
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteRule ^(.*)$ /index.php [L]

and paste it into the local 000-default.conf file; before the closing </VirtualHost> tag. Then you remove the rewrite rules from your apache/apache2.conf file, but you leave it for the added ServerName directive.

  1. You then add the path mapping to the volumes of your php container to load your custom virtual host default configuration file into your container, and you should be good to go; so your docker-compose.yml becomes:
services:

  php:
    ....
    volumes:
      - ./php:/var/www/html
      - ./php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
      - ./php/conf.d/error_reporting.ini:/usr/local/etc/php/conf.d/error_reporting.ini
      - ./apache/apache2.conf:/etc/apache2/apache2.conf
      - ./apache/sites-enabled/000-default.conf:/etc/apache2/sites-enabled/000-default.conf
     ....

Rewrite is now fully functional! I just wonder, is it normal that you actually have to specify rewrite rules within the currently active config file of the sites-enabled folder??