Ansible chmod: Change File Permissions with file Module (Guide)
By Luca Berton · Published 2024-01-01 · Category: windows-automation
How to change file permissions (chmod) in Ansible with the file module. Set mode, owner, group, recursive permissions on files and directories.

How to change file or directory permission with Ansible?
See also: Ansible Set File Permissions 755: chmod with file Module Guide
Ansible change file/directory permission
Today we're talking about the Ansible modulefile.
The full name is ansible.builtin.file, which means that is part of the collection of modules "builtin" with ansible and shipped with it.
It's a module pretty stable and out for years.
It works in a different variety of operating systems.
It manages files and file properties.
For Windows targets, use the ansible.windows.win_file module instead.
Main Parameters
- path _string_ (dest, name) - file path
- owner _string_ - user
- group _string_ - group
- mode _raw_ - Ex: '0644' or 'u=rw,g=r,o=r'
- state _string_ - file/absent/directory/hard/link/touch
- setype/seuser/selevel - SELinux
## Playbook Let's jump in a real-life playbook to change file permission with Ansible.
code
- file.yml
---
- name: file module demo
hosts: all
vars:
myfile: "/home/devops/test.txt"
become: false
tasks:
- name: check permission
ansible.builtin.file:
path: "{{ myfile }}"
owner: "devops"
group: "users"
mode: '0777'See also: Ansible Create User Account: user Module Complete Guide
Conclusion
Now you know how to change file or directory permission with Ansible.Permission Format Options
Ansible accepts permissions in two formats:
Octal notation (recommended)
- name: Set file to 644
ansible.builtin.file:
path: /etc/myapp/config.yml
mode: '0644' # Always quote and include leading 0
become: trueSymbolic notation
- name: Set file permissions symbolically
ansible.builtin.file:
path: /etc/myapp/config.yml
mode: 'u=rw,g=r,o=r' # Same as 0644
become: trueSee also: Ansible Remove User Account: Delete Users with user Module
Common Permission Patterns
| Octal | Symbolic | Meaning | Use Case |
|---|---|---|---|
0644 | u=rw,g=r,o=r | Owner read/write, others read | Config files |
0755 | u=rwx,g=rx,o=rx | Owner full, others read/execute | Scripts, directories |
0600 | u=rw,g=,o= | Owner only | Secrets, SSH keys |
0700 | u=rwx,g=,o= | Owner only (executable) | Private scripts |
0444 | u=r,g=r,o=r | Read-only for everyone | Reference files |
0775 | u=rwx,g=rwx,o=rx | Owner+group full | Shared directories |
Advanced Examples
Change ownership and permissions together
- name: Set ownership and permissions
ansible.builtin.file:
path: /var/www/html
owner: www-data
group: www-data
mode: '0755'
recurse: true # Apply to all files/dirs inside
become: trueSet different permissions for files vs directories
- name: Find all files
ansible.builtin.find:
paths: /var/www/html
file_type: file
recurse: true
register: website_files
- name: Set file permissions to 644
ansible.builtin.file:
path: "{{ item.path }}"
mode: '0644'
loop: "{{ website_files.files }}"
become: true
- name: Find all directories
ansible.builtin.find:
paths: /var/www/html
file_type: directory
recurse: true
register: website_dirs
- name: Set directory permissions to 755
ansible.builtin.file:
path: "{{ item.path }}"
mode: '0755'
loop: "{{ website_dirs.files }}"
become: trueMake a script executable
- name: Deploy and make executable
ansible.builtin.copy:
src: scripts/deploy.sh
dest: /usr/local/bin/deploy.sh
owner: root
group: root
mode: '0755' # rwxr-xr-x
become: trueSet SELinux context
- name: Set SELinux context for web content
ansible.builtin.file:
path: /var/www/custom
setype: httpd_sys_content_t
recurse: true
become: trueSet sticky bit, setuid, setgid
# Sticky bit on shared directory (only owner can delete their files)
- name: Set sticky bit on /tmp-style directory
ansible.builtin.file:
path: /shared/uploads
mode: '1777' # Leading 1 = sticky bit
become: true
# Setgid on group directory (new files inherit group)
- name: Set setgid on project directory
ansible.builtin.file:
path: /projects/teamwork
mode: '2775' # Leading 2 = setgid
group: developers
become: trueFAQ
Why must I quote the mode value?
Without quotes, YAML interprets 0644 as the integer 644 (octal 01204), which gives wrong permissions. Always use mode: '0644' with quotes.
How do I check current permissions?
- name: Get current permissions
ansible.builtin.stat:
path: /etc/myapp/config.yml
register: file_info
- name: Show permissions
ansible.builtin.debug:
msg: "Mode: {{ file_info.stat.mode }}, Owner: {{ file_info.stat.pw_name }}"What does recurse: true do?
Applies the same owner/group/mode to all files AND directories inside the path. Be careful — files and directories often need different permissions (644 vs 755).
How do I change permissions on Windows?
Use ansible.windows.win_acl for Windows ACL permissions:
- name: Set Windows permissions
ansible.windows.win_acl:
path: C:\inetpub\wwwroot
user: IIS_IUSRS
rights: ReadAndExecute
type: allowBasic Permission Change
- ansible.builtin.file:
path: /opt/myapp/start.sh
mode: '0755'
become: trueChange Owner and Group
- file:
path: /var/www/html
owner: www-data
group: www-data
recurse: true
become: trueCommon Permission Patterns
# Executable script
- file:
path: /opt/scripts/deploy.sh
mode: '0755'
owner: deploy
# Private key
- file:
path: /home/deploy/.ssh/id_rsa
mode: '0600'
owner: deploy
group: deploy
# Config file (read-only)
- file:
path: /etc/myapp/config.yml
mode: '0644'
owner: root
group: root
# Shared directory
- file:
path: /opt/shared
state: directory
mode: '0775'
owner: root
group: developers
# Sensitive config
- file:
path: /etc/myapp/secrets.yml
mode: '0600'
owner: root
group: rootSymbolic Mode
# Add execute for owner
- file:
path: /opt/script.sh
mode: u+x
# Add read/write for group
- file:
path: /opt/shared/data
mode: g+rw
recurse: true
# Remove world read
- file:
path: /etc/myapp/secrets
mode: o-rwxRecursive Permissions
# All files and directories
- file:
path: /var/www/mysite
owner: www-data
group: www-data
recurse: true
become: true
# Different permissions for files vs directories
- shell: |
find /var/www/mysite -type d -exec chmod 755 {} \;
find /var/www/mysite -type f -exec chmod 644 {} \;
become: trueSUID, SGID, Sticky Bit
# SGID on directory (new files inherit group)
- file:
path: /opt/shared
state: directory
mode: '2775'
group: developers
become: true
# Sticky bit (only owner can delete)
- file:
path: /tmp/shared
state: directory
mode: '1777'
become: trueACLs (Extended Permissions)
- ansible.posix.acl:
path: /opt/myapp
entity: deploy
etype: user
permissions: rwx
state: present
become: true
# Default ACL for new files
- ansible.posix.acl:
path: /opt/myapp
entity: developers
etype: group
permissions: rx
default: true
state: present
become: trueBatch Permission Changes
- file:
path: "{{ item.path }}"
mode: "{{ item.mode }}"
owner: "{{ item.owner | default('root') }}"
loop:
- { path: /opt/myapp/bin/start.sh, mode: '0755' }
- { path: /opt/myapp/etc/config.yml, mode: '0644' }
- { path: /opt/myapp/etc/secrets.yml, mode: '0600' }
- { path: /opt/myapp/log, mode: '0755' }
become: trueVerify Permissions
- stat:
path: /etc/myapp/config.yml
register: file_info
- debug:
msg: "Mode: {{ file_info.stat.mode }}, Owner: {{ file_info.stat.pw_name }}"
- assert:
that:
- file_info.stat.mode == '0644'
- file_info.stat.pw_name == 'root'Permission Reference
| Mode | Meaning |
|---|---|
0755 | rwxr-xr-x (executables, directories) |
0644 | rw-r--r-- (config files) |
0600 | rw------- (secrets, private keys) |
0700 | rwx------ (private directories) |
0775 | rwxrwxr-x (shared directories) |
0666 | rw-rw-rw- (shared files, rarely used) |
2775 | rwxrwsr-x (SGID directory) |
1777 | rwxrwxrwt (sticky bit, like /tmp) |
FAQ
Octal string vs integer?
Always quote mode as a string: mode: '0755'. Without quotes, YAML may interpret it as an integer (493), which causes unexpected permissions.
How do I change permissions without changing content?
The file module only changes metadata (permissions, owner, timestamps). It never modifies file content.
recurse doesn't set different perms for files vs dirs?
Correct — recurse applies the same mode to everything. Use find + shell for different file vs directory permissions.
Related Articles
Category: windows-automation
Watch the video: Ansible chmod: Change File Permissions with file Module (Guide) — Video Tutorial