Automated deployment of a WordPress website on a cloud instance. This project uses Ansible to configure a cloud instance with Docker containers running MySQL, PHPMyAdmin, Nginx, and WordPress. It also includes automatic SSL certificate management using Certbot. Ansible vault and docker secrets are used to secure sensitive information.
Each of this service will have it's container:
Technologies used in this project:
---
title: Cloud1 Architecture
config:
  layout: dagre
---
flowchart TB
    WorldWideWeb@{ shape: dbl-circ, label: "🌐<br>World Wide<br>Web" }
    subgraph ControlMachine["🖥️ Control Machine"]
      subgraph AnsibleController["Ansible Controller"]
        InvFile@{ shape: doc, label: "Inventory File" }
        PLY@{ shape: doc, label: "Playbook Files" }
      end
    end
    subgraph Cloud["☁️ Cloud Instance"]
      sshAccess@{ shape: terminal, label: "SSH Access" }
      certificates@{ shape: docs, label: "Certificates" }
      subgraph DockerEngine
        subgraph DatabaseContainer["Database Container"]
            DB@{ shape: database, label: "MySQL Database" }
        end
        subgraph PMAContainer["PHPMyAdmin Container"]
            PMA@{ shape: terminal, label: "PHPMyAdmin" }
        end
        subgraph ReverseProxyContainer["Reverse Proxy Container"]
            RVP@{ shape: procs, label: "Reverse Proxy<br>Nginx" }
        end
        subgraph WebServerContainer["Web Server Container"]
            WP@{ shape: loop-limit, label: "Apache WordPress Application" }
        end
        subgraph CertbotContainer["Certbot Container"]
            CB@{ shape: terminal, label: "Certbot" }
        end
      end
    end
    WorldWideWeb w@-->|443/HTTPS| RVP
    AnsibleController assh@-->|22/SSH| sshAccess
    sshAccess arvp@--> ReverseProxyContainer
    sshAccess aws1@--> WebServerContainer
    sshAccess adb@--> DatabaseContainer
    sshAccess apma@--> PMAContainer
    sshAccess acb@--> CertbotContainer
    RVP rvp1@-->|/wordpress<br>80| WP
    RVP rvp2@-->|/myadmin<br>8081| PMA
    WP -->|3306| DB
    PMA -->|3306| DB
    CB <--> certificates
    RVP --> certificates
    classDef files fill: #fadc89ff,color: #616161ff,stroke: #b4befe
    classDef database fill: #7575bdff,color: #ffffffff,stroke: #45475a
    classDef web fill: #88e68dff,color: #575757ff,stroke: #45475a
    classDef ansible fill: #89b4fa,color: #1e1e2e,stroke: #b4befe
    classDef webContainer fill: #a6e3a17c,color: #1e1e2e,stroke: #94e2d5
    classDef docker fill: #dff8ffff,color: #1e1e2e,stroke: #dff8ffff
    classDef web-anim stroke-dasharray: 9,5, stroke-dashoffset: 900, stroke-width: 2, stroke: #489e5dff, animation: dash 25s linear infinite;
    classDef ansible-anim stroke-dasharray: 5,5, stroke-dashoffset: 300, stroke-width: 2, stroke: #e0b25cff, animation: dash 25s linear infinite;
    class rvp1,rvp2,w web-anim
    class assh,arvp,aws1,adb,apma,acb ansible-anim
    class InvFile,PLY files
    class DB,PMA database
    class RVP,WP,WorldWideWeb web
    class AnsibleController ansible
    class WebServer1Container,WebServer2Container,ReverseProxyContainer webContainer
    class DockerEngine docker
    - 
Clone the repository: git clone git@github.com:Tablerase/Cloud1.git cd Cloud1
- 
Create a Python virtual environment (optional but recommended): python3 -m venv .venv source .venv/bin/activate
- 
Install the required dependencies (Ansible): pip install -r requirements.txt 
- 
Configure your inventory file: cp inventory/inventory.example.yml inventory/inventory.yml 
- 
Edit the inventory/inventory.ymlfile to add your server details. Like for example:all: hosts: wp1: ansible_host: your.server.instance.ip ansible_user: root ansible_ssh_private_key_file: ~/.ssh/id_rsa # or other key file 
- 
Configure variables by editing the inventory/group_vars/all/all.ymlfile.- For project_domain: use website like DuckDNS to get a free domain name. Just put the ip address of your server instance and choose a domain name.
 
