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 file Module: 20 Practical Examples Cookbook (Create, Delete, Permissions)

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

20 practical Ansible file module examples. Create directories, delete files, set permissions, create symlinks, manage ownership.

The file module manages files, directories, and symlinks on remote hosts — permissions, ownership, creation, and deletion. Here are 20 production-ready examples.

1. Create a Directory

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

See also: ansible.builtin.file Module: Manage Files, Directories & Symlinks (Complete Guide)

2. Create Nested Directories

- name: Create full directory tree
  ansible.builtin.file:
    path: /opt/myapp/releases/current/logs
    state: directory
    mode: '0755'
    owner: deploy
    group: deploy
  # Creates ALL parent directories automatically

3. Create Multiple Directories

- name: Create application directory structure
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    mode: '0755'
    owner: deploy
    group: deploy
  loop:
    - /opt/myapp/config
    - /opt/myapp/logs
    - /opt/myapp/data
    - /opt/myapp/backups
    - /opt/myapp/tmp

See also: Ansible Development: Write Custom Modules, Plugins & Collections

- name: Link current release
  ansible.builtin.file:
    src: /opt/myapp/releases/v2.5.0
    dest: /opt/myapp/current
    state: link
    owner: deploy
    group: deploy
- name: Relative symlink for log rotation
  ansible.builtin.file:
    src: ../shared/logs
    dest: /opt/myapp/current/logs
    state: link

See also: Ansible for Windows: Complete Guide to Windows Automation (2026)

6. Set File Permissions

- name: Secure private key
  ansible.builtin.file:
    path: /home/deploy/.ssh/id_rsa
    mode: '0600'
    owner: deploy
    group: deploy

- name: Make script executable ansible.builtin.file: path: /opt/myapp/bin/start.sh mode: '0755'

7. Set Permissions Recursively

- name: Fix ownership on entire app directory
  ansible.builtin.file:
    path: /opt/myapp
    state: directory
    owner: deploy
    group: deploy
    recurse: true

8. Set Directory with Sticky Bit

- name: Create shared directory with sticky bit
  ansible.builtin.file:
    path: /opt/shared
    state: directory
    mode: '1777'    # Like /tmp — everyone can write, only owner can delete

9. Set SGID on Directory

- name: Shared group directory (new files inherit group)
  ansible.builtin.file:
    path: /opt/teamdata
    state: directory
    mode: '2775'
    group: developers

10. Delete a File

- name: Remove old config
  ansible.builtin.file:
    path: /etc/myapp/old-config.conf
    state: absent

11. Delete a Directory Recursively

- name: Remove old release
  ansible.builtin.file:
    path: /opt/myapp/releases/v1.0.0
    state: absent
  # Removes directory and ALL contents

12. Touch a File (Create Empty or Update Timestamp)

- name: Create marker file
  ansible.builtin.file:
    path: /opt/myapp/.deployed
    state: touch
    mode: '0644'
    owner: deploy
    group: deploy

- name: Update modification time ansible.builtin.file: path: /opt/myapp/logs/access.log state: touch modification_time: preserve # Don't change mtime access_time: "202604130000.00"

- name: Create hard link for shared config
  ansible.builtin.file:
    src: /etc/myapp/shared.conf
    dest: /etc/myapp/service-a.conf
    state: hard

14. Ensure File Exists (Without Overwriting)

- name: Ensure log file exists
  ansible.builtin.file:
    path: /var/log/myapp/app.log
    state: touch
    mode: '0644'
    owner: myapp
    group: myapp
    modification_time: preserve
    access_time: preserve

15. Application Deployment Directory Structure

- name: Build full deployment tree
  ansible.builtin.file:
    path: "{{ item.path }}"
    state: directory
    mode: "{{ item.mode | default('0755') }}"
    owner: "{{ app_user }}"
    group: "{{ app_group }}"
  loop:
    - { path: "{{ deploy_to }}/releases" }
    - { path: "{{ deploy_to }}/shared/config" }
    - { path: "{{ deploy_to }}/shared/logs", mode: '0775' }
    - { path: "{{ deploy_to }}/shared/pids" }
    - { path: "{{ deploy_to }}/shared/tmp" }
    - { path: "{{ deploy_to }}/shared/sockets", mode: '0770' }
  vars:
    deploy_to: /opt/myapp
    app_user: deploy
    app_group: deploy
- name: Link shared resources
  ansible.builtin.file:
    src: "{{ deploy_to }}/shared/{{ item }}"
    dest: "{{ deploy_to }}/current/{{ item }}"
    state: link
    force: true
  loop:
    - config/database.yml
    - config/secrets.yml
    - logs
    - tmp
    - pids

17. Clean Old Releases (Keep Last 5)

- name: List releases
  ansible.builtin.find:
    paths: /opt/myapp/releases
    file_type: directory
  register: releases

- name: Remove old releases (keep 5) ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ (releases.files | sort(attribute='mtime') | list)[:-5] }}" when: releases.files | length > 5

18. Set SELinux Context

- name: Set SELinux context for web content
  ansible.builtin.file:
    path: /var/www/html
    state: directory
    setype: httpd_sys_content_t
    recurse: true
  when: ansible_selinux.status == "enabled"

19. Conditional Directory Creation

- name: Create environment-specific dirs
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    mode: '0755'
  loop:
    - /opt/myapp/config
    - "{{ '/opt/myapp/debug' if environment == 'staging' else '/opt/myapp/cache' }}"
    - "{{ '/opt/myapp/ssl' if ssl_enabled else omit }}"
  when: item is not none

20. Verify Permissions (Audit Mode)

- name: Check file permissions
  ansible.builtin.file:
    path: "{{ item.path }}"
    mode: "{{ item.mode }}"
    owner: "{{ item.owner }}"
  check_mode: true
  register: perm_check
  loop:
    - { path: /etc/ssh/sshd_config, mode: '0644', owner: root }
    - { path: /etc/shadow, mode: '0640', owner: root }
    - { path: /etc/crontab, mode: '0644', owner: root }

- name: Report permission drift ansible.builtin.debug: msg: "⚠️ {{ item.item.path }} permissions have drifted" loop: "{{ perm_check.results }}" when: item.changed

FAQ

What's the difference between file, copy, and template modules?

file manages metadata — permissions, ownership, existence, symlinks. It doesn't write content. Use copy for static files, template for Jinja2 templates, and file for everything else (directories, symlinks, permissions).

Does recurse: true work with mode?

recurse: true applies owner and group recursively but does NOT apply mode recursively (by design — you usually want different modes for files vs directories). Use find + file for recursive permission changes with different file/directory modes.

How do I create a directory only if it doesn't exist?

state: directory is already idempotent — it creates the directory if missing and does nothing if it exists. You don't need a separate check.

Can I manage Windows files with the file module?

Use ansible.windows.win_file for Windows targets. The ansible.builtin.file module is for Unix/Linux only.

Conclusion

The file module handles everything about files except their content — directories, symlinks, permissions, ownership, SELinux contexts, and cleanup. Combine it with copy, template, and find for complete file management. Every example above is idempotent and production-ready.

Related Articles

Ansible copy vs template vs lineinfileAnsible Create Directory GuideAnsible Delete File GuideHow to Make Playbooks Idempotent

Category: troubleshooting

Browse all Ansible tutorials · AnsiblePilot Home