Ansible Server Automation Setup
Ansible is a configuration management tool. Describes the desired state of servers in YAML playbooks, applies it via SSH without agents on remote machines.
Project structure
ansible/
├── inventory/
│ ├── production
│ └── staging
├── group_vars/
│ ├── all.yml
│ └── webservers.yml
├── host_vars/
│ └── web01.yml
├── roles/
│ ├── common/
│ ├── nginx/
│ ├── php/
│ └── myapp/
├── playbooks/
│ ├── setup.yml
│ └── deploy.yml
└── ansible.cfg
Inventory
# inventory/production
[webservers]
web01 ansible_host=10.0.0.10
web02 ansible_host=10.0.0.11
[dbservers]
db01 ansible_host=10.0.0.20
[webservers:vars]
ansible_user=deploy
ansible_ssh_private_key_file=~/.ssh/id_rsa
Setup playbook
# playbooks/setup.yml
---
- name: Setup web servers
hosts: webservers
become: true
roles:
- common
- nginx
- php
- myapp
vars:
app_name: myapp
app_domain: example.com
php_version: "8.3"
Role: nginx
# roles/nginx/tasks/main.yml
---
- name: Install Nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: yes
- name: Deploy Nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: "/etc/nginx/sites-available/{{ app_name }}"
owner: root
group: root
mode: "0644"
notify: reload nginx
- name: Enable site
ansible.builtin.file:
src: "/etc/nginx/sites-available/{{ app_name }}"
dest: "/etc/nginx/sites-enabled/{{ app_name }}"
state: link
notify: reload nginx
- name: Start and enable Nginx
ansible.builtin.service:
name: nginx
state: started
enabled: yes
# roles/nginx/handlers/main.yml
---
- name: reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
Role: application deployment
# roles/myapp/tasks/main.yml
---
- name: Create deploy user
ansible.builtin.user:
name: deploy
shell: /bin/bash
groups: www-data
append: yes
- name: Clone/update repository
ansible.builtin.git:
repo: "https://github.com/user/{{ app_name }}.git"
dest: "/var/www/{{ app_name }}"
version: "{{ app_branch | default('main') }}"
force: yes
become_user: deploy
- name: Install PHP dependencies
community.general.composer:
command: install
working_dir: "/var/www/{{ app_name }}"
no_dev: yes
optimize_autoloader: yes
become_user: deploy
- name: Copy .env file
ansible.builtin.template:
src: .env.j2
dest: "/var/www/{{ app_name }}/.env"
owner: deploy
group: www-data
mode: "0640"
- name: Run migrations
ansible.builtin.command:
cmd: php artisan migrate --force
chdir: "/var/www/{{ app_name }}"
become_user: deploy
changed_when: false
- name: Clear caches
ansible.builtin.command:
cmd: "php artisan {{ item }}"
chdir: "/var/www/{{ app_name }}"
loop:
- config:cache
- route:cache
- view:cache
become_user: deploy
changed_when: false
Deploy playbook
# playbooks/deploy.yml
---
- name: Deploy application
hosts: webservers
serial: 1 # one server at a time (rolling)
become: true
vars:
app_branch: "{{ branch | default('main') }}"
pre_tasks:
- name: Enable maintenance mode
ansible.builtin.command:
cmd: php artisan down --refresh=15
chdir: "/var/www/{{ app_name }}"
roles:
- myapp
post_tasks:
- name: Disable maintenance mode
ansible.builtin.command:
cmd: php artisan up
chdir: "/var/www/{{ app_name }}"
# Execution
ansible-playbook -i inventory/production playbooks/deploy.yml
# Deploy specific branch
ansible-playbook -i inventory/production playbooks/deploy.yml \
-e "branch=feature/new-api"
# Dry run
ansible-playbook -i inventory/production playbooks/setup.yml \
--check --diff
Vault for secrets
# Encrypt secrets file
ansible-vault encrypt group_vars/all/vault.yml
# Run with vault
ansible-playbook playbooks/deploy.yml --ask-vault-pass
# or
ansible-playbook playbooks/deploy.yml --vault-password-file ~/.vault_pass
Timeline
Ansible automation for typical PHP project (setup + deploy playbooks): 3–5 days.







