diff --git a/tutorials/devops-recipe-using-ansible-to-build-a-web-server/01.en.md b/tutorials/devops-recipe-using-ansible-to-build-a-web-server/01.en.md new file mode 100644 index 000000000..cf91235ec --- /dev/null +++ b/tutorials/devops-recipe-using-ansible-to-build-a-web-server/01.en.md @@ -0,0 +1,350 @@ +--- +SPDX-License-Identifier: MIT +path: "/tutorials/devops-recipe-using-ansible-to-build-a-web-server" +slug: "devops-recipe-using-ansible-to-build-a-web-server" +date: "2025-01-16" +title: "How to setup an Nginx webserver using Ansible on Ubuntu" +short_description: "This tutorial is for beginner DevOps enthusiasts and it shows how to simply setup an Nginx web server, install Docker and configure a Let’s Encrypt certificate" +tags: ["Ansible", "Docker", "Nginx", "Certbot"] +author: "Sergiu Chilat" +author_link: "https://github.com/sergiuchilat" +author_img: "https://avatars.githubusercontent.com/u/14886372" +author_description: "IT enthusiast for almost 20 years:)" +language: "en" +available_languages: ["en"] +header_img: "header-4" +cta: "dedicated" +--- + +## Introduction + +This tutorial is for beginner DevOps enthusiasts and it illustrate how to simply setup an Nginx web server, install Docker and DockerCompose, and configure a Let’s Encrypt certificate managed by Certbot. +The proposed solution is based on Ansible playbooks. + +**Prerequisites** + +- A local device + - Has Ansible installed (see [Ansible documentation](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html)) + - Has an SSH key pair +- A remote VPS instance with Ubuntu (see this [getting started](https://docs.hetzner.com/cloud/servers/getting-started/creating-a-server/)) + - Add the public key of your local device to your remote VPS. You can find a simple tutorial [here](https://community.hetzner.com/tutorials/add-ssh-key-to-your-hetzner-cloud). + +## Before you start + +Before you start, make sure you have the following files and directories: + +``` +ansible-project/ +├── ansible.cfg # Ansible configuration file +├── inventory # Ansible inventory +├── env.yml # Environment variables +└── playbooks/ # Directory for the playbooks that will be added in the steps below +``` + +* `~/ansible-project/ansible.cfg` + + Here you can set the inventory file that Ansible will use by default when running the playbooks. + + ```ini + [defaults] + inventory = inventory + ``` + +* `~/ansible-project/inventory` + + Here you can add the IP addresses of the servers that you want to configure. + + ```ini + [all] + 127.0.0.1 + 127.0.0.2 + 127.0.0.3 + ``` + +* `~/ansible-project/env.yml` + + This project uses some variables that are stored in the `env.yml` file that is imported in all playbooks. + + ```yaml + APP_MAIN_DOMAIN: "example.com" + LETS_ENCRYPT_EMAIL: "your_email@mail.com" + NGINX_MAX_BODY_SIZE: "50M" + TIMEZONE: "Europe/Chisinau" + ``` + + * APP_MAIN_DOMAIN: `example.com` - the main domain that will be used for the server + * LETS_ENCRYPT_EMAIL: `your_email@example.com` - the email that will be used for the Let's Encrypt certificate generation + * NGINX_MAX_BODY_SIZE: `50M` - the maximum body size that Nginx will accept + * TIMEZONE: `Europe/Chisinau` - the timezone that will be set on the server + +* `~/ansible-project/playbooks` + + Create a directory for the playbooks. + +## Step 1 - Configure the web sever + +In this sample the timezone of the server is set to the `TIMEZONE` variable. This playbook can be extended to set other configurations as well, depending on your needs. + +`~/ansible-project/playbooks/configure-server.yml` + +```yaml +- name: Set the system timezone + hosts: all + become: yes + user: root + + vars_files: + - ../env.yml + + tasks: + - name: Set timezone + ansible.builtin.command: + cmd: timedatectl set-timezone {{ TIMEZONE }} +``` + +## Step 2 - Install and configure Nginx + +In this step we will install Nginx and configure it to serve the main domain. +Below is the code that will install Nginx and configure it to accept a maximum body size of 50M. + +`~/ansible-project/playbooks/install-nginx.yml` + +```yaml +- name: Install Nginx + hosts: all + become: yes + user: root + + vars_files: + - ../env.yml + + tasks: + - name: Update apt cache + apt: + update_cache: yes + + - name: Install nginx + apt: + name: nginx + state: latest + + - name: Ensure client_max_body_size is set inside the HTTP block + ansible.builtin.blockinfile: + path: /etc/nginx/nginx.conf + marker: "# {mark} ANSIBLE MANAGED BLOCK" + block: | + client_max_body_size {{ NGINX_MAX_BODY_SIZE }}; + insertafter: '^http\s*{' + backup: yes + + - name: Reload Nginx to apply changes + ansible.builtin.systemd: + name: nginx + state: reloaded +``` + +## Step 3 - Install Docker and Docker Compose + +The following code will install Docker and Docker compose to your server. + +`~/ansible-project/playbooks/install-docker.yml` + +```yaml +- name: Install Docker on Ubuntu + hosts: all + remote_user: root + become: true + vars: + arch_mapping: # Map ansible architecture {{ ansible_architecture }} names to Docker's architecture names + x86_64: amd64 + aarch64: arm64 + + tasks: + - name: Update and upgrade all packages to the latest version + ansible.builtin.apt: + update_cache: true + upgrade: dist + cache_valid_time: 3600 + + - name: Install required packages + ansible.builtin.apt: + pkg: + - apt-transport-https + - ca-certificates + - curl + - gnupg + - software-properties-common + + - name: Create directory for Docker's GPG key + ansible.builtin.file: + path: /etc/apt/keyrings + state: directory + mode: '0755' + + - name: Add Docker's official GPG key + ansible.builtin.apt_key: + url: https://download.docker.com/linux/ubuntu/gpg + keyring: /etc/apt/keyrings/docker.gpg + state: present + + - name: Print architecture variables + ansible.builtin.debug: + msg: "Architecture: {{ ansible_architecture }}, Codename: {{ ansible_lsb.codename }}" + + - name: Add Docker repository + ansible.builtin.apt_repository: + repo: >- + deb [arch={{ arch_mapping[ansible_architecture] | default(ansible_architecture) }} + signed-by=/etc/apt/keyrings/docker.gpg] + https://download.docker.com/linux/ubuntu {{ ansible_lsb.codename }} stable + filename: docker + state: present + + - name: Install Docker and related packages + ansible.builtin.apt: + name: "{{ item }}" + state: present + update_cache: true + loop: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + + - name: Add Docker group + ansible.builtin.group: + name: docker + state: present + + - name: Add user to Docker group + ansible.builtin.user: + name: "{{ ansible_user }}" + groups: docker + append: true + + - name: Enable and start Docker services + ansible.builtin.systemd: + name: "{{ item }}" + enabled: true + state: started + loop: + - docker.service + - containerd.service +``` + +## Step 4 - Install Certbot and configure Let’s Encrypt certificate + +`~/ansible-project/playbooks/install-certbot.yml` + +The following code will install Certbot and configure a Let's Encrypt certificate for the main domain. + +```yaml + +- name: Secure the site with Let's Encrypt + hosts: all + become: true + user: root + + vars_files: + - ../env.yml + + vars: + webroot_path: '/var/www/html' # the root path of your site + certbot_source_directory: /usr/local/certbot-src + certbot_executable_path: "{{ certbot_source_directory }}/venv/bin/certbot" + email: "{{ LETS_ENCRYPT_EMAIL }}" + domain: "{{ APP_MAIN_DOMAIN }}" + + tasks: + - name: Install required packages for certbot + ansible.builtin.apt: + name: + - python3 + - python3-venv + - gcc + - libaugeas0 + - libssl-dev + - libffi-dev + - ca-certificates + - openssl + - git + + - name: Clone the certbot source directory + ansible.builtin.git: + depth: 1 + repo: https://github.com/certbot/certbot + dest: "{{ certbot_source_directory }}" + update: true + + - name: Create certbot in virtual environment + ansible.builtin.command: python3 tools/venv.py + args: + chdir: "{{ certbot_source_directory }}" + + - name: Generate the SSL certificate + ansible.builtin.command: "{{ certbot_executable_path }} --nginx -d {{ domain }} --non-interactive --agree-tos --email {{ email }}" + + - name: Set up automatic renewal + ansible.builtin.cron: + name: "Certbot automatic renewal" + job: "{{ certbot_executable_path }} renew --quiet" + minute: "11" + hour: "11" + +``` + +You can find the variables used in this playbook in the `env.yml` file: + +- `LETS_ENCRYPT_EMAIL` - the email that will be used for the Let's Encrypt certificate generation +- `APP_MAIN_DOMAIN` - the main domain that will be used for the server and the Let's Encrypt certificate + +## Step 5 - Run the playbooks + +To run the playbooks, execute the following commands: + +```bash +cd ~/ansible-project +ansible-playbook ~/ansible-project/playbooks/configure-server.yml +ansible-playbook ~/ansible-project/playbooks/install-nginx.yml +ansible-playbook ~/ansible-project/playbooks/install-docker.yml +ansible-playbook ~/ansible-project/playbooks/install-certbot.yml +``` + +After running the playbooks, you should have a web server running Nginx, Docker, Docker Compose and a Let's Encrypt certificate. +You can find the Let's Encrypt certificate on the remote VPS instance in `/etc/letsencrypt/live/example.com`. + +## Conclusion + +This tutorial is a simple way to setup a web server using Ansible playbooks. The playbooks can be extended to include more configurations and services. + +##### License: MIT + +