Ansible Playbook — automatyzacja konfiguracji serwera
Opublikowano: 9 kwietnia 2026 · Kategoria: DevOps
Konfiguracja nowego VPS ręcznie to strata czasu i źródło błędów. Zrób to raz przez Ansible Playbook — potem każdy nowy serwer konfigurujesz jedną komendą. Oto jak pisać playbooki od podstaw do zaawansowanych roles.
Instalacja Ansible
# Ubuntu/Debian (control node — maszyna z której uruchamiasz Ansible) sudo apt update && sudo apt install ansible # macOS brew install ansible # pip (zawsze aktualna wersja) pip3 install ansible # Sprawdź wersję ansible --version
Inventory — lista serwerów
Inventory (hosts.ini lub hosts.yaml) definiuje serwery i ich grupy. Ansible łączy się z nimi przez SSH:
# hosts.ini [webservers] web1.example.com ansible_user=root ansible_port=22 web2.example.com ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa [databases] db1.example.com ansible_user=root [all:vars] ansible_python_interpreter=/usr/bin/python3
# Test połączenia z wszystkimi hostami ansible -i hosts.ini all -m ping # Test konkretnej grupy ansible -i hosts.ini webservers -m ping
Struktura playbooka YAML
Playbook to plik YAML z listą play'ów. Każdy play ma: hosts (cel), tasks (lista zadań), opcjonalnie vars, handlers, roles:
# site.yaml — podstawowa struktura
---
- name: Konfiguracja serwera web
hosts: webservers
become: yes # sudo
vars:
domain: example.com
php_version: "8.3"
db_user: appuser
db_name: myapp
handlers:
- name: reload nginx
service:
name: nginx
state: reloaded
- name: reload php-fpm
service:
name: "php{{ php_version }}-fpm"
state: reloaded
tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Install Nginx
apt:
name: nginx
state: present
notify: reload nginx Przykład playbooka: LEMP + UFW + Certbot
# lemp-setup.yaml
---
- name: Konfiguracja stosu LEMP
hosts: webservers
become: yes
vars:
domain: "example.com"
php_version: "8.3"
letsencrypt_email: "[email protected]"
db_root_password: "{{ vault_db_root_password }}"
tasks:
# --- Nginx ---
- name: Zainstaluj Nginx
apt:
name: nginx
state: present
- name: Uruchom i włącz Nginx
service:
name: nginx
state: started
enabled: yes
# --- PHP-FPM ---
- name: Zainstaluj PHP i rozszerzenia
apt:
name:
- "php{{ php_version }}-fpm"
- "php{{ php_version }}-mysql"
- "php{{ php_version }}-curl"
- "php{{ php_version }}-gd"
- "php{{ php_version }}-mbstring"
- "php{{ php_version }}-xml"
- "php{{ php_version }}-zip"
state: present
# --- MySQL ---
- name: Zainstaluj MySQL Server
apt:
name: mysql-server
state: present
# --- UFW Firewall ---
- name: Pozwól SSH przez UFW
ufw:
rule: allow
name: OpenSSH
- name: Pozwól HTTP i HTTPS
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- "80"
- "443"
- name: Włącz UFW
ufw:
state: enabled
policy: deny
# --- Certbot ---
- name: Zainstaluj snapd
apt:
name: snapd
state: present
- name: Zainstaluj certbot przez snap
snap:
name: certbot
classic: yes
- name: Utwórz symlink certbot
file:
src: /snap/bin/certbot
dest: /usr/bin/certbot
state: link
- name: Uzyskaj certyfikat SSL
command: >
certbot --nginx -d {{ domain }} -d www.{{ domain }}
--non-interactive --agree-tos -m {{ letsencrypt_email }}
args:
creates: /etc/letsencrypt/live/{{ domain }}/fullchain.pem # Uruchomienie playbooka ansible-playbook -i hosts.ini lemp-setup.yaml # Dry-run (sprawdź co by się zmieniło bez zmian) ansible-playbook -i hosts.ini lemp-setup.yaml --check # Verbose output ansible-playbook -i hosts.ini lemp-setup.yaml -v # Tylko jeden tag ansible-playbook -i hosts.ini lemp-setup.yaml --tags "nginx,php"
Variables i Jinja2 templates
# templates/nginx.conf.j2 — szablon Jinja2
server {
listen 80;
server_name {{ domain }} www.{{ domain }};
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name {{ domain }};
root /var/www/{{ domain }}/html;
ssl_certificate /etc/letsencrypt/live/{{ domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ domain }}/privkey.pem;
# PHP-FPM
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php{{ php_version }}-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
} # Task używający szablonu
- name: Kopiuj konfigurację Nginx
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/{{ domain }}
owner: root
group: root
mode: '0644'
notify: reload nginx Roles — organizacja złożonych playbooków
# Struktura katalogów dla roles
roles/
nginx/
tasks/main.yml
handlers/main.yml
templates/nginx.conf.j2
defaults/main.yml # Domyślne wartości zmiennych
vars/main.yml # Przesłaniają defaults
php/
tasks/main.yml
handlers/main.yml
mysql/
tasks/main.yml
# Pobranie gotowej roli z Ansible Galaxy
ansible-galaxy install geerlingguy.nginx
ansible-galaxy install geerlingguy.mysql
# site.yaml używający roles
---
- name: Serwer web
hosts: webservers
become: yes
roles:
- nginx
- php
- role: mysql
vars:
mysql_root_password: "tajne_haslo" Ansible Vault — szyfrowanie sekretów
# Zaszyfruj plik z sekretami ansible-vault encrypt group_vars/all/vault.yml # Edytuj zaszyfrowany plik ansible-vault edit group_vars/all/vault.yml # Uruchom playbook z vault password ansible-playbook -i hosts.ini site.yaml --ask-vault-pass # Lub z plikiem hasła (w .gitignore!) ansible-playbook -i hosts.ini site.yaml --vault-password-file ~/.vault_pass
Tip: Nigdy nie commituj niezaszyfrowanych haseł do git. Używaj ansible-vault dla wszystkich sekretów i dodaj *.vault.yml do .gitignore jeśli nie korzystasz z szyfrowania.