Local WordPress copy with docker compose
Sunday, June 29, 2025 •
Introduction
When you have a WordPress page and you want to test something without testing in production… what do you need?
A separate testing stage. Using docker, it is simple to start up some LAMPish (linux, apache, mysql, php) stack locally and start testing without the fear to break something.
Docker Compose
There are kind of official docker images for WordPress available on docker hub, e.g. https://hub.docker.com/_/wordpress. In order to use it, you also need a database, e.g. https://hub.docker.com/_/mysql. For easy access to the database, we’ll use another image: https://hub.docker.com/_/phpmyadmin. The complete docker compose file looks like this:
services:
wordpress:
image: wordpress
restart: unless-stopped
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
WORDPRESS_TABLE_PREFIX: prefix_
volumes:
- ./wordpress:/var/www/html
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- ./db:/var/lib/mysql
phpmyadmin:
image: phpmyadmin
restart: unless-stopped
ports:
- 8081:80
environment:
- PMA_ARBITRARY=1
Save this as a file docker-compose.yaml
.
Now you can start all three services with docker compose up
.
The WordPress installation will be available at http://localhost:8080
and the phpmyadmin is available at http://localhost:8081.
There are some important configuration options to know: The service wordpress uses bind mounts
to access the local directory ./wordpress
inside the container. When the container starts up the first time,
WordPress is extracted and installed into this directory - and this directory is then served by the
included apache webserver. If you start it the first time, you are presented with the usual WordPress
installation wizard where you need to setup a user and password.
If the container is restarted, this directory is reused. So the data
is preserved. This is then also a simple way, to replace this default WordPress installation
with your production copy, see below.
Similar thing is happening with the data of the mysql database: This is written down into the bind
mounted local directory ./db
and is preserved through restarts.
phpmyadmin doesn’t use any volume, it simply serves the application. As it is included in the same docker compose file, it can directly access the database via the service name “db”.
There are some configuration options, which are provided as environment variables. E.g. the WordPress instance needs to know the database, which must match the values for the mysql service. For phpmyadmin we use “PMA_ARBITRARY=1” which allows to use this phpmyadmin instance to connect to any reachable mysql server. You can simply enter “db” as server name and use “exampleuser/examplepass” to login.
You can stop the services with Ctrl+C, as docker compose up runs in the foreground.
Start them again with docker compose up
or destroy the with docker compose down
.
Note: Only the containers are destroyed, not the data, that is preserved in the local directories.
Copying the data
A WordPress instance consists of the PHP files itself (including any additionally installed plugin), the uploaded files and the content of the pages which is stored in the database. In order to replicate a production instance locally, you need to copy all.
-
Stop the (docker compose) services if they are still running.
-
Notice the userid/groupid ownership of the files. You’ll need this later. Then delete or move away all files in the local
./wordpress
. -
Copy all files from the production instance into local
./wordpress
. And adjust the file ownership accordingly, e.g. withchown -R 100032:100032 ./wordpress
. -
Create a database dump from the production instance, e.g. via phpymadmin’s export functionality.
-
Adjust the WordPress configuration for the local stage, that means: Edit the file
./wordpress/wp-config.php
and change the following properties:define( 'DB_NAME', 'exampledb' ); define( 'DB_USER', 'exampleuser' ); define( 'DB_PASSWORD', 'examplepass' ); define( 'DB_HOST', 'db' ); // https://stackoverflow.com/questions/10578369/wordpress-wp-admin-redirects-to-https // allow to use wp-admin locally define( 'FORCE_SSL_ADMIN', false );
-
Then start the services with
docker compose up
. -
Go to phpyadmin: http://localhost:8081 and import your production database dump into database “exampledb”.
-
Go to the table “options” (it might be prefixed with some table prefix) and change the options “siteurl” and “home” to be “http://localhost:8080”.
-
Then go to WordPress: http://localhost:8080. It should display the production page. You can also log in to wp-admin: http://localhost:8080/wp-admin using the production credentials.
-
Update WordPress, install new plugins, test. This should all work now locally.
Note: Some themes might have stored the production URLs for images, so keep an eye on the network requests to see, if all requests really end up on localhost. E.g. I noticed that the configured background image for “Avant Portfolio” was using a absolute production url. But configuring the background image again solved the issue.
Note 2: Maybe you have some absolute links in use for some custom navigation. You’ll need to change those manually to point to “http://localhost:8080/…” (or just use relative links if possible).
Note 3: If the file permissions are messed up, WordPress updates or plugin updates / installations might not work. So be sure, to use the correct userid.
Summary
This article shows an easy way to get a production copy of a WordPress instance running locally. You can simply copy the local folders and create another WordPress instance locally for another test. And all this without directly impacting the production instance.
Comments
No comments yet.Leave a comment
Your email address will not be published. Required fields are marked *. All comments are held for moderation to avoid spam and abuse.