Table of Contents
Go from Ansible beginner to Ansible pro with this full video course.
What does the Ansible copy
module do?
Ansible’s copy
module is suited to the following tasks:
- Copying files from the local host to the remote host
- name: copy file from local host to remote host (relative path, ./files/)
copy:
src: test_file
dest: $HOME/test_file
- name: copy file from local host to remote host (absolute path)
copy:
src: /path/to/ansible/files/test_file
dest: $HOME/test_file
- Copying files between locations on the remote host (using the
remote_src
parameter)
- name: copy file between locations on the remote host
copy:
src: $HOME/test_file
remote_src: true
dest: $HOME/test_file2
- Writing a simple templated text file (using the
content
parameter)
- name: write templated text content into a file on the remote host
copy:
dest: $HOME/test_file
content: "Hello, {{ ansible_user }}!"
If you need to copy files from the remote host to the local host, use the fetch
module.
Ansible copy
Module Video Tutorial
If you prefer watching to reading, here’s a full video tutorial from the TopTechSkills YouTube channel covering a many of the points and examples from this article. Feel free to comment on this article or the video if you have any questions.
When to use the copy
module vs synchronize
module
If you need to copy many (> 100) deeply nested files recursively, I recommend you use the synchronize
module since recursively copying many files with copy
is slow. The synchronize
module is a wrapper around rsync
, which is very efficient and fast at recursively copying large numbers of deeply nested files.
When to use the copy
module vs fetch
module
The copy
module is used when you want to put files onto the remote host, or you want to move files between places on the remote host. The fetch
module is used when you want to move files from the remote host to the local host (i.e. fetch a file from the remote host).
When to use the copy
module vs template
module
The copy
module is capable of putting dynamic (templated) text into a file like so:
- name: put templated text content into a file on the remote host
copy:
dest: $HOME/test_file
content: "Hello, {{ ansible_user }}!"
This is fine for a small amount of text, but if you need to write a large amount of templated text (e.g. a configuration file with many templated lines) you should use the template
module.
Where the copy
module searches for files/directories on the local host
When copying from the local host, Ansible will search for files and directories in the ./files/
directory relative to where Ansible is being run. You can also supply an absolute path to the local file. Given the following file structure, the two plays have the same effect:
.
├── ansible.cfg
├── files
│ └── test_file
└── playbook.yml
# Recommended
- name: copy file from local host to remote host (relative path, ./files/)
copy:
src: test_file
dest: $HOME/test_file
# NOT recommended
- name: copy file from local host to remote host (absolute path)
copy:
src: /path/to/ansible/files/test_file
dest: $HOME/test_file
Given that the result is the same, I highly recommend using the relative file path since it will prevent errors if you ever move, copy or rename your Ansible directory.
Examples
How to copy a file from the local host to a remote host
You can use the src
(local host) and dest
(remote host) parameters to copy a file to a remote host. Note that the src
searches the ./files
directory relative to the playbook.
- name: copy file from local host to remote host
copy:
src: test_file
dest: $HOME/test_file
How to copy a file from the local host to a remote host with owner, group and file permissions
The owner
, group
and mode
parameters give you fine control over the ownership and file permissions of the file(s) created by the copy
module. Remember that you will need become: true
if you are setting the owner
or group
to values that don’t match the ansible_user
.
The mode
parameter accepts the file permissions setting in the following ways:
- An octal number: e.g.
0755
,0644
,0400
- Symbolic mode format: e.g.
u=rw,g=r,o=r
(whereu
is the owner,g
is the group, ando
is others). The permissions arer
forread
,w
for write andx
for execute.
With octal mode:
- name: copy file from local to remote with owner, group and file permissions (octal)
copy:
src: test_file
dest: $HOME/test_file
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0644
With symbolic mode:
- name: copy file from local to remote with owner, group and file permissions (symbolic)
copy:
src: test_file
dest: $HOME/test_file
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: u=rw,g=r,o=r
Setting a different owner with become: true
:
- name: copy file from local to remote with root as the owner (become required)
copy:
src: test_file
dest: "/home/{{ ansible_user }}/test_file"
owner: root
group: root
mode: 0644
become: true
How to copy a file between directories on a remote host with owner, group and file permissions
With octal mode:
- name: copy file between directories on remote with owner, group and file permissions (octal)
copy:
src: $HOME/test_file
remote_src: true
dest: $HOME/test_file2
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0644
With symbolic mode:
- name: copy file between directories on remote with owner, group and file permissions (symbolic)
copy:
src: $HOME/test_file
remote_src: true
dest: $HOME/test_file2
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: u=rw,g=r,o=r
Setting a different owner with become: true
:
- name: copy file between directories on remote with root as the owner (become required)
copy:
src: $HOME/test_file
remote_src: true
dest: "/home/{{ ansible_user }}/test_file"
owner: root
group: root
mode: 0644
become: true
How to copy a directory from the local host to a remote host (recursive copy)
The copy
module can be used to copy a directory from the local host to a remote host (called a recursive copy). To do a recursive copy, set the src
parameter to a directory rather than a file.
There are two different behaviors:
src: test_directory
(without trailing slash): recursively copies the wholetest_directory
from./files
intodest
src: test_directory/
(with trailing slash): copies only the contents oftest_directory
recursively intodest
Let’s look at the results of recursive copy
given the following file structure on the local host:
files
├── test_directory
│ ├── test_directory_2
│ │ └── test_file_2
│ └── test_file_1
└── test_file
Recursive copy without trailing slash
- name: copy directory recursively from local to remote (no trailing slash)
copy:
src: test_directory
dest: $HOME
Resulting file structure on the remote:
.
└── test_directory
├── test_directory_2
│ └── test_file_2
└── test_file_1
Recursive copy with trailing slash
- name: copy directory recursively from local to remote (trailing slash)
copy:
src: test_directory/
dest: $HOME
Resulting file structure on the remote:
.
├── test_directory_2
│ └── test_file_2
└── test_file_1
How to copy a directory between locations on the remote host (recursive copy)
This functionality is not currently supported by the copy
module. If you want to recursively copy directories between locations on the remote host, please use the synchronize
module.
How to write plain text into a file on the remote host with copy
You can write plain text to a file using the content
parameter.
- name: write plain text into a file on the remote host
copy:
dest: $HOME/test_file
content: "Hello, World!"
How to write templated text into a file on the remote host with copy
You can write templated text to a file using the content
parameter. Although this is fine for simple one-line files, if you want to write multi-line templated text to a file, please use the template
module.
- name: write templated text into a file on the remote host
copy:
dest: $HOME/test_file
content: "Hello, {{ ansible_user }}!"
How to test that a file is valid before copying to the remote host
Use the validate
parameter to check whether a file is valid on the remote host before copying the file into place. This parameter is highly recommended if you have some program that can confirm the whether a target file is valid.
%s
in the validate
string refers to the file to be checked.
How to check the validity of a sudoers
file before copying
The /usr/sbin/visudo -cf
command checks the validity of a sudoers
file:
- name: update /etc/sudoers with validation
copy:
src: sudoers
dest: /etc/sudoers
owner: root
group: root
mode: 0400
validate: /usr/sbin/visudo -cf %s
become: true
How to check the validity of an nginx
configuration file before copying
The /usr/bin/nginx -t -c
command checks the validity of an nginx
configuration file:
- name: update /etc/nginx/nginx.conf with validation
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: 0644
validate: /usr/bin/nginx -t -c %s
become: true
How to backup a file if copy
needs to overwrite it
By default, the copy
module will overwrite a file if it already exists on the remote host. If you want to backup the file before it is overwritten, use the backup
parameter:
- name: copy file from local host to remote host with backup
copy:
src: test_file
dest: $HOME/test_file
backup: true
With backup: true
, copy
will make a backup and append the timestamp before overwriting the file:
.
├── test_file
└── test_file.14792.2018-12-26@11:26:17~
How to copy multiple files with a loop
Use the loop
keyword and {{ item }}
to copy multiple files.
- name: copy multiple files from local host to remote host
copy:
src: test_file
dest: "$HOME/test_file_{{ item }}"
register: copy_output
loop:
- 1
- 2
How to capture copy
module output
Use the register
keyword to capture the output of the copy
module.
- name: copy file from local host to remote host
copy:
src: test_file
dest: $HOME/test_file
register: copy_output
- debug: var=copy_output
The debug
task above will output the following:
ok: [123.123.123.123] => {
"copy_output": {
"changed": true,
"checksum": "60fde9c2310b0d4cad4dab8d126b04387efba289",
"dest": "/home/ubuntu/test_file",
"diff": [],
"failed": false,
"gid": 1000,
"group": "ubuntu",
"md5sum": "bea8252ff4e80f41719ea13cdf007273",
"mode": "0664",
"owner": "ubuntu",
"size": 14,
"src": "/home/ubuntu/.ansible/tmp/ansible-tmp-1545813585.53-237422897797330/source",
"state": "file",
"uid": 1000
}
}
How to capture copy
module output from a loop
When using the copy
module in a loop, the output of each item in the loop will go into the results
key of the registered variable.
- name: copy multiple files from local host to remote host
copy:
src: test_file
dest: "$HOME/test_file_{{ item }}"
register: copy_output
loop:
- 1
- 2
- debug: var=copy_output
ok: [123.123.123.123] => {
"copy_output": {
"changed": true,
"msg": "All items completed",
"results": [
{
...
"changed": true,
"checksum": "60fde9c2310b0d4cad4dab8d126b04387efba289",
"dest": "/home/ubuntu/test_file_1",
"diff": [],
"failed": false,
"gid": 1000,
"group": "ubuntu",
"invocation": {...},
"item": "1",
"md5sum": "bea8252ff4e80f41719ea13cdf007273",
"mode": "0664",
"owner": "ubuntu",
"size": 14,
"src": "/home/ubuntu/.ansible/tmp/ansible-tmp-1545814066.74-176188973279099/source",
"state": "file",
"uid": 1000
},
{
...
"changed": true,
"checksum": "60fde9c2310b0d4cad4dab8d126b04387efba289",
"dest": "/home/ubuntu/test_file_2",
"diff": [],
"failed": false,
"gid": 1000,
"group": "ubuntu",
"invocation": {...},
"item": "2",
"md5sum": "bea8252ff4e80f41719ea13cdf007273",
"mode": "0664",
"owner": "ubuntu",
"size": 14,
"src": "/home/ubuntu/.ansible/tmp/ansible-tmp-1545814068.75-122305147949956/source",
"state": "file",
"uid": 1000
}
]
}
}
Further reading
Ansible copy
Module on Ansible Docs