- For 
- 
Configure vault by creating a vault password file and creating a vault-encrypted file. echo "your_vault_password" > .vault_pass.txt Then, create a vault-encrypted file using the following command: ansible-vault create inventory/group_vars/all/vault.yml Then, edit the inventory/group_vars/all/vault.ymlfile to add your sensitive variables:# This file will be encrypted with ansible-vault. # Define sensitive variables here and reference them from plain group_vars via vault_* variables. vault_mysql_root_password: your_mysql_root_password vault_mysql_password: your_mysql_password vault_wordpress_admin_password: your_wordpress_admin_password vault_wordpress_admin_email: your_wordpress_admin_email vault_certbot_email: your_certbot_email If needed, to decrypt the vault file, use the following command: ansible-vault decrypt inventory/group_vars/all/vault.yml 
- 
Check your Ansible connection by running the following command: ansible all -i inventory/inventory.yml -m ping - If the connection is successful, you should see a "pong" response from each host.
- Otherwise, check your SSH configuration (like your SSH keys and config file), ensure that the Ansible user (from inventory) has the necessary permissions to connect to the remote server, and that the server is reachable.
 
- 
Deploy your WordPress site by running the following command: ansible-playbook -i inventory/inventory.yml playbooks/site.yml If you need to pass any extra variables to the playbook, you can do so using the -eflag:ansible-playbook -i inventory/inventory.yml playbooks/site.yml -e "variable_name=value"If you need to use only certain roles from the playbook, you can specify them using the --tagsflag:ansible-playbook -i inventory/inventory.yml playbooks/site.yml --tags "tag_name"
Sensitive values are defined in inventory/group_vars/all/vault.yml and referenced in inventory/group_vars/all/all.yml as vault_* variables. Keep vault.yml encrypted with Ansible Vault.
- ansible.cfgis set with- vault_identity_list = default@.vault_pass.txtso a local- .vault_pass.txtcan unlock the vault automatically (this file is gitignored).
- Docker services use secrets with _FILEenv vars; Ansible writes secret files to{{ docker_compose_path }}/secretswith0600permissions andno_log: true.
How to use:
- Create .vault_pass.txtat the repo root containing your vault password (optional; otherwise pass--ask-vault-pass).
- Encrypt or create the vault file:
- ansible-vault encrypt inventory/group_vars/all/vault.yml(if file exists)
- or ansible-vault create inventory/group_vars/all/vault.yml
- Run the playbook: ansible-playbook playbooks/site.yml
To rotate secrets: ansible-vault edit inventory/group_vars/all/vault.yml and re-run the playbook.
Ansible is a powerful open-source automation tool that can be used to deploy and manage applications and services.
flowchart LR
    subgraph Control["Control Node"]
        ANS["Ansible Engine"]
        PB["Playbook YAML"]
        INV["Inventory File"]
    end
    subgraph Managed["Managed Nodes"]
        MOD["Ansible Modules"]
        RES["System Resources"]
    end
    ANS -->|"Reads"| PB
    ANS -->|"References"| INV
    ANS -->|"SSH Connection"| MOD
    MOD -->|"Configures"| RES
    classDef control fill:#1976d2,color:#ffffff,stroke:#0d47a1
    classDef managed fill:#388e3c,color:#ffffff,stroke:#1b5e20
    class ANS,PB,INV control
    class MOD,RES managed
    Ansible operates on a control node that manages one or more managed nodes. The control node runs the Ansible engine, which reads playbooks and inventories to execute tasks on the managed nodes.
- Ansible Engine: The core component that executes tasks defined in playbooks.
- Playbooks: YAML files that define the tasks to be executed on the managed nodes.
- Inventory: A file that lists the managed nodes and their connection details.
- Ansible Modules: Reusable scripts that perform specific tasks on the managed nodes.
- Managed Nodes: The servers or devices that Ansible manages.
Inventories allow you to define the managed nodes and their connection details. Ansible uses these inventories to know which nodes to target for configuration management.
Playbooks are YAML files that define the tasks to be executed on the managed nodes.
Roles are a way to organize playbooks and tasks into reusable components. They can be shared and reused across different projects.
all:
  hosts:
    node1:
      ansible_host: node1.example.com
    node2:
      ansible_host: node2.example.com
  vars:
    ansible_user: user# Test ping
ansible all -m ping- name: MyFirstPlay
  hosts: all
  tasks:
    - name: Ping all nodes
      ansible.builtin.ping:
    - name: Print message
      ansible.builtin.debug:
        msg: "Hello from {{ inventory_hostname }}"Become is used to run tasks with elevated privileges, such as root access. This is often necessary for tasks that require administrative permissions. You can specify the user to become with the become_user directive, like so:
