Suggest an editImprove this articleRefine the answer for “How to copy files between a Docker container and the host?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`docker cp`** copies files in either direction between a container and the host. The container can be running or stopped — Docker handles both. ```bash # Container -> host docker cp web:/etc/nginx/nginx.conf ./nginx.conf # Host -> container docker cp ./fix.sql db:/tmp/fix.sql # Whole directory docker cp web:/var/log/nginx/ ./nginx-logs ``` **Key:** for one-off copies, `docker cp` is fine. For ongoing dev (host editing → live container), use a bind mount instead. For backup of long-lived data, `tar` through a temporary container.Shown above the full answer for quick recall.Answer (EN)Image**`docker cp`** is the simplest way to move files between a container and your host. It works in both directions, on running and stopped containers, and handles directories recursively. ## Theory ### TL;DR - Syntax: `docker cp SRC DST`. One side has format `CONTAINER:PATH`. - Works on both running and stopped containers. - Copies recursively for directories. Preserves ownership/permissions inside the container. - For ongoing host↔container sync, use bind mounts. For backup of volumes, use a tar via a helper container. - Cannot copy between two containers directly — pipe through host or use a shared volume. ### Quick example ```bash # Get a config file out of a container for inspection $ docker cp nginx-c:/etc/nginx/nginx.conf ./nginx.conf # Drop a SQL fix into a running db $ docker cp ./hotfix.sql db:/tmp/hotfix.sql $ docker exec db psql -U postgres -f /tmp/hotfix.sql # Copy a whole directory of logs out $ docker cp web:/var/log/nginx ./nginx-logs ``` Three directions, all using the same `docker cp`. ### Syntax in detail ```bash docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH docker cp [OPTIONS] CONTAINER:SRC_PATH - # to stdout (as tar) docker cp [OPTIONS] - CONTAINER:DEST_PATH # from stdin (tar) ``` Flags: - `-a` / `--archive` = preserve file owner/group/mode (default behavior since recent versions). - `-L` / `--follow-link` = follow symbolic links in SRC. ### Source/destination behavior Docker's behavior depends on whether SRC and DEST are existing directories: ```bash # Both are existing dirs → copy SRC contents into DEST docker cp /host/dir/. container:/dst/ # note the trailing /. # SRC is dir, DEST does not exist → SRC becomes DEST docker cp /host/dir container:/newdst # /newdst now contains what /host/dir had # SRC is file, DEST is existing dir → file goes inside DEST docker cp /host/file.txt container:/dst/ # → /dst/file.txt # SRC is file, DEST is new path → file is renamed docker cp /host/file.txt container:/dst/renamed.txt ``` Gotcha: trailing `/.` matters. `dir/` vs `dir/.` behaves differently — same behavior as `cp -r` in shell. ### Stream form (tar) ```bash # Stream a tar of /etc out of the container docker cp container:/etc - | tar tf - # list contents # Pipe arbitrary content into a path inside container tar cf - mydir | docker cp - container:/dest ``` Useful for backup pipelines and when you cannot use `docker run --rm` to mount. ### Common mistakes **Forgetting that `cp` to the writable layer is ephemeral** ```bash $ docker cp ./config.yml api:/etc/config.yml # Edit applied. Container restart → file may persist (it is in writable layer). # But docker rm → file gone forever. ``` `docker cp` writes to the container's writable layer. Persists across `docker stop/start` of the same container. Lost on `docker rm`. For permanent changes, edit your image (Dockerfile) or use a volume / bind mount. **Trying to copy between two containers** ```bash # WRONG: not supported $ docker cp source:/file target:/file Error: invalid arguments # Use a stream: $ docker cp source:/file - | docker cp - target:/file # Or a shared volume. ``` **Surprised at file owner on the host** The container often runs as a specific user (root, or app-specific). Files extracted with `docker cp` keep their UIDs, which may be unfamiliar on the host: ```bash $ docker cp api:/var/log/access.log . $ ls -la access.log -rw-r--r-- 1 1000 1000 ... access.log # UID 1000 from inside container ``` Sometimes UID 1000 happens to match your user; sometimes it does not. Use `chown $(id -u):$(id -g) ...` after the copy if needed. **Confusing direction** ```bash # WRONG: this copies FROM host TO container, but the colon is on the wrong side $ docker cp container:./file ./file # error or surprise # RIGHT $ docker cp container:/path/file ./file # container → host $ docker cp ./file container:/path/file # host → container ``` The colon-separated form (`container:path`) is the container side; the other side is the host. ### When to NOT use `docker cp` - **Persistent data** (databases, uploads): use named volumes. `docker cp` writes to the writable layer, which is the wrong place. - **Live dev sync** (edit-on-host, see-in-container): bind mount, not `docker cp`. Faster, no copy step. - **Large directories repeatedly:** consider `rsync` over `docker exec` for delta-only transfers, or just use a bind mount. - **Across hosts:** `docker save | ssh ... | docker load` for images; `tar` over `ssh` for raw files. ### Real-world usage - **Pulling logs out of a misbehaving prod container** before `docker rm`'ing it. - **Injecting a quick fix** (SQL, config snippet) into a running container as a stopgap. Permanent fix goes into the image. - **Backups:** `docker cp` from a stopped DB container to host as a snapshot. Or via `tar` through a helper container — `docker run --rm -v vol:/data alpine tar cf - /data > backup.tar`. - **Debugging:** copy a core dump or heap dump out of the container for analysis. ### Follow-up questions **Q:** Does `docker cp` work on a stopped container? **A:** Yes. The container's filesystem (image + writable layer) exists as long as the container record does. You can `cp` in/out without starting it. **Q:** Are there permission issues when copying into a running container? **A:** Sometimes. The destination's directory permissions and the path's owner inside the container determine if the file ends up owned by root or by the app user. Use `--chown` flag if you need a specific UID/GID — but `docker cp` does not have that flag like `COPY --chown=`. Workaround: `docker exec ... chown` after the copy. **Q:** What is the difference between `docker cp` and `docker exec ... cat ... > file`? **A:** `docker cp` understands directory recursion, preserves metadata, and works on stopped containers. The `exec ... cat` trick works for single files on running containers only. `docker cp` is the right primitive. **Q:** How do I copy from a container to a different host's container? **A:** Pipe through the network: `docker cp src:/file - | ssh remote 'docker cp - dst:/file'`. Or, if both hosts can reach the same registry, build an image with the file and pull it on the other side. **Q:** (Senior) When is `docker cp` not the right primitive even for one-off copies? **A:** Anything you find yourself doing repeatedly should be a volume. Anything you want versioned (config files) should be in the Dockerfile or a config-management volume. Anything large and frequently changing belongs in object storage with the container reading at startup. `docker cp` is for ad-hoc, one-shot, debug-style copies. ## Examples ### Pull config out, edit, push back ```bash $ docker cp web:/etc/nginx/nginx.conf ./nginx.conf $ vi ./nginx.conf $ docker cp ./nginx.conf web:/etc/nginx/nginx.conf $ docker exec web nginx -s reload ``` Quick one-off config tweak. The proper fix would be to bake the config into a new image or mount it from host, but for an emergency tweak this works. ### Backup with tar via a helper container ```bash # Backup a volume's contents (container does not need to be running) $ docker run --rm \ -v pgdata:/data \ -v $PWD:/backup \ alpine \ tar czf /backup/pgdata-$(date +%F).tar.gz -C /data . ``` Better than `docker cp` for volumes because volumes are not part of any single container's writable layer. ### Stream a directory through a tar pipe ```bash # Get all logs as a tar stream $ docker cp web:/var/log/nginx - > logs.tar $ tar xf logs.tar # Inverse: push a tar into a container $ tar cf - some-dir | docker cp - container:/destination ``` Useful when you need to filter on the way (`tar` flags) or when the destination does not have shell-friendly paths.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.