Automation

Install and Use Ansible on Debian 13

Ansible is an open-source automation tool written in Python that handles configuration management, application deployment, and task orchestration over SSH – no agents needed on managed nodes. It uses simple YAML playbooks to define desired state, making it the go-to choice for Linux system administrators managing fleets of servers.

This guide covers installing Ansible on Debian 13 (Trixie) using two methods – pip in a virtual environment (recommended) and the default APT repository. We also walk through inventory configuration, ad-hoc commands, writing a basic playbook, and ansible-vault for secrets management.

Prerequisites

  • A Debian 13 server as the control node (where Ansible runs)
  • One or more managed nodes (any Linux distribution) reachable over SSH
  • A user with sudo privileges on all servers
  • SSH key-based authentication configured between the control node and managed nodes

Our lab setup for this guide:

RoleOSIP Address
Control NodeDebian 13192.168.1.10
Managed Node 1Debian 13192.168.1.11
Managed Node 2Rocky Linux 10192.168.1.12

Installing Ansible through pip gives you the latest version and keeps it isolated from system packages. Debian 13 ships with Python 3.13, which works well with the current Ansible release.

Install the required packages first:

sudo apt update
sudo apt install python3 python3-pip python3-venv sshpass -y

Create a Python virtual environment

Always install Ansible inside a virtual environment to avoid conflicts with system Python packages. Running pip install globally is deprecated on Debian 13 and will fail without --break-system-packages.

python3 -m venv ~/ansible-venv

Activate the virtual environment:

source ~/ansible-venv/bin/activate

Install Ansible with pip

With the venv active, install Ansible:

pip install ansible

This installs the full Ansible package (currently version 13.4.0) which includes ansible-core 2.20 and all standard collections.

Verify the installation:

$ ansible --version
ansible [core 2.20.0]
  config file = None
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user/ansible-venv/lib/python3.13/site-packages/ansible
  ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/user/ansible-venv/bin/ansible
  python version = 3.13.5 (main, ...) [GCC 14.2.0]
  jinja version = 3.1.6
  libyaml = True

To make the venv available every time you log in, add the activation line to your shell profile:

echo 'source ~/ansible-venv/bin/activate' >> ~/.bashrc

Step 2: Install Ansible on Debian 13 from APT Repository

If you prefer the system package manager, Ansible is available directly from the Debian 13 repository. The repo version (12.0.0 at the time of writing) may be slightly behind the latest pip release, but it is well-tested and integrates with system updates.

sudo apt update
sudo apt install ansible -y

Verify the installation:

$ ansible --version
ansible [core 2.17.7]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.13.5 (main, ...) [GCC 14.2.0]
  jinja version = 3.1.4
  libyaml = True

The APT method also installs /etc/ansible/ansible.cfg and /etc/ansible/hosts as default configuration and inventory files.

Step 3: Set Up SSH Key Authentication

Ansible connects to managed nodes over SSH. Key-based authentication removes the need to type passwords on every run. If you already have SSH keys configured, skip to Step 4.

Generate an SSH key pair on the control node:

ssh-keygen -t ed25519 -C "ansible-control"

Press Enter to accept the defaults. Then copy the public key to each managed node:

ssh-copy-id [email protected]
ssh-copy-id [email protected]

Verify passwordless login works:

ssh [email protected] "hostname"
ssh [email protected] "hostname"

Both commands should return the hostname of the remote server without prompting for a password.

Step 4: Configure Ansible Inventory

The inventory file defines which hosts Ansible manages and how they are grouped. Create a project directory and an inventory file:

mkdir -p ~/ansible-project
vi ~/ansible-project/inventory.ini

Add your managed nodes with their connection details:

[webservers]
192.168.1.11 ansible_user=user

[dbservers]
192.168.1.12 ansible_user=user

[all:vars]
ansible_python_interpreter=/usr/bin/python3

The [all:vars] section sets the Python interpreter path for all hosts. This avoids discovery warnings on managed nodes.

You can also create an ansible.cfg file in the project directory to set defaults. This is useful for managing tasks from a web-based interface like Semaphore or from the command line.

vi ~/ansible-project/ansible.cfg

Add the following configuration:

[defaults]
inventory = inventory.ini
remote_user = user
host_key_checking = False
retry_files_enabled = False

Verify your inventory is parsed correctly:

cd ~/ansible-project
ansible-inventory --list

Step 5: Run Ansible Ad-Hoc Commands

Ad-hoc commands let you run quick one-off tasks without writing a playbook. They are useful for checking system state, restarting services, or pushing small changes across multiple servers.

Test connectivity to all managed nodes:

$ ansible all -m ping
192.168.1.11 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.1.12 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

The ping module does not send ICMP packets – it verifies that Ansible can connect via SSH and execute Python on the remote host.

Check disk usage on the webservers group:

ansible webservers -m shell -a "df -h /"

Check memory on all hosts:

ansible all -m shell -a "free -m"

Check uptime across all nodes:

ansible all -m shell -a "uptime"

Install a package on Debian-based managed nodes using the apt module:

ansible webservers -m apt -a "name=curl state=present" --become

The --become flag runs the command with sudo on the remote host. You can automate many repetitive tasks this way without writing full playbooks.

Here is a quick reference of common ad-hoc patterns:

TaskCommand
Ping all hostsansible all -m ping
Check uptimeansible all -m shell -a "uptime"
Restart a serviceansible all -m service -a "name=nginx state=restarted" --become
Copy a fileansible all -m copy -a "src=./file.txt dest=/tmp/file.txt"
Gather factsansible all -m setup

