A containerized WordPress hosting solution with automated SSL certificates and Traefik reverse proxy, designed for cloud deployment on Scaleway infrastructure.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Internet β
β (HTTPS Traffic) β
βββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β
βββββββΌββββββ
β Traefik β :80, :443
β (Gateway) β SSL Termination + Auto Redirect
β β Let's Encrypt ACME
βββββββ¬ββββββ Docker Service Discovery
β
β HTTP (Internal)
βββββββββββββΌββββββββββββ
β Nginx-Internal β :80 (Exposed)
β (Web Server) β Static Files + FastCGI Proxy
βββββββββββββ¬ββββββββββββ
β FastCGI :9000
βββββββββββββΌββββββββββββ
β WordPress β :9000 (Exposed)
β (PHP-FPM) β PHP Processing
βββββββββββββ¬ββββββββββββ
β MySQL Protocol
βββββββββββββΌββββββββββββ
β MariaDB β :3306 (Exposed)
β (Database) β Data Storage
βββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββ
β phpMyAdmin β :8080 (Published)
β (DB Management) β Direct Host Access
β Connected to MariaDB β Development/Admin
βββββββββββββββββββββββββββββββββββββββ
Docker Network: "network" (Bridge)
Volumes: mariadb-data, wordpress-data, traefik-data
Cloud-One is a production-ready WordPress hosting stack that combines:
- Traefik v3: Modern reverse proxy with automatic SSL certificate management via Let's Encrypt, HTTP to HTTPS redirection, and Docker service discovery
- Nginx: High-performance internal web server optimized for static content delivery and FastCGI proxy to WordPress
- WordPress: PHP-FPM based WordPress installation with optimized container configuration
- MariaDB: Reliable MySQL-compatible database with persistent storage
- phpMyAdmin: Web-based database administration interface accessible on port 8080
The stack implements a 4-layer architecture designed for production deployment with:
- SSL termination at Traefik level with automatic certificate renewal
- Static file optimization via Nginx caching and compression
- Container isolation with dedicated Docker network for inter-service communication
- Data persistence using bind-mounted volumes for MySQL and WordPress data
- Infrastructure as Code deployment using Ansible for cloud environments
Network Configuration:
- All services communicate through a dedicated Docker bridge network named
network - Only essential ports are published to the host: 80/443 (Traefik) and 8080 (phpMyAdmin)
- Inter-container communication uses service names for DNS resolution
Service Exposure:
- Traefik: Publishes ports 80/443 for public web access
- Nginx-Internal: Exposes port 80 only to the internal Docker network
- WordPress: Exposes port 9000 for FastCGI communication with Nginx
- MariaDB: Exposes port 3306 only to internal network (secured)
- phpMyAdmin: Publishes port 8080 for direct host access (development)
SSL/TLS Configuration:
- Automatic HTTPS redirection from port 80 to 443
- Let's Encrypt certificates with HTTP-01 challenge
- Staging environment configured by default (change to production in docker-compose.yml)
- Certificate storage in named volume
traefik-data
Data Persistence:
- WordPress files:
${DATA_PATH}/wpbind mount - MySQL data:
${DATA_PATH}/mysqlbind mount - Traefik configuration:
traefik-datanamed volume
- Docker and Docker Compose
- Make
- Ansible (for cloud deployment)
- SSH access to target server (for cloud deployment)
For development and testing purposes, you can work with the project locally before cloud deployment:
-
Clone the repository
git clone <repository-url> cd cloud-one
-
Create environment configuration
cp .env.sample .env # Edit .env with your configuration (use localhost for local testing) -
Test deployment locally (optional)
# Test the stack locally with Docker Compose docker compose up -d -
Prepare for cloud deployment
# Configure for production deployment make ansible-setup # Edit deployment/inventory.yml with your server details
Note: The primary focus is cloud deployment. Local testing is optional and mainly for development purposes.
Cloud-One is designed for automated deployment on cloud infrastructure using Ansible. The deployment process installs Docker, configures the environment, and deploys the entire WordPress stack remotely.
-
Setup Ansible environment
make ansible-setup
This installs required Ansible collections and prepares the deployment environment.
-
Configure deployment variables
- Update the server IP in
deployment/inventory.yml - Ensure your
.envfile contains production values - Verify SSH key access to target server (
~/.ssh/id_ed25519)
- Update the server IP in
-
Deploy infrastructure
make ansible-deploy
This command will:
- Install Docker and Docker Compose on the target server
- Copy all necessary files (docker-compose.yml, services/, .env)
- Build and start all containers
- Configure SSL certificates with Let's Encrypt
- Test HTTP/HTTPS connectivity
-
Verify deployment
make ansible-status # Check container status make ansible-logs # View service logs
-
Access your WordPress site
- Website:
https://your-domain.com - phpMyAdmin:
http://your-server-ip:8080
- Website:
Deployment Requirements:
- Target server: Ubuntu 20.04 LTS (or compatible)
- SSH daemon running with key-based authentication
- Python installed on target server
- Domain name pointing to server IP (for SSL certificates)
Ansible Deployment Commands:
make all # Deploy to remote server with Ansible (same as ansible-deploy)
make ansible-deploy # π Deploy Cloud-One stack to Scaleway server
make ansible-setup # π§ Setup Ansible environment and dependencies
make ansible-ping # π‘ Test SSH connection to remote server
make ansible-status # π Check containers status on remote server
make ansible-logs # π Fetch logs from remote server
make ansible-stop # βΉοΈ Stop containers on remote server
make ansible-restart # π Restart containers on remote serverRemote Management Commands:
make stop # Stop containers on remote server
make clean # Remove containers on remote server
make fclean # π¨ DESTROY all Docker resources on remote server (DESTRUCTIVE)
make build # Build Docker images on remote server
make up # Start containers on remote server
make re # Full remote rebuild (fclean + ansible-deploy)
make volumes # Create required data directories on remote server
make help # Show all available commands with descriptionsNote: All commands operate on the remote Scaleway server via Ansible. No local Docker execution.
Key environment variables (see .env.sample):
DOMAIN_NAME: Your domain nameDATA_PATH: Path for persistent data storageMYSQL_*: Database configuration*_KEY,*_SALT: WordPress security keys
SSL certificates are automatically managed by Traefik using Let's Encrypt ACME HTTP challenge. The configuration uses staging server by default - change to production in docker-compose.yml for live certificates.
Data is persisted using bind mounts:
- MySQL data:
${DATA_PATH}/mysql - WordPress files:
${DATA_PATH}/wp
Use the provided backup script on your server:
./services/wordpress/backup-wordpress.shThis creates:
- Database dump:
backups/wordpress_db_latest.sql - Uploads archive:
backups/wordpress_uploads_latest.tar.gz
- Place backup files in the
services/wordpress/backups/directory - Rebuild the stack:
make re - Backups are automatically restored during WordPress container initialization
- Add the functionnality to download Resume when clicking on it
- Add automated backup scheduling with cron
- Implement monitoring with Prometheus/Grafana
- Add Redis caching layer
- Support for multi-site WordPress installations
- Blue-green deployment strategy
- Integration with cloud storage for backups (S3, etc.)
- Enhanced security hardening
- CI/CD pipeline for automated deployments
This section documents the problems encountered during development and the solutions implemented.
Problem: Initial attempts with different reverse proxy solutions faced various complexity issues:
-
Nginx-proxy + Acme-companion: SSL certificate management proved overly complex with multiple moving parts and difficult configuration synchronization between the proxy and SSL companion containers.
-
Certbot: Managing communication between containers for certificate renewal was problematic, especially handling the HTTP-01 challenge workflow in a containerized environment.
Solution: Migrated to Traefik v3 which provides:
- Built-in ACME Let's Encrypt integration
- Automatic service discovery via Docker labels
- Simplified SSL certificate management
- Single container handling both reverse proxy and SSL termination
Problem: WordPress URL and HTTPS detection issues in containerized environment behind reverse proxy.
Solutions implemented:
-
HTTPS Detection: Added proxy detection in
wp-config.php:if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; }
-
Domain Configuration: Forced HTTPS URLs in WordPress configuration:
define('WP_HOME', 'https://' . getenv('DOMAIN_NAME')); define('WP_SITEURL', 'https://' . getenv('DOMAIN_NAME'));
Problem: WordPress media upload failures due to container file permission mismatches.
Solutions:
- Configured proper user/group mapping between host and container
- Set appropriate directory permissions in WordPress Dockerfile
- Used bind mounts with correct ownership for persistent storage
Problem: Inter-container communication issues, especially database connectivity.
Solutions:
- Implemented dedicated Docker bridge network
- Used container names for service discovery instead of localhost
- Properly configured database host in WordPress:
getenv('MYSQL_HOSTNAME') . ':3306'
-
SSL certificates not working
- Check if port 80/443 are accessible from internet
- Verify domain DNS points to your server
- Check Traefik logs:
docker logs traefik
-
Database connection errors
- Verify MariaDB container is running
- Check environment variables in
.env - Review database logs:
docker logs mariadb
-
File permissions issues
- Ensure data directories are writable
- Check Docker volume mounts in
docker-compose.yml - Verify WordPress container user permissions
-
WordPress HTTPS redirect loops
- Verify proxy headers configuration in
wp-config.php - Check Traefik forwarded headers configuration
- Ensure WP_HOME and WP_SITEURL use https://
- Verify proxy headers configuration in
View service logs:
docker logs traefik
docker logs nginx-internal
docker logs wordpress
docker logs mariadb
docker logs phpmyadminThis project is licensed under the MIT License - see the LICENSE file for details.
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request
For issues and questions:
- Create an issue in the repository
- Check the troubleshooting section
- Review Docker and Traefik documentation
Note: This project is designed for educational and development purposes. For production use, review security configurations and implement additional hardening measures.