"There is no cloud, it's just someone else's computer"
All mandatory requirements from the Cloud-1 subject have been successfully implemented and verified.
# Test WordPress accessibility
curl -I http://51.159.150.9/ # Should return: HTTP/1.1 200 OK
# Test PHPMyAdmin accessibility
curl -I http://51.159.150.9/phpmyadmin/ # Should return: HTTP/1.1 200 OK
# Check all 4 containers running
ssh root@51.159.150.9 "docker ps"
# Verify automated deployment
ansible all -i inventory/hosts -m pingThis project automates the deployment of a WordPress stack (inspired by Inception) on a remote server using Ansible. Each service runs in a separate Docker container following the principle of 1 process = 1 container.
- Overview
- Architecture
- Prerequisites
- Project Structure
- Quick Start
- Detailed Setup
- Configuration
- Deployment Workflow
- Security Considerations
- Troubleshooting
- Learning Resources
Cloud-1 deploys a fully functional WordPress website with:
- WordPress - Content Management System
- MariaDB/MySQL - Database server
- Nginx - Web server and reverse proxy
- PHPMyAdmin - Database management interface
- Fully automated deployment using Ansible
- Each process in its own container
- Data persistence across reboots
- Automatic restart on server reboot
- Secure configuration (no direct database access from internet)
- TLS/HTTPS support
- Multi-server deployment capability
┌─────────────────────────────────────────────────┐
│ Remote Server (Cloud) │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ Nginx Container │ │
│ │ (Reverse Proxy + TLS) │ │
│ │ Port 80/443 │ │
│ └──────────┬──────────────────────────────┘ │
│ │ │
│ ┌──────────▼──────────┐ ┌─────────────────┐ │
│ │ WordPress │ │ PHPMyAdmin │ │
│ │ Container │ │ Container │ │
│ │ (PHP-FPM) │ │ │ │
│ └──────────┬──────────┘ └────────┬────────┘ │
│ │ │ │
│ └──────────┬───────────┘ │
│ │ │
│ ┌──────────▼──────────┐ │
│ │ MariaDB │ │
│ │ Container │ │
│ │ (Internal only) │ │
│ └─────────────────────┘ │
│ │
│ Docker Network: inception-network │
│ Data Volumes: /home/ubuntu/inception/data │
└─────────────────────────────────────────────────┘
| Container | Base Image | Purpose | Exposed Ports |
|---|---|---|---|
| nginx | Custom (Debian/Alpine) | Web server, SSL termination, reverse proxy | 80, 443 |
| wordpress | Custom (PHP-FPM) | WordPress application | 9000 (internal) |
| mariadb | Custom (MariaDB) | Database server | 3306 (internal) |
| phpmyadmin | Custom (PHP-FPM) | Database admin UI | 9000 (internal) |
- Ansible >= 2.9
sudo apt install ansible # or pip3 install ansible - Python >= 3.8
- SSH access to remote server
- Git for version control
- Ubuntu 20.04 LTS (as specified in project requirements)
- SSH daemon running
- Python installed (usually pre-installed)
- Root or sudo access
- Minimum 1GB RAM recommended
- Open ports: 22 (SSH), 80 (HTTP), 443 (HTTPS)
- Subscribe to the project and you will receive an email
- Get your ssh connection via email. (will have your ssh keys from your intra allowing access via ssh)
- AWS
- Google Cloud Platform
- DigitalOcean
- Heroku
Warning: Monitor your cloud resource usage! You are responsible for any costs incurred.
cloud-1/
├── README.md # This file
├── site.yml # Main playbook for deploying WordPress stack
├── provision.yml # Playbook for provisioning cloud instances
├── inventory/
│ └── hosts # Ansible inventory file (static or dynamic)
├── roles/
│ └── docker/
│ └── tasks/
│ └── main.yml # Tasks to install Docker and docker-compose
├── files/ # Files to be copied to remote server
│ ├── docker-compose.yml # Docker compose configuration
│ ├── .env # Environment variables (DO NOT COMMIT!)
│ └── nginx.conf # Nginx configuration
├── Inception/ # Original Inception project (reference)
│ └── srcs/
│ ├── docker-compose.yml
│ └── requirements/
│ ├── nginx/
│ ├── wordpress/
│ └── mariadb/
└── docs/ # Additional documentation
├── SECURITY.md # Security best practices
└── TROUBLESHOOTING.md # Common issues and solutions
site.yml: Main Ansible playbook that orchestrates the deploymentprovision.yml: Creates and configures cloud instances (not needed in my case)roles/docker/: Ansible role that installs Docker and dependenciesinventory/hosts: Defines target servers for deploymentfiles/: Contains configuration files copied to remote server
# Install Ansible
sudo apt install ansible
# Install Scaleway collection (if using Scaleway)
ansible-galaxy collection install scaleway.scalewayEdit inventory/hosts with your server IP:
[scaleway-wordpress]
your.server.ip.address ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsaCreate files/ directory with necessary configurations:
mkdir -p files
# Copy docker-compose.yml, .env, nginx.conf to files/# Check connectivity
ansible scaleway-wordpress -i inventory/hosts -m ping
# Run deployment (dry-run)
ansible-playbook site.yml -i inventory/hosts --check
# Actual deployment
ansible-playbook site.yml -i inventory/hostsOpen browser: http://your.server.ip.address
If you want to automate server creation:
-
Edit
provision.yml:vars: scaleway_api_token: "YOUR_API_TOKEN" scaleway_project_id: "YOUR_PROJECT_ID" ssh_key_name: "your_ssh_key_name"
-
Run provisioning:
ansible-playbook provision.yml
Security Note: Never commit API tokens to version control. Use environment variables or Ansible Vault.
Create files/.env with your configuration:
# Database Configuration
MYSQL_ROOT_PASSWORD=secure_root_password_here
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=secure_wp_password_here
# WordPress Configuration
WORDPRESS_DB_HOST=mariadb:3306
WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wpuser
WORDPRESS_DB_PASSWORD=secure_wp_password_here
# Domain Configuration
DOMAIN_NAME=your.domain.comImportant: Add
.envto.gitignoreto prevent credential leaks!
[scaleway-wordpress]
192.168.1.100 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa
[scaleway-wordpress:vars]
ansible_python_interpreter=/usr/bin/python3For dynamic cloud inventories, use provider plugins (AWS, GCP, Scaleway).
Edit files/docker-compose.yml to match your requirements. See the Inception project reference for container configurations.
# Syntax check
ansible-playbook site.yml -i inventory/hosts --syntax-check
# Dry run (check mode)
ansible-playbook site.yml -i inventory/hosts --check
# Lint the playbook
ansible-lint site.yml
# Deploy
ansible-playbook site.yml -i inventory/hosts
# Deploy with increased parallelism
ansible-playbook site.yml -i inventory/hosts -f 10Key variables in site.yml:
vars:
project_name: "inception" # Project name for Docker compose
docker_compose_path: "/home/ubuntu/inception" # Installation directoryDefined in roles/docker/tasks/main.yml:
- Installs Docker CE, docker-compose
- Adds user to docker group
- Enables Docker service on boot
The docker-compose setup creates an internal network where containers communicate using service names:
- WordPress connects to
mariadb:3306 - PHPMyAdmin connects to
mariadb:3306 - Nginx proxies to
wordpress:9000andphpmyadmin:9000
-
Provision Infrastructure (if automated)
ansible-playbook provision.yml
-
Install Dependencies (Docker, docker-compose)
- Handled by
dockerrole - Updates system packages
- Installs Docker from official repository
- Handled by
-
Deploy Application
ansible-playbook site.yml -i inventory/hosts
- Creates project directory
- Copies docker-compose.yml, .env, configs
- Launches containers
- Waits for service availability
- Enables auto-restart on boot
-
Verify Deployment
# SSH to server ssh ubuntu@your.server.ip # Check containers docker ps # Check logs docker-compose -f /home/ubuntu/inception/docker-compose.yml logs
To update an existing deployment:
# Pull latest changes
git pull
# Re-run playbook (Ansible is idempotent)
ansible-playbook site.yml -i inventory/hosts
# Or use tags for specific tasks
ansible-playbook site.yml -i inventory/hosts --tags "docker-compose"# SSH to server
ssh ubuntu@your.server.ip
# Stop containers
cd /home/ubuntu/inception
docker-compose down
# Restore backup (if available)
# ... restore commands ...
# Restart with old configuration
docker-compose up -d-
Credentials Management
- Never commit
.envfiles - Use Ansible Vault for sensitive data:
ansible-vault encrypt files/.env ansible-playbook site.yml --ask-vault-pass
- Never commit
-
Network Security
- Database not exposed to internet (internal Docker network only)
- Use firewall rules (ufw, iptables)
- Only open necessary ports (80, 443, 22)
-
SSH Security
- Disable password authentication
- Use SSH keys only
- Consider changing default SSH port
- Use fail2ban for brute force protection
-
TLS/HTTPS
- Use Let's Encrypt for free SSL certificates
- Configure in nginx.conf
- Redirect HTTP to HTTPS
-
Docker Security
- Run containers as non-root users
- Use official base images
- Keep images updated
- Scan for vulnerabilities
See docs/SECURITY.md for detailed security guide.
# Test connectivity
ansible scaleway-wordpress -i inventory/hosts -m ping
# Check SSH manually
ssh -i ~/.ssh/id_rsa ubuntu@your.server.ip
# Verify SSH key
ssh-add -l# SSH to server
ssh ubuntu@your.server.ip
# Check container status
docker ps -a
# View logs
docker-compose -f /home/pulgamecanica/inception/docker-compose.yml logs
# Restart containers
docker-compose -f /home/pulgamecanica/inception/docker-compose.yml restart# Check nginx is running
docker ps | grep nginx
# Test from server
curl http://localhost
# Check firewall
sudo ufw status# Check MariaDB container
docker ps | grep mariadb
# Test database connection
docker exec -it <mariadb_container_id> mysql -u wpuser -p
# Verify environment variables
docker-compose -f /home/pulgamecanica/inception/docker-compose.yml config# Run playbook in verbose mode
ansible-playbook site.yml -i inventory/hosts -vvv
# Check specific task
ansible-playbook site.yml -i inventory/hosts --start-at-task="Task name"
# Syntax check
ansible-playbook site.yml --syntax-check
# Lint playbook
ansible-lint site.yml- Official Ansible Documentation
- Ansible Best Practices
- Ansible Galaxy - Pre-built roles
- Let's Encrypt - Free SSL certificates
- Nginx Documentation
- OWASP Top 10
Remember: Always monitor your cloud resources. Turn off services you're not using to avoid unexpected charges!