MODUL ANSIBLE
Di setiap host
root@tusirah:~# vim.tiny /etc/ssh/sshd_config
PermitRootLogin yes
reboot os debian
control node
sudo su -
ssh-keygen
ssh-copy-id root@192.168.8.134
ssh-copy-id root@192.168.8.135
test koneksi server debian
masih sebagai root control node
ssh root@192.168.8.134
ssh root@192.168.8.135
harus bisa login root tanpa password
Node Control
mkdir /etc/ansible
vim.tiny /etc/ansible/hosts
[servers]
server1 ansible_host=192.168.8.134
server2 ansible_host=192.168.8.135
[all:vars]
ansible_python_interpreter=/usr/bin/python3
ansible-inventory --list -y
all:
children:
servers:
hosts:
server1:
ansible_host: 192.168.8.134
ansible_python_interpreter: /usr/bin/python3
server2:
ansible_host: 192.168.8.135
ansible_python_interpreter: /usr/bin/python3
ansible all -m ping -u root
server1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
server2 | SUCCESS => {
"changed": false,
"ping": "pong"
root@tusirah:~# ansible all -m command -a "uname -a" -u root
server1 | CHANGED | rc=0 >>
Linux debianfw 6.1.0-32-amd64 #1 SMP PREEMPT_DYNAMIC Debian
6.1.129-1 (2025-03-06) x86_64 GNU/Linux
server2 | CHANGED | rc=0 >>
Linux server2 6.1.0-32-amd64 #1 SMP PREEMPT_DYNAMIC Debian
6.1.129-1 (2025-03-06) x86_64 GNU/Linux
root@tusirah:~# ansible all -m command -a "whoami" -u root
server2 | CHANGED | rc=0 >>
root
server1 | CHANGED | rc=0 >>
root
cat /etc/ansible/hosts > inventory.ini
vim.tiny inventory.ini
[servers]
server1 ansible_host=192.168.8.134 ansible_user=root
server2 ansible_host=192.168.8.135 ansible_user=root
[all:vars]
ansible_python_interpreter=/usr/bin/python3
vim.tiny playbook.yaml
- name: My first play
hosts: server1
tasks:
- name: Ping my hosts
ansible.builtin.ping:
- name: Print message
ansible.builtin.debug:
msg: Hello world
- name: Server dua
hosts: server2
tasks:
- name: Ping my hosts
ansible.builtin.ping:
- name: Print message
ansible.builtin.debug:
msg: Hello world
atau group juga bisa
vim.tiny playbook2.yaml
- name: My first play
hosts: servers
tasks:
- name: Ping my hosts
ansible.builtin.ping:
- name: Print message
ansible.builtin.debug:
msg: Hello world
command playbook
ansible-playbook -i inventory.ini playbook2.yaml
PLAY [My first play]
******************************************************************
***********************
TASK [Gathering Facts]
******************************************************************
*********************
ok: [server1]
TASK [Ping my hosts]
******************************************************************
***********************
ok: [server1]
TASK [Print message]
******************************************************************
***********************
ok: [server1] => {
"msg": "Hello world"
}
PLAY [Server dua]
******************************************************************
**************************
TASK [Gathering Facts]
******************************************************************
*********************
ok: [server2]
TASK [Ping my hosts]
******************************************************************
***********************
ok: [server2]
TASK [Print message]
******************************************************************
***********************
ok: [server2] => {
"msg": "Hello world"
}
PLAY RECAP
******************************************************************
*********************************
server1 : ok=3 changed=0 unreachable=0
failed=0 skipped=0 rescued=0 ignor
ed=0
server2 : ok=3 changed=0 unreachable=0
failed=0 skipped=0 rescued=0 ignor
ed=0
root@tusirah:~# ansible-playbook -i inventory.ini playbook2.yaml
PLAY [My first play]
******************************************************************
***********************
TASK [Gathering Facts]
******************************************************************
*********************
ok: [server2]
ok: [server1]
TASK [Ping my hosts]
******************************************************************
***********************
ok: [server1]
ok: [server2]
TASK [Print message]
******************************************************************
***********************
ok: [server1] => {
"msg": "Hello world"
}
ok: [server2] => {
"msg": "Hello world"
}
PLAY RECAP
******************************************************************
*********************************
server1 : ok=3 changed=0 unreachable=0
failed=0 skipped=0 rescued=0 ignor
ed=0
server2 : ok=3 changed=0 unreachable=0
failed=0 skipped=0 rescued=0 ignor
ed=0
adduser debian host
vim.tiny adduser.yaml
- name: Create a user
hosts: server1
become: yes
tasks:
- name: Add user odik
user:
name: odik
shell: /bin/bash
home: /home/odik
root@tusirah:~# ansible-playbook -i inventory.ini adduser.yaml
PLAY [Create a user]
******************************************************************
***********************
TASK [Gathering Facts]
******************************************************************
*********************
ok: [server1]
TASK [Add user odik]
******************************************************************
***********************
changed: [server1]
PLAY RECAP
******************************************************************
*********************************
server1 : ok=2 changed=1 unreachable=0
failed=0 skipped=0 rescued=0 ignor
ed=0
vim.tiny ping.yaml
- name: Test Ping and Uname
hosts: all
gather_facts: no
tasks:
- name: Ping target hosts
ansible.builtin.ping:
- name: Get system information
ansible.builtin.command: uname -a
register: uname_output
- name: Show system information
ansible.builtin.debug:
msg: "{{ uname_output.stdout }}"
root@tusirah:~# ansible-playbook -i inventory.ini ping.yaml
PLAY [Test Ping and Uname]
******************************************************************
*****************
TASK [Ping target hosts]
******************************************************************
*******************
ok: [server1]
ok: [server2]
TASK [Get system information]
******************************************************************
**************
changed: [server2]
changed: [server1]
TASK [Show system information]
******************************************************************
*************
ok: [server1] => {
"msg": "Linux debianfw 6.1.0-32-amd64 #1 SMP PREEMPT_DYNAMIC
Debian 6.1.129-1 (2025-03-06) x86_64 GNU/Linu
x"
}
ok: [server2] => {
"msg": "Linux server2 6.1.0-32-amd64 #1 SMP PREEMPT_DYNAMIC
Debian 6.1.129-1 (2025-03-06) x86_64 GNU/Linux
"
}
PLAY RECAP
******************************************************************
*********************************
server1 : ok=3 changed=1 unreachable=0
failed=0 skipped=0 rescued=0 ignor
ed=0
server2 : ok=3 changed=1 unreachable=0
failed=0 skipped=0 rescued=0 ignor
ed=0
Rubah Hostname
cat inventory.ini
[servers]
server1 ansible_host=192.168.8.134 ansible_user=root
server2 ansible_host=192.168.8.135 ansible_user=root
server3 ansible_host=192.168.8.136 ansible_user=root
[all:vars]
ansible_python_interpreter=/usr/bin/python3
vim.tiny hostname.yaml
- name: Configure Hostname on Multiple Servers
hosts: all
become: yes
vars:
server_hostnames:
- { name: "server1", ip: "192.168.8.134" }
- { name: "server2", ip: "192.168.8.135" }
- { name: "server3", ip: "192.168.8.136" }
tasks:
- name: Set hostname
hostname:
name: "{{ item.name }}"
loop: "{{ server_hostnames }}"
when: ansible_default_ipv4.address == item.ip
- name: Update /etc/hosts file
lineinfile:
path: /etc/hosts
regexp: '^127.0.1.1'
line: "127.0.1.1 {{ item.name }}"
loop: "{{ server_hostnames }}"
when: ansible_default_ipv4.address == item.ip
- name: Restart hostname service (if required)
command: hostnamectl set-hostname {{ item.name }}
loop: "{{ server_hostnames }}"
when: ansible_default_ipv4.address == item.ip and
ansible_distribution in ["Ubuntu", "Debian"]
ansible-playbook -i inventory.ini hostname.yaml
PLAY [Configure Hostname on Multiple Servers]
****************************************************************
TASK [Gathering Facts]
******************************************************************
*********************
ok: [server1]
ok: [server3]
ok: [server2]
TASK [Set hostname]
******************************************************************
************************
skipping: [server2] => (item={'name': 'server1', 'ip':
'192.168.8.134'})
skipping: [server3] => (item={'name': 'server1', 'ip':
'192.168.8.134'})
skipping: [server3] => (item={'name': 'server2', 'ip':
'192.168.8.135'})
ok: [server2] => (item={'name': 'server2', 'ip': '192.168.8.135'})
skipping: [server2] => (item={'name': 'server3', 'ip':
'192.168.8.136'})
changed: [server3] => (item={'name': 'server3', 'ip':
'192.168.8.136'})
changed: [server1] => (item={'name': 'server1', 'ip':
'192.168.8.134'})
skipping: [server1] => (item={'name': 'server2', 'ip':
'192.168.8.135'})
skipping: [server1] => (item={'name': 'server3', 'ip':
'192.168.8.136'})
TASK [Update /etc/hosts file]
******************************************************************
**************
skipping: [server2] => (item={'name': 'server1', 'ip':
'192.168.8.134'})
skipping: [server3] => (item={'name': 'server1', 'ip':
'192.168.8.134'})
skipping: [server3] => (item={'name': 'server2', 'ip':
'192.168.8.135'})
changed: [server2] => (item={'name': 'server2', 'ip':
'192.168.8.135'})
skipping: [server2] => (item={'name': 'server3', 'ip':
'192.168.8.136'})
changed: [server3] => (item={'name': 'server3', 'ip':
'192.168.8.136'})
changed: [server1] => (item={'name': 'server1', 'ip':
'192.168.8.134'})
skipping: [server1] => (item={'name': 'server2', 'ip':
'192.168.8.135'})
skipping: [server1] => (item={'name': 'server3', 'ip':
'192.168.8.136'})
TASK [Restart hostname service (if required)]
****************************************************************
skipping: [server2] => (item={'name': 'server1', 'ip':
'192.168.8.134'})
skipping: [server3] => (item={'name': 'server1', 'ip':
'192.168.8.134'})
skipping: [server3] => (item={'name': 'server2', 'ip':
'192.168.8.135'})
changed: [server3] => (item={'name': 'server3', 'ip':
'192.168.8.136'})
changed: [server1] => (item={'name': 'server1', 'ip':
'192.168.8.134'})
skipping: [server1] => (item={'name': 'server2', 'ip':
'192.168.8.135'})
skipping: [server1] => (item={'name': 'server3', 'ip':
'192.168.8.136'})
changed: [server2] => (item={'name': 'server2', 'ip':
'192.168.8.135'})
skipping: [server2] => (item={'name': 'server3', 'ip':
'192.168.8.136'})
PLAY RECAP
******************************************************************
*********************************
server1 : ok=4 changed=3 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0
server2 : ok=4 changed=2 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0
server3 : ok=4 changed=3 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0
USER Import dan CSV
cat userlinux.csv
username,password,shell,groups
utik,pass123,/bin/bash,sudo
doni,pass123,/bin/bash,developer
roni,pass123,/bin/bash,sales
rudi,pass123,/bin/bash,sales
vim.tiny import3.yml
---
- name: Import users from CSV and create accounts
hosts: all
become: yes
tasks:
- name: Copy CSV file to remote servers
ansible.builtin.copy:
src: "/home/budi/workflow/hosts/userlinux.csv"
dest: "/tmp/userlinux.csv"
mode: '0644'
- name: Read CSV file from remote server
community.general.read_csv:
path: "/tmp/userlinux.csv"
register: users_list
- name: Ensure required groups exist
ansible.builtin.group:
name: "{{ item }}"
state: present
loop:
- sudo
- sales
- developer
- name: Create users from CSV data
ansible.builtin.user:
name: "{{ item.username }}"
password: "{{ item.password | password_hash('sha512') }}"
shell: "{{ item.shell }}"
groups: "{{ item.groups }}"
append: yes
loop: "{{ users_list.list }}"
ansible-playbook -i inventory.ini import3.yml
PLAY [Import users from CSV and create accounts]
******************************************************************
******************************************************************
*******
TASK [Gathering Facts]
******************************************************************
******************************************************************
*********************************
ok: [server2]
ok: [server1]
ok: [server3]
TASK [Copy CSV file to remote servers]
******************************************************************
******************************************************************
*****************
ok: [server1]
ok: [server3]
ok: [server2]
TASK [Read CSV file from remote server]
******************************************************************
******************************************************************
****************
ok: [server3]
ok: [server1]
ok: [server2]
TASK [Ensure required groups exist]
******************************************************************
******************************************************************
********************
ok: [server3] => (item=sudo)
ok: [server2] => (item=sudo)
ok: [server1] => (item=sudo)
changed: [server3] => (item=sales)
changed: [server2] => (item=sales)
changed: [server1] => (item=sales)
changed: [server2] => (item=developer)
changed: [server3] => (item=developer)
changed: [server1] => (item=developer)
TASK [Create users from CSV data]
******************************************************************
******************************************************************
**********************
changed: [server1] => (item={'username': 'utik', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'sudo'})
changed: [server2] => (item={'username': 'utik', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'sudo'})
changed: [server3] => (item={'username': 'utik', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'sudo'})
changed: [server2] => (item={'username': 'doni', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'developer'})
changed: [server1] => (item={'username': 'doni', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'developer'})
changed: [server3] => (item={'username': 'doni', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'developer'})
changed: [server2] => (item={'username': 'roni', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'sales'})
changed: [server3] => (item={'username': 'roni', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'sales'})
changed: [server1] => (item={'username': 'roni', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'sales'})
changed: [server2] => (item={'username': 'rudi', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'sales'})
changed: [server3] => (item={'username': 'rudi', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'sales'})
changed: [server1] => (item={'username': 'rudi', 'password':
'pass123', 'shell': '/bin/bash', 'groups': 'sales'})
PLAY RECAP
******************************************************************
******************************************************************
*********************************************
server1 : ok=5 changed=2 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0
server2 : ok=5 changed=2 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0
server3 : ok=5 changed=2 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0
Untuk DNS Bind9
budi@tusirah:~/workflow/hosts$ tree ansible-bind9/
ansible-bind9/
├── inventory.ini
├── playbook.yml
└── roles
└── bind9
├── handlers
│ └── main.yml
├── tasks
│ └── main.yml
└── templates
├── db.linux.com.j2
└── named.conf.local.j2
cd ansible-bind9
vim inventory.ini
[bind9_servers]
dns_server1 ansible_host=192.168.8.135 ansible_user=root
dns_server2 ansible_host=192.168.8.136 ansible_user=root
vim playbook.yml
- name: Deploy BIND9 DNS Server
hosts: bind9_servers
become: yes
roles:
- bind9
vim roles/bind9/tasks/main.yml
- name: Install BIND9
apt:
name: bind9
state: present
update_cache: yes
- name: Copy named.conf.local
template:
src: named.conf.local.j2
dest: /etc/bind/named.conf.local
notify: Restart BIND9
- name: Copy zone file for linux.com
template:
src: db.linux.com.j2
dest: /etc/bind/db.linux.com
notify: Restart BIND9
- name: Ensure BIND9 is running and enabled
service:
name: bind9
state: started
enabled: yes
vim roles/bind9/templates/named.conf.local.j2
zone "linux.com" {
type master;
file "/etc/bind/db.linux.com";
};
vim roles/bind9/templates/db.linux.com.j2
$TTL 86400
@ IN SOA ns.linux.com. admin.linux.com. (
2024032001 ; Serial
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400 ) ; Minimum TTL
; Nameservers
@ IN NS ns.linux.com.
; A records
ns IN A 192.168.8.135
ns2 IN A 192.168.8.136
www IN A 192.168.8.134
www IN A 192.168.8.135
mail IN A 192.168.8.134
; MX records
@ IN MX 10 mail.linux.com.
vim roles/bind9/handlers/main.yml
- name: Restart BIND9
service:
name: bind9
state: restarted
pwd
/home/budi/workflow/hosts/ansible-bind9
ansible all -i inventory.ini -m ping
dns_server2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
dns_server1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
ansible-playbook -i inventory.ini playbook.yml
ansible all -i inventory.ini -m command -a "systemctl status bind
9.service"
Client DNS
budi@tusirah:~/workflow/hosts$ mkdir client-dns
budi@tusirah:~/workflow/hosts$ tree client-dns/
client-dns/
├── inventory.ini
├── playbook.yml
└── templates
└── resolv.conf.j2
cd client-dns
mkdir templates
vim inventory.ini
[servers]
server1 ansible_host=192.168.8.134 ansible_user=root
server2 ansible_host=192.168.8.135 ansible_user=root
server3 ansible_host=192.168.8.136 ansible_user=root
[all:vars]
ansible_python_interpreter=/usr/bin/python3
vim templates/resolv.conf.j2
# Managed by Ansible
nameserver 192.168.8.135
nameserver 192.168.8.136
vim playbook.yml
- name: Update resolv.conf using template
hosts: all
become: yes
tasks:
- name: Deploy resolv.conf template
template:
src: resolv.conf.j2
dest: /etc/resolv.conf
owner: root
group: root
mode: '0644'
budi@tusirah:~/workflow/hosts/client-dns$ ansible all -i
inventory.ini -m ping
server2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
server3 | SUCCESS => {
"changed": false,
"ping": "pong"
}
server1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible-playbook -i inventory.ini playbook.yml
ansible all -i inventory.ini -m command -a "nslookup
www.linux.com"
server1 | CHANGED | rc=0 >>
Server: 192.168.8.135
Address: 192.168.8.135#53
Name: www.linux.com
Address: 192.168.8.135
Name: www.linux.com
Address: 192.168.8.134
server2 | CHANGED | rc=0 >>
Server: 192.168.8.135
Address: 192.168.8.135#53
Name: www.linux.com
Address: 192.168.8.134
Name: www.linux.com
Address: 192.168.8.135
server3 | CHANGED | rc=0 >>
Server: 192.168.8.135
Address: 192.168.8.135#53
Name: www.linux.com
Address: 192.168.8.135
Name: www.linux.com
Address: 192.168.8.134
Ansible Deploy Nginx
mkdir ansible-nginx
cd ansible-nginx
vim inventory.ini
[webservers]
web1 ansible_host=192.168.8.134 ansible_user=root
web2 ansible_host=192.168.8.135 ansible_user=root
[all:vars]
ansible_python_interpreter=/usr/bin/python3
vim playbook.yml
- name: Deploy Nginx with Custom Config and Index Page
hosts: webservers
become: yes
tasks:
- name: Install Nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: yes
- name: Deploy Nginx Configuration
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/default
notify: Restart Nginx
- name: Ensure default site is enabled
ansible.builtin.file:
src: /etc/nginx/sites-available/default
dest: /etc/nginx/sites-enabled/default
state: link
notify: Restart Nginx
- name: Deploy Index Page
ansible.builtin.template:
src: index.html.j2
dest: /var/www/html/index.html
handlers:
- name: Restart Nginx
ansible.builtin.service:
name: nginx
state: restarted
mkdir templates
vim nginx.conf.j2
server {
listen 80;
server_name _;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
vim index.html.j2
<html>
<head><title>Hello</title></head>
<body>
<h1>Hello from {{ ansible_hostname }}!</h1>
</body>
</html>
cd /home/budi/workflow/hosts/ansible-nginx/
ansible all -i inventory.ini -m ping
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible-playbook -i inventory.ini playbook.yml