- name: Install a package with sudo
  ansible.builtin.yum:
    name: httpd
    state: present
  become: true
  become_user: rootTags allow you to run specific parts of a playbook without executing the entire playbook. This is useful for testing or when you only want to apply certain changes.
- name: Install a package
  ansible.builtin.yum:
    name: httpd
    state: present
  tags: install
- name: another task
  ansible.builtin.debug:
    msg: "This is another task"
  tags: otherWhen running the playbook, you can specify the tag to execute only that part:
ansible-playbook playbook.yml --tags install
# Will only run tasks with the 'install' tag, skipping others.Ansible Roles are a way to organize playbooks and tasks into reusable components. They allow you to group related tasks, variables, and files together, making it easier to manage complex configurations.
Ansible supports Jinja2 templating, allowing you to create dynamic configurations based on variables and facts collected from the managed nodes. This is useful for generating configuration files or scripts that need to be customized for each node.
Ansible modules are the building blocks of Ansible tasks. They are reusable scripts that perform specific actions on the managed nodes, such as installing packages, managing files, or executing commands.
Ansible can execute tasks in parallel across multiple managed nodes, making it efficient for large-scale deployments. This is achieved through the use of SSH connections and the ability to run tasks concurrently.
# Parallel execution example (default 5 forks)
ansible all -m ping -f 10Multipass is a lightweight VM manager that allows you to create and manage virtual machines easily. It is particularly useful for testing and development environments.
To create a new VM with Multipass, you can use the following command:
multipass launch --name my-vmTo list all running VMs, use:
multipass listTo access a specific VM, you can use:
multipass shell my-vmTo delete a VM, use:
multipass delete my-vmCertbot is a tool for automatically obtaining and renewing SSL/TLS certificates from the Let's Encrypt Certificate Authority. It simplifies the process of securing your web applications with HTTPS.
---
title: Certbot Challenge Flow
config:
  layout: dagre
---
flowchart TB
    WorldWideWeb@{ shape: dbl-circ, label: "🌐<br>World Wide<br>Web" }
    subgraph Cloud["☁️ Cloud Instance"]
      certificates@{ shape: docs, label: "Certificates" }
      subgraph DockerEngine
        subgraph ReverseProxyContainer["Reverse Proxy Container"]
            RVP@{ shape: procs, label: "Reverse Proxy<br>Nginx" }
        end
        subgraph CertbotContainer["Certbot Container"]
            CB@{ shape: terminal, label: "Certbot" }
        end
        CBChallenge@{ shape: doc, label: "Certbot Challenge" }
      end
    end
    WorldWideWeb w@-->|443/HTTPS<br>**/**| RVP
    CB cb1@-->|Send Challenge|WorldWideWeb
    WorldWideWeb cb2@-->|80/HTTP<br>**/.well-known/acme-challenge/**| RVP
    RVP cb3@-->|Write Challenge Response| CBChallenge
    CBChallenge cb4@-->|Read Challenge Response| CB
    CB <-->|Create/Renew| certificates
    RVP -->|Use| certificates
    classDef files fill: #fadc89ff,color: #616161ff,stroke: #b4befe
    classDef database fill: #7575bdff,color: #ffffffff,stroke: #45475a
    classDef web fill: #88e68dff,color: #575757ff,stroke: #45475a
    classDef ansible fill: #89b4fa,color: #1e1e2e,stroke: #b4befe
    classDef webContainer fill: #a6e3a17c,color: #1e1e2e,stroke: #94e2d5
    classDef docker fill: #dff8ffff,color: #1e1e2e,stroke: #dff8ffff
    classDef certbot fill: #9966ff,color: #ffffff,stroke: #7a4dcf
    classDef web-anim stroke-dasharray: 9,5, stroke-dashoffset: 900, stroke-width: 2, stroke: #489e5dff, animation: dash 25s linear infinite;
    classDef challenge-anim stroke-dasharray: 5,5, stroke-dashoffset: 300, stroke-width: 2, stroke: #db5ce0ff, animation: dash 25s linear infinite;
    class cb1,cb2,cb3,cb4 challenge-anim
    class rvp1,rvp2,w web-anim
    class CB,CBChallenge,certificates certbot
    class RVP,WP,WorldWideWeb web
    class WebServer1Container,WebServer2Container,ReverseProxyContainer webContainer
    class DockerEngine docker
    