How to Migrate a WordPress Site to a Docker Environment
Move your existing WordPress installation into a containerized stack using Docker Compose, preserving the database and media files while updating the web server and PHP runtime.
This guide moves your current WordPress installation into a Docker environment. You will use Docker Compose to define the web server, PHP application, and database services. The steps target a fresh Linux installation with Docker and Docker Compose installed.
Prerequisites
- Operating System: Ubuntu 24.04, Debian 12, or AlmaLinux 9 with root privileges.
- Installed Packages: Docker Engine 27.x, Docker Compose 2.x, MySQL 8.0 or MariaDB 10.x.
- Existing Data: Access to your current WordPress site files and a MySQL database dump.
- Network: A static IP address or a reserved hostname for the Docker host.
Step 1: Prepare the Source Data
Before starting the containers, you must export your current data to ensure nothing is lost during the migration. Log into your existing server and navigate to the root of your WordPress installation. Stop the web server if it is currently running to prevent file locking issues.
sudo systemctl stop apache2
# or
sudo systemctl stop nginx
Export your database to a SQL file. Connect to the database using the mysql client and run the export command. Replace wp_db with your actual database name.
mysqldump -u root -p wp_db > /tmp/wordpress_backup.sql
Compress the file to save disk space and transfer it easily if needed.
gzip /tmp/wordpress_backup.sql
Copy the compressed file and the wp-config.php file to a directory on your new Docker host. This directory will serve as the data volume for the containers.
cp /tmp/wordpress_backup.sql.gz /var/www/html/
cp /path/to/your/wordpress/wp-config.php /var/www/html/
Create a directory for the uploaded media files. This ensures the Docker container can write to the same location as your old server.
mkdir -p /var/www/html/wp-content/uploads
Step 2: Create the Docker Compose File
Create a file named docker-compose.yml in the directory where you stored your data. This file defines the services required to run WordPress. You will use an official Nginx image for the web server and a custom PHP image for the application logic.
version: '3.8'
services:
web:
image: nginx:1.25.3-alpine
container_name: wordpress-web
ports:
- "8080:80"
volumes:
- ./wp-config.php:/etc/nginx/conf.d/default.conf
- ./wp-content/uploads:/var/www/html/wp-content/uploads
- ./html:/var/www/html
depends_on:
- db
networks:
- wp-net
db:
image: mariadb:10.11
container_name: wordpress-db
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: wp_db
MYSQL_USER: wp_user
MYSQL_PASSWORD: wppassword
volumes:
- db_data:/var/lib/mysql
networks:
- wp-net
app:
build:
context: ./php
dockerfile: Dockerfile
container_name: wordpress-app
volumes:
- ./wp-content/uploads:/var/www/html/wp-content/uploads
- ./html:/var/www/html
depends_on:
- db
networks:
- wp-net
networks:
wp-net:
driver: bridge
volumes:
db_data:
Create the php directory to hold the PHP configuration. Inside this directory, create a Dockerfile that installs the necessary PHP extensions. WordPress requires specific extensions like mysqlnd, mbstring, and xml.
FROM php:8.3-fpm-alpine
RUN apk add --no-cache \
curl \
git \
libpng-dev \
libjpeg-turbo-dev \
freetype-dev \
libxml2-dev \
oniguruma-dev
RUN docker-php-ext-install \
mysqli \
pdo_mysql \
mbstring \
exif \
pcntl \
bcmath \
gd \
zip \
xml
COPY php.ini /usr/local/etc/php/conf.d/custom.ini
COPY custom.conf /usr/local/etc/php-fpm.d/www.conf
Create the php.ini file with the memory limit set to 128M for standard sites.
memory_limit = 128M
upload_max_filesize = 100M
post_max_size = 100M
Create the custom.conf file to configure the PHP-FPM pool.
[www]
user = www-data
group = www-data
pm = dynamic
pm.max_children = 50
pm.start_servers = 2
pm.min_spare_servers = 5
pm.max_spare_servers = 10
Step 3: Configure Nginx
Create the directory /etc/nginx/conf.d and place the default.conf file there. This file routes requests to the PHP-FPM container. Ensure the document root points to the /var/www/html directory where you copied your WordPress files.
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $document_root;
}
location ~ /\.ht {
deny all;
}
}
Ensure the wp-config.php file you copied earlier contains the correct database credentials. Update the database host to db if using Docker networking, or keep it as localhost if running everything on the same host without a network.
Step 4: Start the Services
Navigate to the directory containing your docker-compose.yml file. Run the command to build the PHP image and start the services. This command pulls the Nginx and MariaDB images, builds your custom PHP image, and launches the containers.
docker compose up -d --build
Wait for the output to indicate that the containers are up. Check the status of the containers to ensure they are running without errors.
docker compose ps
Expected output shows STATUS as Up for all services.
NAME IMAGE STATUS
wordpress-web nginx:1.25.3-alpine Up 10 seconds
wordpress-db mariadb:10.11 Up 10 seconds
wordpress-app wordpress-app Up 10 seconds
Verify the installation
Open a web browser and navigate to http://localhost:8080. You should see your WordPress login screen or the dashboard if you have already set up the site. Check the logs to ensure no PHP errors are occurring.
docker compose logs -f
Look for the PHP-FPM and nginx logs. If you see Connection refused or Database connection failed, check the wp-config.php file. Ensure the database credentials match the environment variables in the docker-compose.yml file.
Troubleshooting
If the containers fail to start, inspect the logs for the specific error message. A common issue is permission errors on the wp-content/uploads directory. Ensure the directory is owned by the www-data user or map the volume correctly.
chown -R www-data:www-data /var/www/html/wp-content/uploads
Another issue is the PHP memory limit. If you see a Fatal error: Allowed memory size exhausted, increase the limit in the php.ini file and rebuild the image.
docker compose build app
docker compose up -d
If the database connection fails, verify that the MariaDB container is initialized correctly. You may need to reset the root password in the environment variables if the initial setup failed.
MYSQL_ROOT_PASSWORD: new_secure_password
MYSQL_DATABASE: wp_db
Ensure the Nginx configuration file is valid. Run the syntax check before applying the configuration.
nginx -t
If the test passes, reload the Nginx container configuration.
docker compose restart web
Finally, verify that the media files are accessible. Access http://localhost:8080/wp-content/uploads/ directly to ensure the volume mapping is working correctly and the files are readable by the web server.