ThisCalculator

Everyday

Ansible Copy Module Examples for Remote Servers

Updated · Standard formula, shown below

Ansible Copy Module Examples for Remote Servers

The Ansible copy module copies a file or directory from the local machine (or the control node) to a remote server. You provide the source path, the destination path, and optionally set permissions, ownership, and backup behavior. This article shows practical examples, explains how the module works, and covers common pitfalls.

Basic Syntax and Parameters

The simplest playbook task using copy looks like this:

- name: Copy a file
  ansible.builtin.copy:
    src: /local/path/file.txt
    dest: /remote/path/file.txt

Key parameters you will use often:

  • src – source file or directory on the control node. If it is a directory, the entire directory is copied recursively.
  • dest – absolute path on the remote host. If src is a directory, dest is the parent directory where the source directory will be placed.
  • owner and group – set the file ownership on the remote host.
  • mode – set file permissions, e.g., 0644 or 'u=rw,g=r,o=r'.
  • backup – if yes, create a timestamped backup of the remote file if it differs from the source.
  • force – if no, the file is only copied if the destination does not exist.
  • content – instead of src, you can provide the file content directly as a string.

Copying a Single File

The most common use is copying a configuration file. For example, to deploy an NGINX configuration:

- name: Deploy nginx config
  ansible.builtin.copy:
    src: files/nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'

Note the quotes around 0644 – without them, YAML would interpret it as a number and the leading zero would be lost, resulting in wrong permissions.

Copying a Directory

To copy an entire directory, point src to the directory. The behavior depends on a trailing slash:

  • src: mydir – copies the directory itself to dest, creating dest/mydir.
  • src: mydir/ – copies the contents of mydir directly into dest.

Example:

- name: Copy website files
  ansible.builtin.copy:
    src: public/
    dest: /var/www/html/
    owner: www-data
    group: www-data
    mode: '0755'

Using content Instead of a File

When the file content is short or generated dynamically, use content:

- name: Create a simple file
  ansible.builtin.copy:
    dest: /etc/motd
    content: |
      Welcome to this server.
      Managed by Ansible.
    owner: root
    group: root
    mode: '0644'

This is useful for templates that do not need variables; for variable substitution, use the template module instead.

Setting Permissions and Ownership

You can set permissions using octal notation (e.g., 0644) or symbolic (e.g., u=rw,g=r,o=r). Ownership is set with owner and group – the remote user must have privileges to change ownership, so run the task with become: yes if needed.

Example with symbolic mode:

- name: Copy script with specific permissions
  ansible.builtin.copy:
    src: script.sh
    dest: /usr/local/bin/script.sh
    mode: 'u=rwx,g=rx,o=rx'

Backup and Force Options

If the destination file already exists and differs from the source, Ansible will overwrite it by default. To keep a backup, set backup: yes – the old file is saved with a timestamp suffix. To avoid overwriting an existing file, set force: no – the task will skip if the destination exists.

- name: Copy with backup
  ansible.builtin.copy:
    src: config.yml
    dest: /etc/app/config.yml
    backup: yes

Common Mistakes and Troubleshooting

  • Missing quotes on mode – as mentioned, always quote the mode.
  • Trailing slash confusion – forgetting the trailing slash on a directory source can create an unexpected nested directory.
  • Permission denied – when writing to protected paths like /etc, use become: yes.
  • File always shows as changed – if the source file changes every run (e.g., timestamps), the copy module will report changed. Use checksum to verify, or consider the template module if content is dynamic.
  • Copying between remote hosts – the copy module only copies from the control node to the remote. To copy between two remote hosts, use the fetch module to download first, then copy, or use synchronize with delegate_to.

Frequently Asked Questions

Can I copy a file from one remote server to another?
No, the copy module only works from the control node to a remote host. To transfer between remotes, use fetch to pull the file to the control node, then copy to push it to the second host, or use synchronize with the delegate_to parameter.

What is the difference between copy and template?
copy copies a static file as-is. template processes a Jinja2 template file, allowing you to substitute variables and use loops/conditionals. Use template when the file content depends on host variables.

How do I copy a file only if it doesn’t exist?
Set force: no. The task will skip if the destination already exists, regardless of content.

Why does my copy task always report ‘changed’?
This usually happens when the source file changes on every run (e.g., it contains a timestamp or a build ID). Ansible compares checksums; if they differ, it copies. If you want to avoid unnecessary copies, ensure the source file is stable, or use template with a fixed output.

Can I copy a file with special characters in the path?
Yes, but you must quote the path properly in YAML. Use single quotes for paths with spaces or special characters, e.g., src: '/path/with space/file.txt'.

Does copy module preserve file attributes like SELinux context?
By default, it does not preserve SELinux context. You can set setype, seuser, serole parameters, or use synchronize with rsync_opts to preserve attributes.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.