Ansible copy Module: Copy Files to Remote Hosts (ansible.builtin.copy Guide)
By Luca Berton · Published 2024-01-01 · Category: windows-automation
How to copy files to remote hosts with Ansible copy module (ansible.builtin.copy). Transfer files, set permissions, use content parameter, backup.

How to copy files to remote hosts?
I'm going to show you a live Playbook with some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible PilotSee also: Ansible Copy Multiple Files: fileglob Lookup & with_fileglob Examples
Ansible copy files to remote hosts
Today we're talking about Ansible module copy. The full name is "ansible.builtin.copy" which means is part of the collection of modules "builtin" with ansible and shipped with it. This module is pretty stable and out for years. The purpose is to copy files to remote locations. Please note that the opposite is done by Ansible fetch module. For Windows target use Ansible win_copy module.Parameters
• dest _path_ - remote path • src _string_ - local path • backup _boolean_ - no / yes • validate _string_ - validation command • checksum _string_ 2.5+ • mode/owner/group • setype/seuser/selevelThe parameter list is pretty wide but I'll summarize the most useful.
The only required parameter is "dest" which specifies the remote absolute path destination.
The "src" specifies the source file in the controller host. It could be a relative or absolute path. I recommend absolutely.
The backup boolean option allows you to create a backup if the utility overwrites any file.
If there is any tool to validate the file we could specify it in the validate parameter, very useful for configuration files.
Let me also highlight that we could also specify the permissions and SELinux properties.
See also: Ansible win_copy Module: Copy Files to Windows Hosts (ansible.windows.win_copy)
Demo
Let's jump in a real-life playbook to copy files to remote hosts with Ansible.code
• copy.yml---
- name: copy module Playbook
hosts: all
become: false
tasks:
- name: copy report.txt
ansible.builtin.copy:
src: report.txt
dest: /home/devops/report.txt
owner: devops
mode: '0644'
• report.txt
test report.txt
Conclusion
Now you know how to Copy files to remote hosts with Ansible.See also: Ansible Create File with Content: copy Module content Parameter
Advanced Copy Examples
Copy with backup
- name: Deploy config with automatic backup
ansible.builtin.copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: true # Saves existing file as .backup
become: true
notify: reload nginx
Copy entire directory
- name: Copy directory to remote
ansible.builtin.copy:
src: files/app/ # Trailing slash copies CONTENTS
dest: /opt/myapp/
owner: appuser
group: appuser
mode: '0755'
become: true
# Without trailing slash: copies the directory itself
# src: files/app → creates /opt/myapp/app/
# src: files/app/ → copies contents into /opt/myapp/
Validate before replacing
- name: Copy and validate nginx config
ansible.builtin.copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
validate: /usr/sbin/nginx -t -c %s
become: true
# Only replaces if nginx -t passes
Copy with content from variable
- name: Generate hosts file entry
ansible.builtin.copy:
content: |
{% for host in groups['webservers'] %}
{{ hostvars[host].ansible_host }} {{ host }}
{% endfor %}
dest: /etc/hosts.d/webservers
mode: '0644'
become: true
Remote-to-remote copy (using remote_src)
- name: Copy file on remote host
ansible.builtin.copy:
src: /var/log/app.log
dest: /backup/app.log.bak
remote_src: true # Source is on the remote host
become: true
copy vs synchronize vs template
| Module | Use Case | Speed |
|--------|----------|-------|
| copy | Single files, small directories | Moderate |
| synchronize | Large directories (rsync) | Fast |
| template | Files needing Jinja2 rendering | Moderate |
| fetch | Remote → controller (reverse copy) | Moderate |
For directories with many files, synchronize (rsync) is significantly faster than copy.
Key Parameters
| Parameter | Description |
|-----------|-------------|
| src | Local source path |
| dest | Remote destination path |
| content | Write text content directly |
| mode | File permissions |
| owner / group | File ownership |
| backup | Create backup of existing file |
| force | Overwrite if content differs (default: true) |
| remote_src | Source is on remote host |
| validate | Command to validate file before replacing |
| directory_mode | Permissions for created directories |
FAQ
Why is copy slow for large files?
Ansible copy calculates checksums and transfers via SSH/SFTP. For large files or many files, use synchronize (rsync) instead:
- name: Sync large directory
ansible.posix.synchronize:
src: /local/large-dir/
dest: /remote/large-dir/
How do I copy files between two remote hosts?
Use fetch + copy, or delegate:
- name: Fetch from source
ansible.builtin.fetch:
src: /data/export.csv
dest: /tmp/
flat: true
delegate_to: source_server
- name: Copy to destination
ansible.builtin.copy:
src: /tmp/export.csv
dest: /data/import.csv
Does copy preserve timestamps?
No — copy sets the modification time to the current time. Use synchronize with --times to preserve timestamps.
Copy File to Remote
- name: Copy config to remote
ansible.builtin.copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
become: true
Copy with Backup
- copy:
src: files/app.conf
dest: /etc/myapp/app.conf
backup: true # Creates timestamped backup
become: true
Copy Directory
# With trailing slash — copies CONTENTS
- copy:
src: files/configs/
dest: /etc/myapp/
become: true
# Without trailing slash — copies the DIRECTORY itself
- copy:
src: files/configs
dest: /opt/
become: true
Copy Between Remote Paths
- copy:
src: /opt/myapp/config.yml
dest: /opt/myapp/config.yml.bak
remote_src: true
become: true
Inline Content
- copy:
content: |
DB_HOST={{ db_host }}
DB_PORT={{ db_port }}
APP_ENV={{ env }}
dest: /etc/myapp/.env
mode: '0600'
become: true
Copy Multiple Files
- copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode | default('0644') }}"
loop:
- { src: nginx.conf, dest: /etc/nginx/nginx.conf }
- { src: php.ini, dest: /etc/php/8.2/fpm/php.ini }
- { src: deploy.sh, dest: /opt/scripts/deploy.sh, mode: '0755' }
become: true
notify: restart services
Conditional Copy
- copy:
src: "configs/{{ env }}.conf"
dest: /etc/myapp/config.conf
become: true
# Or with when
- copy:
src: files/ssl.conf
dest: /etc/nginx/conf.d/ssl.conf
when: enable_ssl | default(false)
become: true
Validate Before Placing
- copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
validate: "nginx -t -c %s"
become: true
- copy:
src: files/sudoers
dest: /etc/sudoers
validate: "visudo -cf %s"
become: true
Force and Idempotency
# Only copy if file doesn't exist
- copy:
src: files/initial-config.yml
dest: /etc/myapp/config.yml
force: false # Don't overwrite existing
become: true
# Always overwrite (default)
- copy:
src: files/config.yml
dest: /etc/myapp/config.yml
force: true
become: true
copy vs synchronize vs template
| Module | Best For |
|--------|----------|
| copy | Single/few files, inline content |
| synchronize | Large directory trees (rsync) |
| template | Files with Jinja2 variables/logic |
| fetch | Copy FROM remote TO controller |
| get_url | Download from HTTP/HTTPS |
Key Parameters
| Parameter | Description |
|-----------|-------------|
| src | Source file/dir on controller |
| dest | Destination on remote |
| content | Inline content (instead of src) |
| owner/group | File ownership |
| mode | Permissions |
| backup | Keep backup of original |
| force | Overwrite if different |
| remote_src | Source is on remote host |
| validate | Validation command |
| directory_mode | Mode for created directories |
| follow | Follow symlinks |
FAQ
How do I copy from remote to local?
Use the fetch module:
- fetch:
src: /var/log/app.log
dest: /tmp/logs/{{ inventory_hostname }}/
flat: true
Large files are slow — alternatives?
Use synchronize (rsync wrapper) for large files or directories — it's significantly faster.
Why does copy show "changed" every run?
Check file permissions — if mode doesn't match, Ansible reports a change. Always specify mode explicitly.
Copy a File
- ansible.builtin.copy:
src: files/app.conf
dest: /etc/myapp/app.conf
become: true
With Permissions
- copy:
src: files/app.conf
dest: /etc/myapp/app.conf
owner: appuser
group: appgroup
mode: '0644'
become: true
Write Content Directly
- copy:
content: |
[database]
host = db.example.com
port = 5432
dest: /etc/myapp/db.conf
mode: '0644'
become: true
Copy Directory
- copy:
src: files/configs/ # Trailing slash = copy contents
dest: /etc/myapp/
become: true
- copy:
src: files/configs # No trailing slash = copy directory itself
dest: /etc/myapp/
become: true
Backup Before Overwrite
- copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
backup: true # Creates .bak file
become: true
notify: reload nginx
Don't Overwrite Existing
- copy:
src: files/default.conf
dest: /etc/myapp/config.conf
force: false # Skip if dest exists
become: true
Validate Before Deploy
# Validate nginx config
- copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
validate: "nginx -t -c %s"
become: true
# Validate sudoers
- copy:
src: files/sudoers
dest: /etc/sudoers.d/myapp
validate: "visudo -cf %s"
mode: '0440'
become: true
Copy from Remote to Remote
# remote_src copies on the remote host itself
- copy:
src: /opt/backup/config.conf
dest: /etc/myapp/config.conf
remote_src: true
become: true
Copy with Variable Content
- copy:
content: "{{ lookup('template', 'config.j2') }}"
dest: /etc/myapp/config.conf
become: true
copy vs template vs synchronize
| Module | Use Case |
|--------|----------|
| copy | Static files, small content |
| template | Dynamic files with Jinja2 |
| synchronize | Large directories (rsync) |
| fetch | Remote → controller (reverse copy) |
FAQ
copy vs fetch?
copy sends files controller→remote. fetch pulls files remote→controller.
How to copy to multiple hosts?
Just target multiple hosts — copy runs on each host in the play.
Large files slow?
Use synchronize (rsync wrapper) for large files or many files — it's much faster than copy.
Related Articles
• the Ansible become reference • the Ansible roles overview • Ansible for Windows guideCategory: windows-automation
Watch the video: Ansible copy Module: Copy Files to Remote Hosts (ansible.builtin.copy Guide) — Video Tutorial