Docker & DevOps

Open a shell inside a running Docker container

Use docker exec to get a bash or sh shell inside a running container, run one-off commands, act as root or another user, and copy files in and out with docker cp.

BeginnerLinux server5 min read

Sooner or later you need to look inside a container: check a config file, run a database command or see why the app cannot reach something. docker exec runs a command in a container that is already running, without restarting it. This guide covers interactive shells, one-off commands, users, and copying files with docker cp.

Before you start

  • A Linux VPS with Docker Engine installed. See Install Docker and Docker Compose.
  • A running container. docker exec does not work on stopped containers.
  • The container name or ID from docker ps.
Bash
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'

Open an interactive shell

Bash
docker exec -it web bash
  • -i keeps standard input open so you can type.
  • -t gives you a proper terminal, so the prompt and line editing work.

Many small images, such as those based on Alpine or BusyBox, do not include bash. Use sh instead:

Bash
docker exec -it web sh

Type exit or press Ctrl + D to leave. The container keeps running.

Note: Some hardened images, often called distroless, contain no shell at all. docker exec then fails with executable file not found. Use docker cp to read files, or start a debug container that shares the target's network, as shown below.

Run a one-off command

Leave out -it when you only need the output:

Bash
docker exec web cat /etc/nginx/conf.d/default.conf
docker exec web nginx -t
docker exec db psql -U postgres -c 'select version();'

Use -it again for commands that need a terminal, such as an interactive database client:

Bash
docker exec -it db psql -U postgres

To use shell features like pipes or * inside the container, wrap the command in sh -c:

Bash
docker exec web sh -c 'ls /var/log/nginx/*.log | wc -l'

Without sh -c, the pipe would run on the host instead.

Run as root or as another user

docker exec runs as the image's default user. Many images run as a non-root user for safety, so commands such as package installs fail. Run as root for a moment:

Bash
docker exec -it -u root app sh

Or run as a specific user or numeric ID:

Bash
docker exec -u www-data app php artisan cache:clear
docker exec -u 1000:1000 app id

Warning: Changes you make inside a container, such as installing a package or editing a file outside a volume, are lost when the container is recreated. Treat exec sessions as a place to inspect and test. Make permanent changes in the Dockerfile, the Compose file or a mounted volume.

Set the working directory and environment

Bash
docker exec -w /app -e DEBUG=1 app node scripts/check.js

-w sets the directory the command starts in, and -e adds an environment variable for this command only.

Exec into a Compose service

From the project folder, you can use the service name instead of the container name:

Bash
docker compose exec app sh
docker compose exec db psql -U postgres

docker compose exec allocates a terminal by default, so -it is not needed. Add -T to disable it when running from a script or cron job.

Copy files with docker cp

docker cp copies between the host and a container. It works on stopped containers too.

Copy a file out of the container:

Bash
docker cp web:/etc/nginx/nginx.conf ./nginx.conf

Copy a file in:

Bash
docker cp ./nginx.conf web:/etc/nginx/nginx.conf
docker exec web nginx -s reload

Copy a whole folder out:

Bash
docker cp app:/app/logs ./app-logs

Files copied into a container end up owned by root. If the app runs as another user, check ownership with docker exec web ls -l /etc/nginx/ and fix it with docker exec -u root web chown if needed.

Debug a container that has no tools

To test networking from the point of view of a minimal container, start a throwaway container that shares its network:

Bash
docker run --rm -it --network container:app nicolaka/netshoot

Inside it you have curl, dig, ss and other tools, and localhost is the app container's localhost. If you prefer not to pull a third-party image, busybox:stable offers wget and nslookup.

Check it works

Confirm you are inside the right container and as the right user:

Bash
docker exec web sh -c 'hostname; id; pwd'

The hostname matches the container ID shown by docker ps, and id shows the user the command ran as.

Troubleshooting

  • Error response from daemon: container... is not running: start it first with docker start NAME. If it stops again straight away, see Fix a Docker container that exits immediately.
  • OCI runtime exec failed: exec: "bash": executable file not found: the image has no bash. Use sh, or docker cp for distroless images.
  • the input device is not a TTY: you used -t from a script or cron job. Drop -t, or use docker compose exec -T.
  • Permission denied inside the container: you are running as a non-root user. Add -u root for that command.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.