There are real reasons to want a Linux shell that isn't your host's: testing a script's portability, reading docs that assume a specific distro, learning Linux on a Windows or Mac machine, or making sure a tool works on Alpine before you commit to building a slim image. A VM is overkill for a 30-minute experiment. A docker run gives you a Linux shell in under three seconds.
How do I run Linux in Docker?
# Ubuntu 24.04 LTS
docker run --rm -it ubuntu:24.04 bash
# Debian 12 (bookworm)
docker run --rm -it debian:12 bash
# Alpine 3.20 (very small, musl libc)
docker run --rm -it alpine:3.20 sh
# Fedora 41
docker run --rm -it fedora:41 bash
# Rocky Linux 9 (RHEL-compatible)
docker run --rm -it rockylinux:9 bash--rm deletes the container when you exit, so nothing is left behind. -it gives you an interactive terminal. Replace bash with sh on Alpine (no bash by default).
When you exit, the container is gone. Anything you installed, every file you created, all gone. A new docker run is a fresh, untouched system.
What's NOT in a minimal image
Container images are stripped down. The things you take for granted on a real Linux install are often absent:
- No
sudo. You are root inside the container;sudois unnecessary and usually not installed. - No
systemd. Container processes run directly under PID 1.systemctldoes not work. - No editors.
vim,nano,less— not in the base image. Install them:apt update && apt install -y vimon Ubuntu/Debian,apk add vimon Alpine. - No
ping,curl,wget,dig,ip,netstat. Networking tools are extras.apt install -y iputils-ping curl dnsutils iproute2. - No
ps,top,kill -l. Many process tools come fromprocps:apt install -y procps. - Tiny package lists by default. Ubuntu official is ~30 MB. Alpine official is ~7 MB. Compare to a real install at multiple GB — the difference is everything except the bare minimum.
That's the trade-off of container images. The first thing most experiments need is apt update to refresh the package index.
Practical usage: a real session
A common case — checking whether a shell script works on Ubuntu 24.04 when you're on a Mac:
docker run --rm -it -v "$(pwd):/work" -w /work ubuntu:24.04 bash
# Inside the container:
apt update
apt install -y curl jq
./my-script.shThe bind mount (-v "$(pwd):/work") means your project on the host is at /work inside the container; the script sees your files. When you exit, the container is gone but the files on your host are unchanged (unless the script wrote to them — bind mounts go both ways).
Same shape for trying a tool that doesn't run on macOS or Windows natively. Need strace? Run an Ubuntu container with it.
Make changes persist across runs
--rm is the throwaway version. If you want your work to stick across multiple sessions, skip --rm, name the container, and docker start -ai it next time:
# First time: create and start
docker run --name sandbox -it ubuntu:24.04 bash
# do work, exit
# Next time: resume
docker start -ai sandbox
# everything you installed is still theredocker start -ai starts the container and attaches your terminal to it. The writable layer survives between runs as long as the container exists.
To preserve work across container removal (so you can docker rm and recreate without losing files), put your work in a named volume:
docker run --name sandbox -it \
-v sandbox-home:/root \
ubuntu:24.04 bashThe sandbox-home volume holds anything you put in /root (or wherever you mount it). New containers attached to the same volume see the same files.
Pick a distro
| Distro | When to reach for it |
|---|---|
Ubuntu (ubuntu:24.04, ubuntu:22.04) | Default for tutorials, broad package support, what most cloud VMs run. |
Debian (debian:12, debian:11) | Stable, smaller package surface than Ubuntu, parent of Ubuntu. Great for reproducible servers. |
Alpine (alpine:3.20) | Tiny (~7 MB). musl libc and BusyBox tools — different enough from Debian that some software doesn't build. Used heavily for small production images. |
Fedora (fedora:41) | Bleeding-edge package versions. Good for testing against future RHEL. |
Rocky / AlmaLinux (rockylinux:9) | RHEL-compatible. For matching production RHEL/CentOS environments. |
Arch (archlinux:latest) | Rolling release, AUR style, for testing against very current packages. |
For learning Linux fundamentals, Ubuntu or Debian are the easiest start.
Common pitfalls
- Container exits immediately when you start it without
-it. A container with no foreground process exits.-it(-ito keep stdin open,-tfor a TTY) gives you an interactive shell. Without it,bashreads no input and exits. Unable to locate packageerrors right afterapt install. Runapt updatefirst. The image has no package index by default to keep its size down.- No
bashon Alpine. Usesh(BusyBox ash). If you really want bash,apk add bashfirst. - Changes lost after exit. Expected with
--rm. For persistence, name the container and usedocker start -ai, or mount a volume. - Permission errors on a bind-mounted directory. The container's UID 0 (root) creates files owned by root on the host. Run as your user with
-u "$(id -u):$(id -g)", or accept that you'll needsudo chownto clean up.
FAQ
Sources
Authoritative references this article was fact-checked against.
- Official Ubuntu image — Docker Hubhub.docker.com
- Official Debian image — Docker Hubhub.docker.com
- Official Alpine image — Docker Hubhub.docker.com

