AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible inventory_hostname vs ansible_hostname vs ansible_fqdn (Explained)

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

Difference between Ansible inventory_hostname, ansible_hostname, ansible_host, and ansible_fqdn variables.

Ansible inventory_hostname vs ansible_hostname vs ansible_fqdn (Explained)

What is the difference between ansible_hostname vs inventory_hostname?

These two ansible internal variables sometimes confuse one for another but they're fundamentally different. I'm Luca Berton and welcome to today's episode of Ansible Pilot.

ansible_hostname and ansible_fqdn

Read from the target machine hostname from the facts: • ansible_hostname read the hostname from the facts collected during the gather_facts • Same as the uname -n or hostname command-line • Need gather_facts enabled, otherwise the ansible_facts variable would be unavailable to use in your playbook • Same as hostname of the target host • As this is based on the gather_facts step. ansible_hostname not available in ad-hoc command

inventory_hostname

Read from Ansible inventory or hosts files: • inventory_hostname read the hostname from the inventory configuration or the hosts file. Could be different from the hostname configuration of the remote system. It could be only a name on the controller machine • inventory_hostname is always available to use in your playbook. • Could be different from the hostname of the target host • Available for both playbook and ad-hoc command

See also: 10 Proven Methods to Optimize Ansible Playbook Performance

Playbook

Let me show you the difference between ansible_hostname vs inventory_hostname vs ansible_fqdn internal variables in a simple Ansible Playbook.

code

• hostnames.yml
---
- name: hostnames Playbook
  hosts: all
  gather_facts: true
  tasks:
    - name: print inventory_hostname
      ansible.builtin.debug:
        var: inventory_hostname
    - name: print ansible_hostname
      ansible.builtin.debug:
        var: ansible_hostname
    - name: print ansible_fqdn
      ansible.builtin.debug:
        var: ansible_fqdn
• inventory
foo.example.com ansible_host=192.168.0.190
[all:vars]
ansible_connection=ssh
ansible_user=devops
ansible_ssh_private_key_file=~/.ssh/id_rsa

execution

ansible-pilot $ ansible-playbook -i ansible\ statements/inventory ansible\ statements/hostnames.yml
PLAY [hostnames Playbook] *****************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [foo.example.com]
TASK [print inventory_hostname] *******************************************************************
ok: [foo.example.com] => {
    "inventory_hostname": "foo.example.com"
}
TASK [print ansible_hostname] *********************************************************************
ok: [foo.example.com] => {
    "ansible_hostname": "Playbook"
}
TASK [print ansible_fqdn] *************************************************************************
ok: [foo.example.com] => {
    "ansible_fqdn": "demo.example.com"
}
PLAY RECAP ****************************************************************************************
foo.example.com            : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
ansible-pilot $

idempotency

ansible-pilot $ ansible-playbook -i ansible\ statements/inventory ansible\ statements/hostnames.yml
PLAY [hostnames Playbook] *****************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [foo.example.com]
TASK [print inventory_hostname] *******************************************************************
ok: [foo.example.com] => {
    "inventory_hostname": "foo.example.com"
}
TASK [print ansible_hostname] *********************************************************************
ok: [foo.example.com] => {
    "ansible_hostname": "Playbook"
}
TASK [print ansible_fqdn] *************************************************************************
ok: [foo.example.com] => {
    "ansible_fqdn": "demo.example.com"
}
PLAY RECAP ****************************************************************************************
foo.example.com            : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
ansible-pilot $

before execution

ansible-pilot $ ssh devops@192.168.0.190
[devops@demo ~]$ uname -a
Linux demo.example.com 4.18.0-348.el8.x86_64 #1 SMP Mon Oct 4 12:17:22 EDT 2021 x86_64 x86_64 x86_64 GNU/Linux
[devops@demo ~]$ uname -n
demo.example.com
[devops@demo ~]$ hostname
demo.example.com
[devops@demo ~]$

Conclusion

