🎁 New User? Get 20% off your first purchase with code NEWUSER20 Register Now β†’
Menu

Categories

Ansible for Beginners: Automating Your IT Infrastructure Step by Step

Ansible for Beginners: Automating Your IT Infrastructure Step by Step

What Is Ansible and Why Should You Learn It?

Ansible is an open-source automation tool that lets you configure servers, deploy applications, and orchestrate complex workflows β€” all without installing agents on your target machines. It uses SSH and simple YAML files called playbooks to describe what you want your infrastructure to look like.

If you've ever spent hours manually configuring servers, installing packages, or deploying applications across multiple machines, Ansible will change your life. Write it once, run it everywhere, and know that every server is configured identically.

Installing Ansible

Ansible runs on a control node (your workstation or a management server) and connects to managed nodes via SSH.

On Ubuntu/Debian

sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install -y ansible

On RHEL/CentOS/Fedora

sudo dnf install -y ansible-core

Via pip (Any Platform)

pip install ansible

Verify installation:

ansible --version
# ansible [core 2.17.x]

Setting Up Your Inventory

The inventory file tells Ansible which servers to manage. Create /etc/ansible/hosts or a local inventory.ini:

[webservers]
web1.example.com
web2.example.com
192.168.1.50

[databases]
db1.example.com ansible_port=2222
db2.example.com

[all:vars]
ansible_user=deploy
ansible_python_interpreter=/usr/bin/python3

Testing Connectivity

# Ping all hosts
ansible all -i inventory.ini -m ping

# Ping specific group
ansible webservers -i inventory.ini -m ping

Ad-Hoc Commands: Quick One-Liners

Before writing playbooks, Ansible's ad-hoc commands are useful for quick tasks:

# Check disk space on all servers
ansible all -m command -a "df -h"

# Install a package on webservers
ansible webservers -m apt -a "name=nginx state=present" --become

# Restart a service
ansible webservers -m service -a "name=nginx state=restarted" --become

# Copy a file to all servers
ansible all -m copy -a "src=./config.txt dest=/etc/app/config.txt"

Your First Playbook

Playbooks are YAML files that describe the desired state of your infrastructure:

# setup-webserver.yml
---
- name: Configure Web Servers
  hosts: webservers
  become: yes
  vars:
    app_port: 8080
    app_user: www-data

  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: Install required packages
      apt:
        name:
          - nginx
          - certbot
          - python3-certbot-nginx
          - ufw
        state: present

    - name: Start and enable Nginx
      service:
        name: nginx
        state: started
        enabled: yes

    - name: Configure firewall - allow HTTP
      ufw:
        rule: allow
        port: "80"
        proto: tcp

    - name: Configure firewall - allow HTTPS
      ufw:
        rule: allow
        port: "443"
        proto: tcp

    - name: Deploy Nginx configuration
      template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/sites-available/default
      notify: Restart Nginx

  handlers:
    - name: Restart Nginx
      service:
        name: nginx
        state: restarted

Run the playbook:

ansible-playbook -i inventory.ini setup-webserver.yml

Using Variables and Templates

Jinja2 templates make your configurations dynamic:

# templates/nginx.conf.j2
server {
    listen 80;
    server_name {{ domain_name }};

    location / {
        proxy_pass http://127.0.0.1:{{ app_port }};
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Variable Precedence

Variables can be defined in multiple places (lowest to highest priority):

  1. Inventory variables
  2. Group vars (group_vars/webservers.yml)
  3. Host vars (host_vars/web1.yml)
  4. Playbook vars
  5. Extra vars (-e "var=value" on command line)

Organizing with Roles

Roles structure your automation into reusable components:

ansible-galaxy init roles/webserver

This creates a standard directory structure:

roles/webserver/
β”œβ”€β”€ tasks/main.yml
β”œβ”€β”€ handlers/main.yml
β”œβ”€β”€ templates/
β”œβ”€β”€ files/
β”œβ”€β”€ vars/main.yml
β”œβ”€β”€ defaults/main.yml
└── meta/main.yml

Use roles in your playbook:

---
- name: Setup Infrastructure
  hosts: all
  become: yes
  roles:
    - common
    - { role: webserver, when: "'webservers' in group_names" }
    - { role: database, when: "'databases' in group_names" }

Practical Example: Full Application Deployment

# deploy-app.yml
---
- name: Deploy Application
  hosts: webservers
  become: yes
  vars:
    app_repo: "https://github.com/company/myapp.git"
    app_dir: "/var/www/myapp"
    app_branch: "main"

  tasks:
    - name: Clone/update application repository
      git:
        repo: "{{ app_repo }}"
        dest: "{{ app_dir }}"
        version: "{{ app_branch }}"
        force: yes
      register: git_result

    - name: Install dependencies
      command: npm install --production
      args:
        chdir: "{{ app_dir }}"
      when: git_result.changed

    - name: Run database migrations
      command: npm run migrate
      args:
        chdir: "{{ app_dir }}"
      when: git_result.changed

    - name: Restart application
      systemd:
        name: myapp
        state: restarted
        daemon_reload: yes
      when: git_result.changed

Error Handling and Conditionals

tasks:
  - name: Check if config exists
    stat:
      path: /etc/app/config.yml
    register: config_file

  - name: Deploy default config
    template:
      src: default-config.yml.j2
      dest: /etc/app/config.yml
    when: not config_file.stat.exists

  - name: Attempt risky operation
    command: /opt/app/migrate.sh
    register: migrate_result
    ignore_errors: yes

  - name: Rollback if migration failed
    command: /opt/app/rollback.sh
    when: migrate_result.failed

Ansible Vault: Managing Secrets

# Encrypt a file
ansible-vault encrypt secrets.yml

# Edit encrypted file
ansible-vault edit secrets.yml

# Run playbook with vault
ansible-playbook site.yml --ask-vault-pass

Best Practices Summary

  • Idempotency β€” Every playbook should be safe to run multiple times
  • Use roles β€” Organize reusable components properly
  • Version control β€” Keep all playbooks in Git
  • Test first β€” Use --check (dry run) and --diff flags
  • Use vault β€” Never store passwords or keys in plain text
  • Tag your tasks β€” Enable running specific parts of playbooks

Conclusion

Ansible is the perfect entry point into infrastructure automation. Its agentless architecture, simple YAML syntax, and massive module library make it accessible to beginners while powerful enough for enterprise environments. Start small β€” automate one repetitive task β€” and gradually build your automation toolkit from there.

Share this article:
Nico Brandt
About the Author

Nico Brandt

JavaScript Development, TypeScript Engineering, Web Application Architecture, Technical Documentation

Nico Brandt is a JavaScript and TypeScript developer focused on building well-structured, maintainable, and scalable web applications.

He works extensively with modern JavaScript and TypeScript across frontend and backend environments, emphasizing type safety, code readability, and predictable application behavior.

...
JavaScript TypeScript Frontend Development Backend APIs Asynchronous Programming

Stay Updated

Subscribe to our newsletter for the latest tutorials, tips, and exclusive offers.