Explore plans starting at ₹699/mo →
DevOps

Ansible Automation for Server Provisioning: From Bare Metal to Production

S
ServerRaja
9 min read
#Infrastructure#Linux#Ubuntu#Tutorial#Automation#DevOps#System Administration
Ansible Automation for Server Provisioning: From Bare Metal to Production

Why Ansible for Server Provisioning?

When you manage more than a handful of servers, manual configuration becomes unsustainable. Ansible is a powerful, agentless automation tool that uses SSH to configure remote servers. You write declarative YAML files called playbooks that describe the desired state of your servers, and Ansible makes it happen.

Unlike other configuration management tools, Ansible requires no agent software on managed nodes. It connects via SSH, executes tasks, and cleans up. This makes it ideal for provisioning ServerRaja cloud servers quickly and consistently.

Installing Ansible

Install Ansible on your control machine:

# 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

# CentOS/RHEL sudo yum install -y epel-release sudo yum install -y ansible

# pip installation (any Linux distribution) pip3 install ansible

# Verify installation ansible --version ```

Setting Up the Inventory

Create an inventory file to define your servers:

# inventory/hosts.ini
[webservers]
web1.serverraja.com ansible_user=deploy
web2.serverraja.com ansible_user=deploy
web3.serverraja.com ansible_user=deploy

[dbservers] db1.serverraja.com ansible_user=deploy db2.serverraja.com ansible_user=deploy

[all:vars] ansible_python_interpreter=/usr/bin/python3 ansible_ssh_common_args='-o StrictHostKeyChecking=no' ```

Test connectivity to all servers:

ansible all -i inventory/hosts.ini -m ping

Writing Your First Playbook

Create a comprehensive server provisioning playbook:

---
# playbooks/provision-server.yml
- name: Provision production servers
  hosts: webservers
  become: yes
  vars:
    app_user: deploy
    app_port: 3000
    ssh_port: 2222
    timezone: Asia/Kolkata

tasks: - name: Set system timezone timezone: name: "{{ timezone }}"

- name: Update all packages apt: update_cache: yes upgrade: dist cache_valid_time: 3600

- name: Install essential packages apt: name: - vim - curl - wget - htop - git - ufw - fail2ban - unattended-upgrades - apt-transport-https - ca-certificates - software-properties-common state: present

- name: Create application user user: name: "{{ app_user }}" shell: /bin/bash groups: sudo append: yes create_home: yes

- name: Set up SSH key for deploy user authorized_key: user: "{{ app_user }}" key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}" state: present

- name: Configure SSH security template: src: templates/sshd_config.j2 dest: /etc/ssh/sshd_config owner: root group: root mode: '0644' notify: Restart SSH

- name: Configure UFW firewall ufw: state: enabled policy: deny direction: incoming

- name: Allow SSH through UFW ufw: rule: allow port: "{{ ssh_port }}" proto: tcp

- name: Allow HTTP through UFW ufw: rule: allow port: '80' proto: tcp

- name: Allow HTTPS through UFW ufw: rule: allow port: '443' proto: tcp

- name: Configure fail2ban template: src: templates/jail.local.j2 dest: /etc/fail2ban/jail.local notify: Restart fail2ban

- name: Set up automatic security updates copy: src: files/50unattended-upgrades dest: /etc/apt/apt.conf.d/50unattended-upgrades owner: root group: root mode: '0644'

- name: Configure sysctl for performance sysctl: name: "{{ item.key }}" value: "{{ item.value }}" state: present reload: yes loop: - { key: 'net.core.somaxconn', value: '65535' } - { key: 'net.ipv4.tcp_max_syn_backlog', value: '65535' } - { key: 'vm.swappiness', value: '10' } - { key: 'net.ipv4.ip_local_port_range', value: '1024 65535' }

- name: Set up log rotation for application template: src: templates/app-logrotate.j2 dest: /etc/logrotate.d/{{ app_user }} owner: root group: root mode: '0644'

handlers: - name: Restart SSH service: name: sshd state: restarted

- name: Restart fail2ban service: name: fail2ban state: restarted ```

Using Roles for Organization

Break your playbooks into reusable roles:

ansible-galaxy init roles/common
ansible-galaxy init roles/nginx
ansible-galaxy init roles/nodejs

A role structure looks like:

roles/
└── nginx/
    ├── tasks/
    │   └── main.yml
    ├── templates/
    │   └── nginx.conf.j2
    ├── handlers/
    │   └── main.yml
    ├── vars/
    │   └── main.yml
    └── defaults/
        └── main.yml

Apply roles in your playbook:

- name: Configure web servers
  hosts: webservers
  become: yes
  roles:
    - common
    - nginx
    - nodejs

Running Playbooks

Execute your playbooks with useful flags:

# Run against all hosts
ansible-playbook -i inventory/hosts.ini playbooks/provision-server.yml

# Dry run (check mode) ansible-playbook -i inventory/hosts.ini playbooks/provision-server.yml --check

# Run with specific tags ansible-playbook -i inventory/hosts.ini playbooks/provision-server.yml --tags "firewall,ssh"

# Limit to specific hosts ansible-playbook -i inventory/hosts.ini playbooks/provision-server.yml --limit web1.serverraja.com

# Use a vault-encrypted variables file ansible-playbook -i inventory/hosts.ini playbooks/provision-server.yml --ask-vault-pass ```

Ansible Vault for Secrets

Encrypt sensitive data with Ansible Vault:

# Create an encrypted file
ansible-vault create secrets.yml

# Edit an encrypted file ansible-vault edit secrets.yml

# Use encrypted variables in playbooks ansible-playbook playbook.yml --ask-vault-pass ```

Conclusion

Ansible transforms server provisioning from a manual, error-prone process into a repeatable, version-controlled workflow. Start with a basic provisioning playbook covering user management, firewall configuration, and essential packages. Then organize your automation into roles as complexity grows. With ServerRaja cloud servers, you can provision an entire fleet in minutes using Ansible.

Ansible Server Provisioning Guide | ServerRaja