From Manual Setup to One-Command Deployment: My Journey Dockerizing WordPress
Source: Dev.to
The “Why” Behind the Project
As someone transitioning into DevOps, I quickly realized that real learning happens through building, not just watching tutorials. While I had previously set up WordPress using manual SSH commands and Ansible playbooks, I kept hearing about containerization as a fundamental DevOps skill. I decided to bridge this gap by completing Project 1 in my 30‑project DevOps roadmap: containerizing a full WordPress LEMP stack.
This post documents my hands‑on journey, the challenges I faced, and the key concepts I learned along the way.
What I Built
I created a production‑like WordPress environment that can be spun up with a single command:
docker-compose up -d
The command launches two containers:
- MySQL 8.4 – the database
- WordPress (PHP 8.3) – the application
The entire infrastructure is defined in a docker-compose.yml file—Infrastructure as Code in practice.
The Architecture: Simple but Powerful
User Browser → localhost:8080 → WordPress Container → MySQL Container (db:3306)
docker-compose.yml
services:
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DB_NAME: wordpress
depends_on:
- db
volumes:
- wp_data:/var/www/html
volumes:
db_data:
wp_data:
Key Challenges & Solutions
Challenge 1 – Database Connection Issues
- Problem: WordPress installation failed with “database connection error”.
- Solution: Containers communicate via service names, not
localhost. Usingdb(the service name) as the database host fixed the issue.
Challenge 2 – Port Conflicts on macOS
- Problem: Port 80 was already in use.
- Solution: Changed the port mapping to
"8080:80"in the compose file.
Challenge 3 – Authentication Errors with GitHub
- Problem: Could’t push code because password authentication was deprecated.
- Solution: Generated a GitHub Personal Access Token and used it for CLI Git operations.
What This Project Taught Me
-
Infrastructure as Code (IaC) Isn’t Just a Buzzword
Defining the whole stack in a YAML file felt revolutionary. This single file can:- Be version‑controlled
- Be shared with teammates
- Deploy identical environments everywhere
- Serve as documentation
-
Container Networking Is Magical (Once You Understand It)
Thewordpresscontainer can connect to thedbcontainer simply by using the service name (db:3306). Docker creates a virtual network where containers discover each other by name. -
Development‑Production Parity Is Achievable
The same environment runs on:- My local MacBook
- An AWS EC2 instance
- A CI/CD pipeline
- Any developer’s machine
No more “it works on my machine” problems!
-
Learning in Public Has Benefits
Documenting this journey on GitHub and writing this post solidified my understanding. The complete code is available here for anyone to reference or build upon.
Comparison: Before vs. After Docker
| Aspect | Manual/Ansible Setup | Dockerized Setup |
|---|---|---|
| Setup Time | 15–20 minutes | 30 seconds |
| Reproducibility | Environment‑dependent | Guaranteed consistency |
| Learning Curve | Lower initially | Steeper but more valuable |
| Portability | Server‑specific | Runs anywhere with Docker |
| Scaling | Manual intervention | Add more containers |
Essential Commands I Lived By
| Action | Command |
|---|---|
| Start everything | docker-compose up -d |
| Check status | docker-compose ps |
| View logs | docker-compose logs -f |
| Stop everything | docker-compose down |
| Stop and remove volumes (clean slate) | docker-compose down -v |
| Access MySQL shell | docker-compose exec db mysql -u root -p |
For Beginners: My Recommended Learning Path
- Start with the official Docker Getting Started tutorial – builds confidence.
- Containerize something simple (e.g., a static website) before tackling databases.
- Use Docker Compose early – it simplifies multi‑container apps.
- Don’t fear
docker-compose down -v– starting fresh often fixes issues. - Read error messages carefully – they’re usually helpful.
Next Steps in My Journey
- Add Nginx as a reverse proxy for better performance and SSL termination.
- Implement persistent storage properly for uploads and themes.
- Add monitoring with a Prometheus/Grafana container.
- Create a CI/CD pipeline to automatically build and deploy the image.
- Convert this to Kubernetes manifests to learn orchestration.
Final Thoughts
Dockerizing WordPress went from a daunting task to an empowering skill. The initial frustration with networking and configuration gave way to excitement as I realized the power of containers.
The most valuable lesson wasn’t about Docker itself, but about the DevOps mindset: automate everything, document thoroughly, and build reproducible systems.
To anyone on a similar learning journey: start building. Your first project doesn’t need to be perfect; it needs to be finished. Then write about it, share it, and start the next one.
Resources That Helped Me
-
…and countless blog posts, Stack Overflow answers, and the Docker community Slack.
-
Docker Hub: WordPress Docker Image
-
Docker Compose Documentation: Docker Compose Docs
Connect with me
- GitHub: @alanvarghese-dev