Step 6: Write and Run an Ansible Playbook

Playbooks define a series of tasks in YAML format. They are reusable, version-controllable, and the primary way to use Ansible in production.

Create a playbook that installs Nginx on the webservers group, enables the service, and verifies it is running:

vi ~/ansible-project/setup-nginx.yml

Add the following content:

---
- name: Install and configure Nginx
  hosts: webservers
  become: yes
  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: Install Nginx
      apt:
        name: nginx
        state: present

    - name: Start and enable Nginx
      systemd:
        name: nginx
        state: started
        enabled: yes

    - name: Verify Nginx is running
      shell: systemctl is-active nginx
      register: nginx_status

    - name: Show Nginx status
      debug:
        var: nginx_status.stdout

Run the playbook:

cd ~/ansible-project
ansible-playbook setup-nginx.yml

Expected output:

PLAY [Install and configure Nginx] ********************************************

TASK [Gathering Facts] ********************************************************
ok: [192.168.1.11]

TASK [Update apt cache] *******************************************************
changed: [192.168.1.11]

TASK [Install Nginx] **********************************************************
changed: [192.168.1.11]

TASK [Start and enable Nginx] *************************************************
ok: [192.168.1.11]

TASK [Verify Nginx is running] ************************************************
changed: [192.168.1.11]

TASK [Show Nginx status] ******************************************************
ok: [192.168.1.11] => {
    "nginx_status.stdout": "active"
}

PLAY RECAP ********************************************************************
192.168.1.11               : ok=6    changed=3    unreachable=0    failed=0    skipped=0

Every task reports whether it changed something or was already in the desired state. This idempotency is what makes Ansible safe to run repeatedly.

Use variables and handlers

A more realistic playbook uses variables for flexibility and handlers to restart services only when configuration changes:

vi ~/ansible-project/deploy-app.yml

Add the following content:

---
- name: Deploy web application
  hosts: webservers
  become: yes
  vars:
    http_port: 8080
    app_root: /var/www/myapp

  tasks:
    - name: Install required packages
      apt:
        name:
          - nginx
          - curl
        state: present
        update_cache: yes

    - name: Create application directory
      file:
        path: "{{ app_root }}"
        state: directory
        owner: www-data
        group: www-data
        mode: '0755'

    - name: Deploy Nginx vhost config
      template:
        src: templates/vhost.conf.j2
        dest: /etc/nginx/sites-available/myapp.conf
      notify: Reload Nginx

    - name: Enable site
      file:
        src: /etc/nginx/sites-available/myapp.conf
        dest: /etc/nginx/sites-enabled/myapp.conf
        state: link
      notify: Reload Nginx

  handlers:
    - name: Reload Nginx
      systemd:
        name: nginx
        state: reloaded

Handlers run only when notified by a task that reports “changed” – Nginx reloads only when the config file actually changes.

Step 7: Manage Secrets with Ansible Vault

Ansible Vault encrypts sensitive data – passwords, API keys, certificates – so you can store them safely in version control alongside your playbooks. For a complete reference, see our Ansible Vault cheat sheet.

Create an encrypted file

ansible-vault create ~/ansible-project/secrets.yml

You will be prompted to set a vault password. The file opens in your editor. Add your sensitive variables:

db_password: S3cur3P@ssw0rd
api_key: abc123def456

Save and close. The file is now AES-256 encrypted on disk.

View and edit encrypted files

View the contents without editing:

ansible-vault view ~/ansible-project/secrets.yml

Edit the encrypted file:

ansible-vault edit ~/ansible-project/secrets.yml

Use vault secrets in playbooks

Reference vault-encrypted files with vars_files in your playbook:

vi ~/ansible-project/db-setup.yml

Add the following content:

---
- name: Configure database
  hosts: dbservers
  become: yes
  vars_files:
    - secrets.yml
  tasks:
    - name: Set database password
      shell: "echo 'Password configured: {{ db_password }}'"
      no_log: true

Run the playbook with the vault password:

ansible-playbook db-setup.yml --ask-vault-pass

For automation (CI/CD pipelines), store the vault password in a file and reference it:

echo 'your-vault-password' > ~/.vault_pass
chmod 600 ~/.vault_pass
ansible-playbook db-setup.yml --vault-password-file ~/.vault_pass

Encrypt an existing file

If you have a plain-text file with secrets that needs encryption:

ansible-vault encrypt ~/ansible-project/vars/credentials.yml

To decrypt it back to plain text:

ansible-vault decrypt ~/ansible-project/vars/credentials.yml

To change the vault password on an encrypted file:

ansible-vault rekey ~/ansible-project/secrets.yml

Conclusion

Ansible is installed on Debian 13 and ready to manage your infrastructure. We covered pip-based installation in a virtual environment, APT installation, inventory setup, ad-hoc commands, playbook creation, and vault-based secrets management.

For production use, set up a dedicated Ansible AWX instance for centralized job scheduling and RBAC, keep your playbooks in Git, and use ansible-vault for all credentials. Structure larger projects with roles to keep tasks modular and reusable across environments.

Related Articles

Ansible How To Setup LEMP stack for WordPress using Ansible Automation Install Chef Server & Workstation on Ubuntu 20.04 Cheat Sheets netstat vs ss usage guide on Linux Chat Install Mattermost Server on Ubuntu 22.04|20.04|18.04

Press ESC to close