As I continue exploring my homelab, I’m discovering more fascinating projects that I’ve always wanted to explore. One project in particular that caught my interest is deploying WordPress within a Docker environment, especially leveraging Traefik’s capabilities as a reverse proxy.
I’ve always admired WordPress for its open-source foundation, strong community support, and vast selection of themes and plugins. Previously, I deployed WordPress using the traditional approach, setting it up on a single server with Apache. While this method worked fine, I knew there had to be a better, more efficient way.
Having recently gained more experience with Docker, I realised how straightforward and powerful deploying WordPress containers can be. Docker simplifies setup, making it quick to get a functional WordPress site running. Coupled with Traefik, which handles the reverse proxy tasks, I can easily expose WordPress securely and automatically obtain free SSL certificates from Let’s Encrypt.
Using Docker and Traefik together streamlines the deployment process and enhances scalability, security, and maintainability. Now, I can quickly experiment with various themes, plugins, and configurations without worrying about impacting my main environment. It’s exciting to see how much flexibility and control this setup provides compared to the traditional method.
Shifting to a Docker-based WordPress deployment with Traefik has significantly improved my homelab experience, opening up numerous possibilities for exploration, learning, and experimentation.
Deploying WordPress with Docker and Traefik
Previously, I deployed Traefik as a reverse proxy on my Docker instance to handle routing for various services hosted on the same Docker environment. This Traefik deployment served as the foundational infrastructure for my current WordPress project.
Security and Environment Management
For optimal security practices, I leveraged Docker environment files (.env
) to securely store sensitive configuration details, including credentials for both the WordPress application and the MySQL database service. By externalising sensitive information into environment files, I ensured that no sensitive data was directly embedded within Docker Compose files, greatly enhancing security.
Network and Routing Configuration
To enable seamless routing by Traefik, I ensured that the WordPress container was connected to the same Docker network as Traefik, named proxy
. Within the Docker Compose file, I explicitly configured labels for Traefik, specifying the domain under which my WordPress site would be available.
Database Management and phpMyAdmin
Since migrating a legacy WordPress database was necessary, I also included a phpMyAdmin
container for convenient database management. Given the inherent security risks of exposing database management tools directly to the internet, I deliberately avoided applying Traefik labels to the phpMyAdmin
container. Although it remained within the proxy
network for internal communication with the MySQL service, I exposed it only locally on port 907
8. This careful approach ensured secure, isolated database management, limiting access exclusively to the host machine.
SSL Implementation with Let’s Encrypt
This project successfully achieved secure and encrypted connections by integrating SSL certificates from Let’s Encrypt, ensuring safe access to the WordPress site.
#Defining a service
services:
wordpress:
depends_on:
- db
image: wordpress
restart: always
security_opt:
- no-new-privileges:true # helps to increase security
env_file:
- .env # store other secrets e.g., dashboard password
# Define a network
networks:
- proxy
# Environment variables for wordpress
environment:
WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
#Defining volumes
volumes:
- ./:/var/www/html
#Labels for traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.blog.entrypoints=http"
- "traefik.http.routers.blog.rule=Host(`blog.sanjumathew.uk`)"
- "traefik.http.middlewares.blog-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.blog.middlewares=blog-https-redirect"
- "traefik.http.routers.blog-secure.entrypoints=https"
- "traefik.http.routers.blog-secure.rule=Host(`blog.sanjumathew.uk`)"
- "traefik.http.routers.blog-secure.tls=true"
- "traefik.http.routers.blog-secure.service=blog"
- "traefik.http.services.blog.loadbalancer.server.port=80"
- "traefik.docker.network=proxy"
#Phpmyadmin service
phpmyadmin:
depends_on:
- db
image: phpmyadmin
restart: always
security_opt:
- no-new-privileges:true # helps to increase security
env_file:
- .env # store other secrets e.g., dashboard password
# Environment variables for phpmyadmin
environment:
A_HOST: ${PMA_HOST}
UPLOAD_LIMIT: ${UPLOAD_LIMIT}
# Define a network
networks:
- proxy
#Define the port for phpmyadmin
ports:
- 9078:80
#Mysql service
db:
image: mysql:8.0
restart: always
# Environment variables for Mysql
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
#Defining volumes
volumes:
- ./db:/var/lib/mysql
# Define a network
networks:
- proxy
security_opt:
- no-new-privileges:true # helps to increase security
env_file:
- .env # store other secrets e.g., dashboard password
networks:
proxy:
external: true
volumes:
db: