Новинка Виртуальный VDS сервер в Нидерландах от 390р
Выберите продукт

Ansible на VDS: inventory, become, SSH-ключи и первый playbook

Разберём, как подготовить Ansible для управления VDS: собрать inventory, настроить SSH-ключи, проверить доступ, аккуратно включить become и написать первый идемпотентный playbook для базовой Linux administration.
Ansible на VDS: inventory, become, SSH-ключи и первый playbook

Ansible удобен тем, что не требует агента на сервере: управляющая машина подключается к VDS по SSH, выполняет модули, возвращает результат и закрывает соединение. Для администратора это означает быстрый старт: нужен корректный inventory, рабочий SSH-доступ, Python на управляемом Linux-сервере и понятная политика повышения привилегий через become.

В этой инструкции соберём минимальный, но уже пригодный для работы набор: отдельный SSH-ключ для автоматизации, структуру проекта, inventory для нескольких VDS, первичную проверку доступа, безопасное использование become и первый playbook, который можно расширять под веб-сервер, базу данных, мониторинг или деплой приложения.

Главная идея: сначала добиваемся предсказуемого подключения и повторяемого результата, а уже потом усложняем роли, переменные, CI/CD и GitOps. Половина проблем с Ansible на VDS начинается не в YAML, а в SSH, sudo и inventory.

Что понадобится перед стартом

У нас будет одна управляющая машина — ноутбук администратора, рабочая станция или отдельный bastion-хост. С неё Ansible будет ходить на один или несколько серверов. Управляемые VDS могут быть на Debian, Ubuntu, AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux или Fedora: для базового сценария отличия в основном касаются пакетного менеджера, названия группы sudo и некоторых служб.

Если вы только выбираете площадку для тестового стенда или продакшена, удобнее сразу брать сервер с чистым Linux-образом и доступом по SSH: например, посмотреть тарифы на облачный VDS и затем подключить его к Ansible как обычный SSH-хост.

Проверьте, что у вас есть:

  • IP-адреса VDS и доступ по SSH, хотя бы временно под root или под пользователем с sudo;
  • локальный OpenSSH-клиент;
  • Ansible на управляющей машине;
  • Python 3 на управляемых серверах;
  • понимание, какой пользователь будет постоянным административным пользователем, например deploy или admin.

Не стоит сразу отключать root-доступ, менять порт SSH и включать сложные firewall-правила до того, как вы проверили новый ключ, пользователя и become. Сначала создаём рабочий путь входа, затем аккуратно ужесточаем политику.

Установка Ansible на управляющую машину

Ansible запускается на управляющей машине. На сам VDS устанавливать Ansible не нужно, если вы используете классический push-подход. На управляемой стороне нужны SSH, Python и права для выполнения задач.

Debian и Ubuntu

sudo apt update
sudo apt install -y ansible openssh-client python3
ansible --version

RHEL-based и Fedora

Для AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux и Fedora чаще используется пакет ansible-core. В некоторых RHEL-based системах может понадобиться подключённый EPEL, но на современных дистрибутивах базового ansible-core обычно хватает для первых playbook.

sudo dnf install -y ansible-core openssh-clients python3
ansible --version

Структура проекта Ansible

Даже для одного VDS лучше не хранить всё в домашней папке вперемешку. Небольшая структура дисциплинирует: inventory отдельно, playbook отдельно, конфигурация Ansible отдельно. Такой проект легко положить в Git, передать коллеге и подключить к CI.

mkdir -p ansible-vds/inventory
mkdir -p ansible-vds/playbooks
mkdir -p ansible-vds/group_vars
cd ansible-vds

Минимальная структура будет такой:

ansible-vds/
  ansible.cfg
  inventory/
    hosts.yml
  group_vars/
    all.yml
  playbooks/
    bootstrap.yml
    base.yml

