This project sets up WordPress using Composer and Docker (via docker-compose for local development and docker-swarm/Portainer for production).
It places WordPress core in a subfolder and keeps wp-content separate from the core.
- 📖 Overview
- 📂 Project Structure
- ⚙️ Environment Setup
- 🔑 Generating Secure Keys
- 🐳 Running Locally with Docker Compose
- 🌐 Deploying with Portainer (Docker Swarm)
- 🎨 Adding Themes & Plugins
- 📦 How to Move Database
- ✅ TODO List
-
Composer manages:
- WordPress core (
public/wordpress) - Plugins (installed to
public/wp-content/plugins) - Themes (installed to
public/wp-content/themes) - Uploads (installs by wp to
public/wp-content/uploads)
- WordPress core (
-
Docker containers:
compose_db(MySQL)compose_php(PHP-FPM with Composer and wp-cli)compose_nginx(nginx)
-
Environment Variables via
.env:- Database credentials (
MYSQL_ROOT_PASSWORD,MYSQL_DATABASE, etc.) - Debug setting
- WordPress salts (
AUTH_KEY,SECURE_AUTH_KEY, etc.)
- Database credentials (
.
├─ composer.json
├─ composer.lock # Generated by Composer
├─ public/
│ ├─ .env.example # Example environment file (not committed to production)
│ ├─ wp-config.php
│ ├─ index.php
│ ├─ wordpress/ # WordPress core
│ └─ wp-content/ # Custom WordPress content directory
│ ├─ themes/
│ ├─ plugins/
│ └─ uploads/
├─ deploy/
│ ├─ docker-compose.yml # Local Docker Compose
│ ├─ docker-swarm.yml # Docker Swarm / Portainer stack
│ └─ default.conf # Nginx configuration
├─ .gitignore
└─ README.md
You'll need a .env file to store environment variables. Copy and fill (public/.env.example) file.
Database credentials (MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, etc.) defined in the .env file are automatically loaded into both Docker Compose and wp-config.php. You do not need to manually update credentials anywhere else—only the .env file.
WordPress recommends unique salts and keys for security. You can generate them via https://roots.io/salts.html
Copy and paste the keys into your .env under names like AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, etc.
The debug settings (DEBUG, DEBUG_LOG, DEBUG_DISPLAY) defined in the .env file directly control the debug configuration in wp-config.php. Always manage debug configuration from your .env file, never directly in wp-config.php.
Security Note: Never commit your real
.envfile into source control. Use.env.exampleas a template.
- Copy
.env.exampleto.envand set real values (database credentials, WP salts, etc.). - Install Composer dependencies (on your host machine or in the container):
composer install
- Start containers:
docker compose --env-file ./public/.env -f ./deploy/docker-compose.yml up -d
- Access the site at
http://localhost:NGINX_PORT(depending on what port you mapped, e.g.8080).
- Copy or adapt
deploy/docker-swarm.ymlfor your production environment. - Provide environment variables in Portainer’s stack setup or as a
.envfile. - Deploy the stack in Portainer.
- Verify the containers start up (check logs in Portainer UI).
Since Docker Swarm containers communicate over an internal overlay network, you typically do not need to expose the MySQL port externally—only the Nginx port for incoming HTTP/HTTPS.
Many plugins and themes can be installed via WPackagist
or direct Composer packages. For example, in composer.json:
"require": {
"wpackagist-plugin/classic-editor": "^1.6"
},Then run:
composer updateto fetch the new plugin/theme.
It will be placed in public/wp-content/plugins/ or public/wp-content/themes/.
If you must install a plugin that isn’t on WPackagist,
you can manually place the plugin folder in public/wp-content/plugins/,
or a theme folder in public/wp-content/themes/,
but that bypasses the benefits of Composer version control.
To migrate the WordPress database using wp-cli:
wp db export db-backup.sqlThis creates a SQL dump file db-backup.sql in the current directory.
Make sure you're in the WordPress root directory, then run:
wp db import db-backup.sqlAfter importing, update all URLs in the database:
wp search-replace 'http://old-domain.com' 'http://new-domain.com' --skip-columns=guid✅
--skip-columns=guidavoids changing post GUIDs, which should stay permanent.
- Create
Dockerfilefor PHP image - Host custom image
Feel free to contribute to this project — pull requests are always welcome!
Developed in Grids by Max Ray