Docker packages an application together with everything it needs to run, so the same app behaves the same way on your laptop and on your VPS. Before you install your first stack, it helps to know the handful of terms Docker uses everywhere. This guide explains them with short examples you can run on a Linux VPS.
Before you start
- A Linux VPS running Ubuntu 22.04 or 24.04, Debian 12, or AlmaLinux or Rocky Linux 8 or 9.
- A user with
sudorights, connected over SSH. - Docker Engine and the Compose plugin installed. If you have not done that yet, follow Install Docker and Docker Compose first.
Images: the read-only template
An image is a packaged filesystem plus some metadata: which command to start, which port the app listens on, and which environment variables it expects. Images are built in layers. Each instruction in a Dockerfile adds a layer, and layers are shared between images, so two images based on the same Debian base only store that base once.
Images are read-only. You never edit an image in place; you build a new one.
List the images on your server:
docker image lsDownload an image without running it:
docker pull nginx:stableTags: versions of an image
The part after the colon is the tag. It usually names a version, such as nginx:1.27 or postgres:16. If you leave the tag off, Docker uses latest.
latest is only a label. It does not always mean "newest", and it changes when the publisher pushes a new build. On a server you care about, pin a specific tag so an update never surprises you.
Tip: Pin to a major or minor version (postgres:16, node:22-alpine) and update on purpose. That keeps security fixes flowing without jumping to a new major release.
Containers: a running copy of an image
A container is a process started from an image. Docker gives it its own filesystem view, network interface and process list, but it shares the host's Linux kernel. That is why containers start in under a second and use far less memory than a full virtual machine.
Start a test container:
docker run -d --name web -p 8080:80 nginx:stable-druns it in the background.--name webgives it a name you can use later.-p 8080:80sends traffic from port 8080 on the VPS to port 80 in the container.
See running containers:
docker psA container has a thin writable layer on top of its image. Anything written there disappears when the container is removed. Data you want to keep belongs in a volume. See Docker volumes vs bind mounts for how that works.
Stop and remove the test container:
docker stop web
docker rm webRegistries: where images live
A registry stores images so servers can pull them. The common ones are:
- Docker Hub (
docker.io), the default when an image name has no host in front. - GitHub Container Registry (
ghcr.io). - Registries run by cloud providers, or a private registry you host yourself.
The full name of an image includes the registry, the repository and the tag:
ghcr.io/example/myapp:1.4.2
docker.io/library/nginx:stablenginx:stable is a short form of the second line. Official images live under the library namespace on Docker Hub.
docker run versus Docker Compose
docker run starts one container with options typed on the command line. It is fine for quick tests, but long commands are easy to mistype and hard to repeat.
Docker Compose describes one or more containers in a compose.yaml file. You keep the file in a folder, put it under version control and start everything with one command:
services:
web:
image: nginx:stable
ports:
- "8080:80"
restart: unless-stoppeddocker compose up -dUse docker run to experiment. Use Compose for anything that should still be running next month. The Docker Compose file explained guide walks through every common key.
When containers make sense on a small VPS
Containers are a good fit when:
- You run several apps that need different versions of the same runtime, such as two Node.js versions.
- The app is published as an official image, for example Nextcloud, Gitea or Uptime Kuma.
- You want a clean way to remove an app completely, with nothing left behind on the host.
- You want to move a stack to a new server by copying a folder and its volumes.
They add little value when:
- You only run one simple site that the distribution's packages already cover, such as a static site behind Nginx.
- The server has very little RAM and every megabyte counts. Docker itself is light, but each container brings its own copy of its runtime libraries.
Check it works
Run Docker's test image:
docker run --rm hello-worldThe output should start with Hello from Docker!. The --rm flag removes the container when it exits. Then check your disk usage by type:
docker system dfYou should see lines for Images, Containers, Local Volumes and Build Cache.
Troubleshooting
permission denied while trying to connect to the Docker daemon socket: your user is not in thedockergroup, or you have not logged in again since adding it. See Fix "permission denied" on the Docker socket.Unable to find image... pull access denied: the image name or tag is misspelt, or the image is private and you have not logged in to that registry.port is already allocated: another container or service already uses that host port. Pick a different host port or stop the other process.- The container stops straight away: run
docker logs <name>to see why. Many images exit when a required environment variable is missing.
Next steps
- Learn the options you will use every day: Docker run flags you will actually use.
- Build your own image: Write a Dockerfile and build your first image.
- Keep your stacks tidy with Docker Compose commands cheat sheet.