ansible.cfg задаёт поведение по умолчанию, inventory/hosts.yml описывает серверы и группы, group_vars/all.yml хранит общие переменные, а playbook выполняют конкретную работу. Для маленького проекта это не избыточность, а страховка от хаоса.

Структура проекта Ansible с inventory, group_vars и playbooks

SSH-ключи для Ansible

Не используйте один и тот же ключ для личного входа, деплоя, резервного копирования и автоматизации. Отдельный ключ упрощает ротацию и аудит: если ключ Ansible нужно заменить, вы не ломаете все остальные процессы.

ssh-keygen -t ed25519 -a 100 -f ~/.ssh/ansible_vds -C ansible-vds

Закройте права на приватный ключ:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/ansible_vds
chmod 644 ~/.ssh/ansible_vds.pub

Если у вас пока есть root-доступ к новому VDS, можно временно скопировать ключ root-пользователю, чтобы затем создать постоянного пользователя и настроить sudo через Ansible.

ssh-copy-id -i ~/.ssh/ansible_vds.pub root@203.0.113.10

Перед первым массовым запуском полезно заранее добавить host key сервера в known_hosts. Это снижает риск интерактивных запросов посреди playbook и помогает не отключать проверку host key.

ssh-keyscan -H 203.0.113.10 >> ~/.ssh/known_hosts

Здесь важно не путать два разных типа ключей. SSH-ключ пользователя подтверждает, что вы имеете право войти на сервер. SSH host key подтверждает, что вы подключаетесь именно к тому серверу, а не к подменённому узлу. Отключать host_key_checking ради удобства можно только в одноразовых лабораторных окружениях; для постоянного VDS лучше оставить проверку включённой.

Первый inventory: один VDS и несколько групп

inventory — это карта инфраструктуры для Ansible. В нём описывают хосты, группы и переменные подключения. Даже если сейчас у вас один сервер, называйте группы осмысленно: web, db, monitoring, stage, prod. Когда серверов станет больше, структура уже будет готова.

Создайте файл inventory/hosts.yml:

all:
  children:
    web:
      hosts:
        web1:
          ansible_host: 203.0.113.10
    db:
      hosts:
        db1:
          ansible_host: 203.0.113.11
  vars:
    ansible_user: deploy
    ansible_ssh_private_key_file: ~/.ssh/ansible_vds
    ansible_python_interpreter: /usr/bin/python3
    ansible_become: true
    ansible_become_method: sudo

Пока пользователя deploy может ещё не быть на сервере. Это нормально: ниже мы сделаем bootstrap-playbook, который подключится под root и создаст такого пользователя. После этого основной inventory будет использовать уже не root, а отдельного администратора.

Если сервер один, inventory всё равно может выглядеть так:

all:
  hosts:
    vds1:
      ansible_host: 203.0.113.10
  vars:
    ansible_user: deploy
    ansible_ssh_private_key_file: ~/.ssh/ansible_vds
    ansible_python_interpreter: /usr/bin/python3
    ansible_become: true
    ansible_become_method: sudo

Имя vds1 — это alias внутри Ansible. Оно не обязано совпадать с DNS-именем. Но в продакшене удобнее использовать понятные имена: web-prod-1, db-stage-1, monitoring-1.

ansible.cfg: меньше флагов в командной строке

Чтобы каждый раз не указывать inventory и ключ вручную, создайте ansible.cfg в корне проекта:

[defaults]
inventory = inventory/hosts.yml
remote_user = deploy
private_key_file = ~/.ssh/ansible_vds
host_key_checking = True
retry_files_enabled = False
interpreter_python = auto_silent

[privilege_escalation]
become = True
become_method = sudo
become_ask_pass = False

Параметр host_key_checking лучше держать в значении True. Если после переустановки VDS вы видите предупреждение о смене host key, не игнорируйте его автоматически. Сначала убедитесь, что сервер действительно переустановлен, затем удалите старую запись.

