{"id":19143155,"url":"https://github.com/devenes/web-server-provisioning","last_synced_at":"2026-04-21T09:31:03.880Z","repository":{"id":39988629,"uuid":"494108035","full_name":"devenes/web-server-provisioning","owner":"devenes","description":"Provisioning a Web Server and a Database Server with a Dynamic Website Using Ansible","archived":false,"fork":false,"pushed_at":"2022-06-14T01:15:03.000Z","size":2309,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-03T15:37:54.133Z","etag":null,"topics":["ansible","apache","database","sql","terraform"],"latest_commit_sha":null,"homepage":"","language":"SCSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devenes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-19T14:33:15.000Z","updated_at":"2022-06-14T01:17:26.000Z","dependencies_parsed_at":"2022-09-13T19:31:52.380Z","dependency_job_id":null,"html_url":"https://github.com/devenes/web-server-provisioning","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devenes%2Fweb-server-provisioning","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devenes%2Fweb-server-provisioning/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devenes%2Fweb-server-provisioning/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devenes%2Fweb-server-provisioning/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devenes","download_url":"https://codeload.github.com/devenes/web-server-provisioning/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240223948,"owners_count":19767673,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","apache","database","sql","terraform"],"created_at":"2024-11-09T07:29:44.953Z","updated_at":"2026-04-21T09:30:58.846Z","avatar_url":"https://github.com/devenes.png","language":"SCSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Provisioning a Web Server and a Database Server with a Dynamic Website Using Ansible\n\nThe purpose of this hands-on project is to have the knowledge of provisioning a web and database server with a dynamic website.\n\n## Contents\n\n- [Provisioning a Web Server and a Database Server with a Dynamic Website Using Ansible](#provisioning-a-web-server-and-a-database-server-with-a-dynamic-website-using-ansible)\n  - [Contents](#contents)\n  - [Project Setup](#project-setup)\n  - [Build the Infrastructure](#build-the-infrastructure)\n  - [Install Ansible on the Controller Node](#install-ansible-on-the-controller-node)\n  - [Pinging the Target Nodes](#pinging-the-target-nodes)\n  - [Install, Start and Enable MariaDB](#install-start-and-enable-mariadb)\n  - [Configure User Credentials and Database Schema](#configure-user-credentials-and-database-schema)\n  - [Install, Start and Enable Apache Web Server and Other Dependencies](#install-start-and-enable-apache-web-server-and-other-dependencies)\n  - [Pull the Code and Make Necessary Changes](#pull-the-code-and-make-necessary-changes)\n\n## Project Setup\n\n![ho-04](ho-04.png)\n\n## Build the Infrastructure\n\n- Get to the AWS Console and spin-up 3 EC2 Instances with `Red Hat Enterprise Linux 8` AMI.\n\n- Configure the security groups as shown below:\n\n  - Controller Node ----\u003e Port 22 SSH\n\n  - Target Node1 -------\u003e Port 22 SSH, Port 3306 MYSQL/Aurora\n\n  - Target Node2 -------\u003e Port 22 SSH, Port 80 HTTP\n\n## Install Ansible on the Controller Node\n\n- Connect to your `Controller Node`.\n\n- Optionally you can connect to your instances using VS Code.\n\n- Run the commands below to install Python3 and Ansible.\n\n```bash\nsudo yum install -y python3\n```\n\n```bash\npip3 install --user ansible\n```\n\n- Check Ansible's installation with the command below.\n\n```bash\nansible --version\n```\n\n## Pinging the Target Nodes\n\n- Run the command below to transfer your pem key to your Ansible Controller Node.\n\n```bash\nscp -i \u003cPATH-TO-PEM-FILE\u003e \u003cPATH-TO-PEM-FILE\u003e ec2-user@\u003cCONTROLLER-NODE-IP\u003e:/home/ec2-user\n```\n\n- Make a directory named `Ansible-Website-Project` under the home directory and cd into it.\n\n```bash\nmkdir Ansible-Website-Project\ncd Ansible-Website-Project\n```\n\n- Create a file named `inventory.txt` with the command below.\n\n```bash\nvi inventory.txt\n```\n\n- Paste the content below into the inventory.txt file.\n\n- Along with the hands-on, public or private IPs can be used.\n\n- \u003ch4 style=\"color:red; display:inline;\"\u003eDO NOT USE DNS NAMES AS THE ansible_host PROPERTY VALUE!\u003c/h4\u003e Because database server expects an ip number as a user's host name.\n\n```txt\n[servers]\ndb_server   ansible_host=\u003cYOUR-DB-SERVER-IP\u003e   ansible_user=ec2-user  ansible_ssh_private_key_file=~/\u003cYOUR-PEM-FILE\u003e\nweb_server  ansible_host=\u003cYOUR-WEB-SERVER-IP\u003e  ansible_user=ec2-user  ansible_ssh_private_key_file=~/\u003cYOUR-PEM-FILE\u003e\n```\n\n- Create a file named `ping-playbook.yml` and paste the content below.\n\n```bash\ntouch ping-playbook.yml\n```\n\n```yml\n- name: ping them all\n  hosts: all\n  tasks:\n    - name: pinging\n      ping:\n```\n\n- Run the command below for pinging the servers.\n\n```bash\nansible-playbook ping-playbook.yml -i inventory.txt\n```\n\n- Explain the output of the above command.\n\n- Create another file named `ansible.cfg` in the project directory.\n\n```\n[defaults]\nhost_key_checking = False\ninventory = inventory.txt\ndeprecation_warnings=False\ninterpreter_python=auto_silent\n```\n\n- Run the command below again.\n\n```bash\nansible-playbook ping-playbook.yml\nansible all -m ping -o\n```\n\n## Install, Start and Enable MariaDB\n\n- Create another file named `playbook.yml` under the `Ansible-Website-Project` directory.\n\n- Paste the content below into the `playbook.yml` file.\n\n```yml\n- name: db configuration\n  hosts: db_server\n  tasks:\n    - name: install mariadb and PyMySQL\n      become: yes\n      yum:\n        name:\n          - mariadb-server\n          - python3-PyMySQL\n        state: latest\n\n    - name: start mariadb\n      become: yes\n      command: systemctl start mariadb\n\n    - name: enable mariadb\n      become: yes\n      systemd:\n        name: mariadb\n        enabled: true\n```\n\n- Explain what these 3 tasks and modules ([yum](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/yum_module.html), [command](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html), [systemd](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/systemd_module.html)) do respectively.\n\n- Explain how `become` property affects the task.\n\n- Run the playbook.yaml\n\n```bash\nansible-playbook playbook.yml\n```\n\n- Open up a new Terminal or Window and connect to the `db_server` instance and check if `MariaDB` is installed, started, and enabled.\n\n```bash\nmysql --version\n```\n\n- Create a file named `db-load-script.sql` under /home/ec2-user folder, copy and paste the content below.\n\n```bash\nvi db-load-script.sql\n```\n\n```txt\nUSE ecomdb;\nCREATE TABLE products (id mediumint(8) unsigned NOT NULL auto_increment,Name varchar(255) default NULL,Price varchar(255) default NULL, ImageUrl varchar(255) default NULL,PRIMARY KEY (id)) AUTO_INCREMENT=1;\n\nINSERT INTO products (Name,Price,ImageUrl) VALUES (\"Laptop\",\"100\",\"c-1.png\"),(\"Drone\",\"200\",\"c-2.png\"),(\"VR\",\"300\",\"c-3.png\"),(\"Tablet\",\"50\",\"c-5.png\"),(\"Watch\",\"90\",\"c-6.png\"),(\"Phone Covers\",\"20\",\"c-7.png\"),(\"Phone\",\"80\",\"c-8.png\"),(\"Laptop\",\"150\",\"c-4.png\");\n```\n\n- Append the content below into `playbook.yml` file for transferring the sql script into database server.\n\n```yml\n- name: copy the sql script\n  copy:\n    src: ~/db-load-script.sql\n    dest: ~/\n```\n\n- Run the command below.\n\n```bash\nansible-playbook playbook.yml\n```\n\n- Check if the file has been sent to the database server.\n\n- Append the content below into `playbook.yml` file in order to login to db_server and set a root password.\n\n```yml\n- name: Create password for the root user\n      mysql_user:\n        login_password: ''\n        login_user: root\n        name: root\n        password: \"devenes1234\"\n```\n\n- Create a file named `.my.cnf` under home directory on controller node.\n\n- Paste the content below.\n\n```conf\n[client]\nuser=root\npassword=devenes1234\n\n[mysqld]\nwait_timeout=30000\ninteractive_timeout=30000\nbind-address=0.0.0.0\n```\n\n- Append the content below into `playbook.yml` file.\n\n```yml\n- name: copy the .my.cnf file\n      copy:\n        src: ~/.my.cnf\n        dest: ~/\n```\n\n- Run the command below and check if everything is ok.\n\n```bash\nansible-playbook playbook.yml\n```\n\n## Configure User Credentials and Database Schema\n\n- Append the content below into `playbook.yml` file in order to create a remote database user.\n\n```yml\n- name: Create db user with name 'remoteUser' and password 'devenes1234' with all database privileges\n  mysql_user:\n    name: remoteUser\n    password: \"devenes1234\"\n    login_user: \"root\"\n    login_password: \"devenes1234\"\n    priv: \"*.*:ALL,GRANT\"\n    state: present\n    host: \"{{ hostvars['web_server'].ansible_host }}\"\n```\n\n- Run the command below to check if everything is ok.\n\n```bash\nansible-playbook playbook.yml\n```\n\n- Append the content below into `playbook.yml` file in order to create a database schema for the products table.\n\n```yml\n- name: Create database schema\n  mysql_db:\n    name: ecomdb\n    login_user: root\n    login_password: \"devenes1234\"\n    state: present\n```\n\n- Notice that this time the module name is `mysql_db`.\n\n- Append the content below into `playbook.yml` file in order to check if the `products` table is already imported.\n\n```yml\n- name: check if the database has the table\n  shell: |\n    echo \"USE ecomdb; show tables like 'products'; \" | mysql\n  register: resultOfShowTables\n\n- name: DEBUG\n  debug:\n    var: resultOfShowTables\n```\n\n- Explain what these shell commands do.\n\n- Emphasize that we have a new property called `register`.\n\n- Skip the explanation of the `register` property for now.\n\n- Explain the output of the `debug module` **after running the playbook**.\n\n- Append the content below int `playbook.yml` file in order to import the `products` table.\n\n```yml\n- name: Import database table\n  mysql_db:\n    name: ecomdb # This is the database schema name.\n    state: import # This module is not idempotent when the state property value is import.\n    target: ~/db-load-script.sql # This script creates the products table.\n  when: resultOfShowTables.stdout == \"\" # This line checks if the table is already imported. If so this task doesn't run.\n```\n\n- Explain that the previously registered task result `resultOfShowTable` has a property called stdout. Visit the [link](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html#return-values) to show the returns of the `shell` module.\n\n- Explain that if the `resultofShowTables.stdout` gives null the database table will be imported. Otherwise, it won't be imported for not getting any error.\n\n- Run the command below to check if there is an error.\n\n```bash\nansible-playbook playbook.yml\n```\n\n- Connect to the database instance to check if there is a table named `products`.\n\n- Run the command below.\n\n```bash\necho \"USE ecomdb; show tables like 'products'; \" | mysql\n```\n\n- Append the content below in order to restart the MariaDB service.\n\n```yml\n- name: restart mariadb\n  become: yes\n  service:\n    name: mariadb\n    state: restarted\n```\n\n## Install, Start and Enable Apache Web Server and Other Dependencies\n\n- Append the content below into the `playbook.yml` file\n\n```yml\n- name: web server configuration\n  hosts: web_server\n  become: yes\n  tasks:\n    - name: install the latest version of Git, Apache, Php, Php-Mysqlnd\n      package:\n        name:\n          - git\n          - httpd\n          - php\n          - php-mysqlnd\n        state: latest\n```\n\n- Emphasize that the `become` property can also be used at the play level.\n\n- Explain that the `package` module has the functionality to employ whatever if the package manager is.\n\n- Emphasize that the `Git, Apache Web Server, PHP, and Php-to-Mysql` packages will be installed.\n\n- Append the content below into the `playbook.yml` file.\n\n```yml\n- name: start the server and enable it\n  service:\n    name: httpd\n    state: started\n    enabled: yes\n```\n\n- Explain that this block of configuration is used to start and enable the Apache Web Server.\n\n## Pull the Code and Make Necessary Changes\n\n- Append the content below into the `playbook.yml` file.\n\n```yml\n- name: clone the repo of the website\n  shell: |\n    if [ -z \"$(ls -al /var/www/html | grep .git)\" ]; then\n      git clone https://github.com/kodekloudhub/learning-app-ecommerce.git /var/www/html/\n      echo \"ok\"\n    else\n      echo \"already cloned...\"\n    fi\n  register: result\n\n- name: DEBUG\n  debug:\n    var: result\n\n- name: Replace a default entry with our own\n  lineinfile:\n    path: /var/www/html/index.php\n    regexp: '172\\.20\\.1\\.101'\n    line: \"$link = mysqli_connect('{{ hostvars['db_server'].ansible_host }}', 'remoteUser', 'devenes1234', 'ecomdb');\"\n  when: not result.stdout == \"already cloned...\"\n```\n\n- For the first task, explain that;\n\n  - The first line checks if the result of the `ls -al /var/www/html | grep .git` command is null.\n  - The second line clones the project content into /var/www/html directory.\n\n- Explain the output of the `debug module` **after running the playbook**.\n\n- For the third task, explain that the `lineinfile` module finds the file specified in the path value, searches for the regular expression specified in the `regexp` property, and replaces the matching line with the value of the `line` property. But this task is run only if the standard output of the first task is not \"already cloned...\".\n\n- Append the content below into `playbook.yml` file.\n\n```yml\n- selinux:\n    state: disabled\n\n- name: Restart service httpd\n  service:\n    name: httpd\n    state: restarted\n```\n\n- Explain that we have to disable the `Security Enhanced Linux` in order to be able to query a remote database.\n\n- Shortly explain that the SELinux is a Linux kernel security module that provides a mechanism for supporting access control security policies.\n\n- Run the command below.\n\n```bash\nansible-playbook playbook.yml\n```\n\n- Check if you can see the website on your browser.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevenes%2Fweb-server-provisioning","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevenes%2Fweb-server-provisioning","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevenes%2Fweb-server-provisioning/lists"}