Now you know more about the Ansible internal variables ansible_hostname, inventory_hostname and ansible_fqdn. You know how to use it based on your use case.

See also: ansible.cfg Configuration File: Complete Settings Guide (2026)

Quick Comparison

| Variable | Source | Example | Needs gather_facts | |----------|--------|---------|-------------------| | inventory_hostname | Inventory file | web1 | No | | inventory_hostname_short | Inventory file (short) | web1 | No | | ansible_hostname | Remote host (hostname) | ip-10-0-1-42 | Yes | | ansible_fqdn | Remote DNS | ip-10-0-1-42.ec2.internal | Yes | | ansible_host | Inventory ansible_host | 10.0.1.42 | No | | ansible_nodename | Remote uname -n | ip-10-0-1-42 | Yes |

Example

# inventory.yml
webservers:
  hosts:
    web1:
      ansible_host: 10.0.1.42
- debug:
    msg:
      - "inventory_hostname: {{ inventory_hostname }}"           # web1
      - "inventory_hostname_short: {{ inventory_hostname_short }}" # web1
      - "ansible_host: {{ ansible_host }}"                       # 10.0.1.42
      - "ansible_hostname: {{ ansible_hostname }}"               # ip-10-0-1-42
      - "ansible_fqdn: {{ ansible_fqdn }}"                      # ip-10-0-1-42.ec2.internal

See also: Ansible Magic Variables: Complete Reference with Examples

When to Use Each

inventory_hostname — Most common

# Referencing hosts in plays, templates, conditions
- name: Configure based on inventory name
  template:
    src: vhost.conf.j2
    dest: "/etc/nginx/sites-enabled/{{ inventory_hostname }}.conf"

# Accessing other hosts' variables - debug: msg: "{{ hostvars[groups['dbservers'][0]].ansible_host }}"

ansible_hostname — Actual hostname

# When you need the real system hostname
- name: Verify hostname matches expected
  assert:
    that: ansible_hostname == expected_hostname
    fail_msg: "Hostname mismatch!"

ansible_fqdn — DNS/certificates

# SSL certificates need FQDN
- name: Generate CSR with correct FQDN
  community.crypto.openssl_csr:
    path: /etc/ssl/certs/{{ ansible_fqdn }}.csr
    common_name: "{{ ansible_fqdn }}"

ansible_host — Connection address

# When you need the IP/address for configs
- name: Configure app to listen on correct IP
  lineinfile:
    path: /etc/myapp/config.yml
    regexp: '^bind_address:'
    line: "bind_address: {{ ansible_host }}"

In Templates

# nginx.conf.j2
server {
    server_name {{ ansible_fqdn }} {{ inventory_hostname }};
    listen {{ ansible_host }}:80;
}

Common Pitfall

# inventory_hostname works WITHOUT gather_facts
- hosts: all
  gather_facts: false
  tasks:
    - debug: msg="{{ inventory_hostname }}"      # Works
    - debug: msg="{{ ansible_hostname }}"        # FAILS - needs facts

# Enable facts for ansible_hostname/fqdn - hosts: all gather_facts: true tasks: - debug: msg="{{ ansible_fqdn }}" # Works

FAQ

Why is ansible_hostname different from inventory_hostname?

inventory_hostname is what YOU named the host in inventory. ansible_hostname is what the HOST calls itself (output of hostname). They can differ significantly, especially in cloud environments.

Which should I use in templates?

For file paths and Ansible references: inventory_hostnameFor DNS/SSL/network configs: ansible_fqdnFor IP-based configs: ansible_host or ansible_default_ipv4.address

How do I set the hostname to match inventory?

- ansible.builtin.hostname:
    name: "{{ inventory_hostname }}"
  become: true

Related Articles

managing inventory in Ansiblerole directory layout in Ansible

Category: troubleshooting

Watch the video: Ansible inventory_hostname vs ansible_hostname vs ansible_fqdn (Explained) — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home