ssh-keygen -R 203.0.113.10
ssh-keyscan -H 203.0.113.10 >> ~/.ssh/known_hosts

become_ask_pass = False означает, что Ansible не будет спрашивать пароль sudo. Для этого у пользователя должен быть настроен passwordless sudo либо нужно запускать playbook с опцией запроса пароля. Для автоматизации VDS чаще выбирают sudo без пароля для отдельного административного пользователя, но доступ к самому ключу защищают правами, passphrase и политикой хранения секретов.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Bootstrap: создаём пользователя для Ansible

Первый запуск часто выполняется под root, потому что на новом VDS ещё нет постоянного администратора. Задача bootstrap — подготовить сервер так, чтобы дальнейшие playbook работали через обычного пользователя с become.

На минимальных образах Python может отсутствовать. Если ansible all -m ping -u root падает именно из-за Python, один раз выполните raw-команду под root:

ansible all -u root -m raw -a 'test -x /usr/bin/python3 || (command -v apt-get && apt-get update && apt-get install -y python3 sudo) || (command -v dnf && dnf install -y python3 sudo)'

Теперь создайте playbooks/bootstrap.yml:

- name: Bootstrap VDS access
  hosts: all
  gather_facts: true
  remote_user: root
  vars:
    admin_user: deploy
  tasks:
    - name: Install sudo and Python on Debian and Ubuntu
      ansible.builtin.apt:
        name:
          - sudo
          - python3
        state: present
        update_cache: true
      when: ansible_os_family == 'Debian'

    - name: Install sudo and Python on RHEL-based systems and Fedora
      ansible.builtin.dnf:
        name:
          - sudo
          - python3
        state: present
      when: ansible_os_family == 'RedHat'

    - name: Create admin user
      ansible.builtin.user:
        name: "{{ admin_user }}"
        shell: /bin/bash
        create_home: true
        state: present

    - name: Add admin user to sudo group on Debian and Ubuntu
      ansible.builtin.user:
        name: "{{ admin_user }}"
        groups: sudo
        append: true
      when: ansible_os_family == 'Debian'

    - name: Add admin user to wheel group on RHEL-based systems and Fedora
      ansible.builtin.user:
        name: "{{ admin_user }}"
        groups: wheel
        append: true
      when: ansible_os_family == 'RedHat'

    - name: Install SSH public key for admin user
      ansible.builtin.authorized_key:
        user: "{{ admin_user }}"
        state: present
        key: "{{ lookup('file', '~/.ssh/ansible_vds.pub') }}"

    - name: Allow passwordless sudo for admin user
      ansible.builtin.copy:
        dest: "/etc/sudoers.d/{{ admin_user }}"
        owner: root
        group: root
        mode: '0440'
        content: |
          {{ admin_user }} ALL=(ALL) NOPASSWD: ALL
        validate: /usr/sbin/visudo -cf %s

В этом playbook есть важный момент: группа администраторов отличается по семействам ОС. В Debian и Ubuntu это обычно sudo, в AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux и Fedora — wheel. Поэтому задачи разделены через when.

Запустите bootstrap, явно указав временного пользователя root, если в ansible.cfg уже прописан deploy:

ansible-playbook playbooks/bootstrap.yml -u root

После успешного выполнения проверьте вход под новым пользователем:

ssh -i ~/.ssh/ansible_vds deploy@203.0.113.10
sudo id

Если команда sudo id выполняется без запроса пароля и показывает uid=0(root), значит become у Ansible тоже должен работать.

Passwordless sudo — сильное право. Его стоит выдавать не личным пользователям всех сотрудников, а отдельному техническому пользователю с контролируемым SSH-ключом, журналированием и понятной процедурой ротации.

Проверяем inventory и SSH-доступ

Теперь можно проверить, что Ansible видит хосты из inventory:

ansible-inventory --graph

Проверка подключения:

ansible all -m ping

Модуль ping в Ansible — это не ICMP ping. Он подключается по SSH, запускает Python на удалённой машине и возвращает результат. Если здесь ошибка, проблема обычно в SSH-ключе, пользователе, Python или host key.

Проверьте выполнение простой команды без повышения привилегий:

ansible all -m command -a 'whoami'

Проверьте выполнение команды с become:

ansible all -b -m command -a 'id'

Если первая команда возвращает deploy, а вторая — root, базовая цепочка работает: inventory найден, SSH-ключ принят, пользователь существует, sudo настроен, become поднимает права.

Первый рабочий playbook для базовой настройки VDS

Теперь напишем playbook, который устанавливает базовые пакеты, включает службу синхронизации времени и создаёт служебный каталог. Он не делает ничего разрушительного, но показывает ключевые принципы: условия по семейству ОС, идемпотентность и выполнение через become.

Создайте playbooks/base.yml:

- name: Base setup for VDS
  hosts: all
  become: true
  gather_facts: true
  tasks:
    - name: Install base packages on Debian and Ubuntu
      ansible.builtin.apt:
        name:
          - curl
          - git
          - htop
          - tmux
          - chrony
        state: present
        update_cache: true
        cache_valid_time: 3600
      when: ansible_os_family == 'Debian'

    - name: Install base packages on RHEL-based systems and Fedora
      ansible.builtin.dnf:
        name:
          - curl
          - git
          - htop
          - tmux
          - chrony
        state: present
      when: ansible_os_family == 'RedHat'

    - name: Enable chrony on Debian and Ubuntu
      ansible.builtin.service:
        name: chrony
        state: started
        enabled: true
      when: ansible_os_family == 'Debian'

    - name: Enable chronyd on RHEL-based systems and Fedora
      ansible.builtin.service:
        name: chronyd
        state: started
        enabled: true
      when: ansible_os_family == 'RedHat'

    - name: Create application directory
      ansible.builtin.file:
        path: /opt/apps
        state: directory
        owner: root
        group: root
        mode: '0755'

    - name: Set managed server notice
      ansible.builtin.copy:
        dest: /etc/motd
        owner: root
        group: root
        mode: '0644'
        content: |
          This VDS is managed by Ansible.
          Manual changes may be overwritten by playbooks.

Запустите сначала в режиме проверки:

ansible-playbook playbooks/base.yml --check --diff

--check показывает, что Ansible собирается изменить, а --diff полезен для файлов: видно, какие строки будут добавлены или удалены. Не все модули идеально поддерживают check mode, но для apt, dnf, file и copy это хороший способ снизить риск.

Если вывод ожидаемый, примените изменения:

ansible-playbook playbooks/base.yml

Повторный запуск должен показать минимум изменений или полный ok. Это и есть идемпотентность: playbook можно запускать много раз, а сервер будет приходить к заданному состоянию, а не выполнять одно и то же действие снова и снова.

Как группировать VDS в inventory

Когда серверов становится больше, inventory превращается в основу всей devops automation. Важно не сваливать все хосты в одну группу servers. Группы должны отвечать на практические вопросы: где продакшен, где staging, где web, где база, где мониторинг.

all:
  children:
    production:
      children:
        prod_web:
          hosts:
            web-prod-1:
              ansible_host: 203.0.113.10
            web-prod-2:
              ansible_host: 203.0.113.12
        prod_db:
          hosts:
            db-prod-1:
              ansible_host: 203.0.113.11
    staging:
      children:
        stage_web:
          hosts:
            web-stage-1:
              ansible_host: 198.51.100.10
  vars:
    ansible_user: deploy
    ansible_ssh_private_key_file: ~/.ssh/ansible_vds
    ansible_python_interpreter: /usr/bin/python3
    ansible_become: true
    ansible_become_method: sudo

Теперь можно запускать playbook только на staging:

ansible-playbook playbooks/base.yml --limit staging

Или только на web-серверах продакшена:

ansible-playbook playbooks/base.yml --limit prod_web

--limit — полезная страховка, но не замена аккуратной структуре. Если вы случайно назвали группу слишком широко, Ansible честно выполнит задачу на всех подходящих хостах.

Терминал с успешным запуском Ansible playbook на нескольких серверах

Где хранить переменные и секреты

Inventory должен оставаться читаемой картой серверов. Общие настройки лучше переносить в group_vars/all.yml, а специфичные — в файлы групп. Например, создайте group_vars/all.yml:

admin_user: deploy
base_packages:
  - curl
  - git
  - htop
  - tmux

Для продакшена можно добавить group_vars/production.yml:

environment_name: production
backup_enabled: true
monitoring_enabled: true

Для staging — group_vars/staging.yml:

environment_name: staging
backup_enabled: false
monitoring_enabled: true

Так вы уменьшаете копипасту и снижаете риск, что staging внезапно получит настройки production. Особенно это важно для задач с базами данных, firewall, SSL, доменами и расписаниями резервного копирования.

Пароли баз данных, приватные ключи, токены API и резервные коды нельзя хранить в открытом виде. Для начала подойдёт Ansible Vault, а в более зрелых процессах — внешний менеджер секретов. Если вы уже строите GitOps-подход, пригодится отдельный разбор про SOPS, age и безопасное хранение секретов в Git.

Become: когда включать глобально, а когда точечно

become говорит Ansible выполнить задачу с повышенными правами. В примерах выше мы включили его глобально: become: true на уровне play. Это удобно для базовой настройки сервера, где почти все задачи требуют root: установка пакетов, изменение файлов в /etc, управление службами.

Но в playbook деплоя приложения лучше не делать всё от root. Например, получение кода из Git, сборка фронтенда или запуск composer/npm часто должны идти от пользователя приложения. Тогда become включают точечно или используют become_user.

- name: Create release directory as app user
  hosts: web
  become: true
  tasks:
    - name: Ensure release directory exists
      ansible.builtin.file:
        path: /var/www/example/releases
        state: directory
        owner: www-data
        group: www-data
        mode: '0755'

    - name: Show app user identity
      ansible.builtin.command: id
      become_user: www-data
      changed_when: false

Для RHEL-based систем пользователь веб-сервера может называться apache, а не www-data. Поэтому для переносимых ролей такие значения лучше выносить в переменные по семействам ОС. Если дальше вы автоматизируете Nginx и PHP-FPM, посмотрите практику с несколькими PHP-FPM пулами под Nginx: там особенно важно не смешивать системные и прикладные права.

Типовые ошибки и быстрая диагностика

Permission denied по SSH

Проверьте, что Ansible использует именно нужный ключ и пользователя:

ansible all -m ping -vvvv

Флаг -vvvv покажет фактическую SSH-команду. Частые причины: приватный ключ имеет слишком широкие права, публичный ключ не добавлен в authorized_keys, пользователь указан не тот, на сервере отключён вход по ключам или SSH слушает нестандартный порт.

Если порт нестандартный, добавьте его в inventory:

all:
  hosts:
    vds1:
      ansible_host: 203.0.113.10
      ansible_port: 2222

sudo: a password is required

Это означает, что become сработал, но sudo запросил пароль. Для ручного запуска можно использовать:

ansible-playbook playbooks/base.yml --ask-become-pass

Для регулярной автоматизации лучше настроить sudoers для технического пользователя и защитить доступ к SSH-ключу. Проверяйте sudoers только через visudo или через Ansible-модуль copy с параметром validate, как в bootstrap-примере.

Python не найден

На минимальных образах VDS Python может отсутствовать. Тогда Ansible не сможет выполнить большинство модулей. Первичную установку Python можно сделать вручную по SSH или через raw-команду под root.

Для Debian и Ubuntu:

apt update
apt install -y python3 sudo

Для RHEL-based систем и Fedora:

dnf install -y python3 sudo

