Ansible setup for website server automation

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815

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.