From Manual Setup to One-Command Deployment: My Journey Dockerizing WordPress

Published: (December 26, 2025 at 03:11 AM EST)
4 min read
Source: Dev.to

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. Using db (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

  1. 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
  2. Container Networking Is Magical (Once You Understand It)
    The wordpress container can connect to the db container simply by using the service name (db:3306). Docker creates a virtual network where containers discover each other by name.

  3. 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!

  4. 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

AspectManual/Ansible SetupDockerized Setup
Setup Time15–20 minutes30 seconds
ReproducibilityEnvironment‑dependentGuaranteed consistency
Learning CurveLower initiallySteeper but more valuable
PortabilityServer‑specificRuns anywhere with Docker
ScalingManual interventionAdd more containers

Essential Commands I Lived By

ActionCommand
Start everythingdocker-compose up -d
Check statusdocker-compose ps
View logsdocker-compose logs -f
Stop everythingdocker-compose down
Stop and remove volumes (clean slate)docker-compose down -v
Access MySQL shelldocker-compose exec db mysql -u root -p
  • 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

Connect with me

Back to Blog

Related posts

Read more »