Setting up a local WordPress development environment with Docker gives you full control over the stack — but it also means you have to wire up Nginx, PHP-FPM, and MariaDB yourself. A common stumbling block is an HTTP 500 error that appears silently during the WordPress installation wizard, specifically when submitting database credentials at /wp-admin/setup-config.php?step=1. This article walks through a working Docker Compose configuration and explains why the 500 error occurs and how to fix it.
The Target Stack
The setup uses three containers managed by Docker Compose:
- nginx — reverse proxy and static file server
- phpfpm — PHP-FPM process manager that executes WordPress PHP files
- mariadb — MySQL-compatible database server
docker-compose.yml
Below is the Docker Compose file that describes the three services. Note that the wordpress directory is bind-mounted into both the nginx and phpfpm containers so they share the same document root.
version: '3'
services:
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./wordpress:/var/www/html
- ./config/nginx:/etc/nginx/conf.d
- ./logs/nginx:/var/log/nginx
depends_on:
- phpfpm
restart: always
mariadb:
image: mariadb:latest
ports:
- "3306:3306"
volumes:
- ./data/db:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: password
restart: always
phpfpm:
image: php:fpm
ports:
- "9000:9000"
volumes:
- ./wordpress:/var/www/html
depends_on:
- mariadb
restart: alwaysCode language: JavaScript (javascript)
Nginx wordpress.conf
Place the following file at ./config/nginx/wordpress.conf. It passes all .php requests to the phpfpm container over FastCGI on port 9000, and uses the standard WordPress try_files rewrite rule.
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
}
}Code language: PHP (php)
The HTTP 500 Error During WordPress Setup
After running docker-compose up you can reach http://127.0.0.1/wp-admin/setup-config.php and start the WordPress installation. The first step loads fine. However, after submitting the database credentials form at step 1, the browser displays a blank page and the Nginx access log records a 500 response:
172.18.0.1 - - [24/Jun/2017:07:25:54 +0000] "POST /wp-admin/setup-config.php?step=2 HTTP/1.1" 500 5 "http://127.0.0.1/wp-admin/setup-config.php?step=1" "Mozilla/5.0 (X11; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0"Code language: JavaScript (javascript)
No corresponding entry appears in the Nginx error log, which means Nginx itself completed the FastCGI transaction successfully — the 500 status was generated by PHP, not Nginx.
Root Cause: Missing MySQL Extension in the Official php:fpm Image
The official php:fpm Docker image ships with a minimal set of PHP extensions. Critically, it does not include the mysqli or pdo_mysql extensions that WordPress requires to connect to a database. When WordPress’s setup wizard attempts to write wp-config.php and test the database connection, PHP throws a fatal error internally, resulting in the blank 500 response.
Because PHP fatal errors at this stage are caught before WordPress’s error handler is fully initialised, no useful message reaches the browser or the Nginx error log. You may see something useful in the PHP-FPM log, which you can check with:
docker-compose logs phpfpm
Fix 1: Build a Custom PHP-FPM Image with MySQL Extensions
Create a Dockerfile alongside your docker-compose.yml that extends the official image and installs the required extensions:
FROM php:fpm
RUN docker-php-ext-install mysqli pdo pdo_mysqlCode language: CSS (css)
Then update the phpfpm service in your docker-compose.yml to build from this Dockerfile instead of pulling the image directly:
phpfpm:
build: .
ports:
- "9000:9000"
volumes:
- ./wordpress:/var/www/html
depends_on:
- mariadb
restart: alwaysCode language: JavaScript (javascript)
Rebuild and restart the stack:
docker-compose up --build
Fix 2: Use the Official wordpress:fpm Image
If you do not need a fully custom PHP build, the simplest alternative is to replace the php:fpm image with the official wordpress:fpm image. This image is purpose-built for WordPress and already includes mysqli, pdo_mysql, and other extensions WordPress depends on:
phpfpm:
image: wordpress:fpm
ports:
- "9000:9000"
volumes:
- ./wordpress:/var/www/html
environment:
WORDPRESS_DB_HOST: mariadb:3306
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: password
depends_on:
- mariadb
restart: alwaysCode language: JavaScript (javascript)
The wordpress:fpm image also auto-generates wp-config.php from the environment variables above, which eliminates the need to complete the setup wizard at all.
Additional Troubleshooting Steps
Enable PHP Error Logging
Add the following to your custom Dockerfile or mount a custom php.ini to expose PHP errors during development:
RUN echo "error_reporting = E_ALL" >> /usr/local/etc/php/php.ini \
&& echo "display_errors = On" >> /usr/local/etc/php/php.ini \
&& echo "log_errors = On" >> /usr/local/etc/php/php.iniCode language: JavaScript (javascript)
Never enable display_errors in a production environment.
Verify Database Connectivity
WordPress must connect to the database using the service name as the hostname, not localhost or 127.0.0.1. In the Docker Compose network, the correct hostname for the database is mariadb (matching the service name). Set the database host to mariadb in the WordPress setup wizard or in wp-config.php.
Check File Permissions
WordPress needs write access to the document root to create wp-config.php. If the ./wordpress directory on the host is owned by root or has restrictive permissions, the PHP-FPM process (which typically runs as www-data) cannot write the file, producing a 500 error. Fix ownership with:
sudo chown -R 33:33 ./wordpress # 33 is the UID for www-data on Debian-based imagesCode language: PHP (php)
Timing: MariaDB May Not Be Ready
Docker Compose’s depends_on only waits for a container to start, not for the service inside it to be ready to accept connections. MariaDB can take several seconds to initialise on first run. If PHP-FPM tries to connect before MariaDB is ready, the connection will fail and WordPress will return a 500. Solutions include:
- Waiting a few seconds after
docker-compose upbefore loading the setup wizard. - Using a health-check and
condition: service_healthyin Compose v3.x+ to delay the phpfpm container until MariaDB is accepting connections. - Using a startup script with a
wait-for-itor similar utility.
Summary
The HTTP 500 error during WordPress setup with a custom Docker Compose stack almost always traces back to one of three causes: missing PHP MySQL extensions in the php:fpm base image, using localhost instead of the MariaDB service name as the database host, or file permission problems on the WordPress directory. Installing mysqli and pdo_mysql via docker-php-ext-install — or switching to the official wordpress:fpm image — resolves the most common case.