Host key verification failed

Ошибка означает, что SSH не доверяет host key сервера или видит его изменение. Если VDS новый, добавьте ключ через ssh-keyscan. Если сервер переустанавливался, сначала убедитесь, что IP действительно ваш, затем удалите старую запись через ssh-keygen -R.

Практические правила для Ansible на VDS

  • Держите inventory, playbook и переменные в Git, но не храните там приватные ключи и секреты в открытом виде.
  • Запускайте опасные изменения сначала с --check --diff, затем с --limit на одном staging-хосте.
  • Не отключайте host_key_checking без крайней необходимости.
  • Разделяйте bootstrap, базовую настройку, безопасность, web-стек и деплой приложения на разные playbook или роли.
  • Используйте понятные имена групп: production, staging, web, db, monitoring.
  • Не превращайте Ansible в набор shell-скриптов. Если есть модуль apt, dnf, file, copy, service, используйте модуль.
  • После ручных правок на сервере переносите изменения в playbook, иначе инфраструктура быстро перестанет быть воспроизводимой.

Куда развивать проект дальше

После первого playbook логичный следующий шаг — роли. Например, отдельные роли common, users, firewall, nginx, php, mysql, backup. Роли делают проект более модульным: один и тот же базовый набор можно применить к новым VDS без копирования YAML между файлами.

Для продакшена полезны теги. Например, базовые пакеты, firewall, пользователи и сервисы можно пометить разными tags, чтобы запускать только нужную часть playbook. Но не злоупотребляйте тегами вместо нормального разделения на роли: чрезмерно сложная матрица тегов быстро становится непонятной.

И наконец, добавьте привычку проверять изменения маленькими шагами. Ansible позволяет быстро применить конфигурацию к десяткам VDS, но эта же сила превращает ошибку в массовую проблему. Хороший inventory, отдельные окружения, --check, --diff, --limit и аккуратный become — базовый набор безопасности для повседневной Linux administration и devops automation.

Итог

Для старта Ansible на VDS не нужен большой фреймворк. Достаточно отдельного SSH-ключа, проверенного host key, понятного inventory, пользователя с sudo, аккуратной настройки become и одного идемпотентного playbook. Такой фундамент уже решает реальные задачи: базовая настройка серверов, установка пакетов, подготовка каталогов, включение служб и контроль различий между staging и production.

Когда эта основа работает стабильно, её можно расширять ролями, шаблонами, секретами, CI/CD и мониторингом. Главное — не пропускать базовый слой. Надёжная автоматизация начинается не с красивого YAML, а с воспроизводимого SSH-доступа, понятных прав и inventory, которому можно доверять.

Поделиться статьей

Вам будет интересно

PostgreSQL pg_hba.conf на VDS: почему trust 0.0.0.0/0 опасен и как открыть доступ правильно OpenAI Статья написана AI (GPT 5)

PostgreSQL pg_hba.conf на VDS: почему trust 0.0.0.0/0 опасен и как открыть доступ правильно

PostgreSQL не подключается извне, и хочется поставить trust для всех адресов? Разбираем безопасный путь: listen_addresses, точные ...
PostgreSQL на VDS: pg_hba.conf, SCRAM и TLS для безопасного доступа OpenAI Статья написана AI (GPT 5)

PostgreSQL на VDS: pg_hba.conf, SCRAM и TLS для безопасного доступа

PostgreSQL удобно держать на VDS, но открывать порт 5432 «как есть» нельзя. Разберём, как включить сетевые подключения, описать пр ...
systemd-tmpfiles: безопасная очистка /tmp и кэшей вместо cron rm -rf OpenAI Статья написана AI (GPT 5)

systemd-tmpfiles: безопасная очистка /tmp и кэшей вместо cron rm -rf

Когда /tmp разрастается, рука тянется к cron и rm -rf. Разбираем, почему это рискованно, как работает systemd-tmpfiles, где лежат ...