Docker Compose commands wey you need for server
Learn Docker Compose V2 commands for lifecycle, changes, logs, shells, networks, volumes, and safe cleanup, plus why docker-compose fails on fresh Ubuntu.
Compose commands wey you go really use
Docker Compose get more than forty subcommands. Daily server work dey use about twelve. This page group dem according to the work wey you dey do, give one clear reason for each one, and point you to the detailed guide when command get hidden problem.
Everything here dey use Compose V2: docker compose with a space, no be the old docker-compose script. V2 na Go plugin wey dey install together with Docker Engine, and V1 don comot from current packages. So, if you see docker-compose: command not found for fresh Ubuntu box as of July 2026, na expected result, no be error. Check am with docker compose version. If e print nothing, install the docker-compose-plugin package.
Every command below dey run from the directory wey hold your compose.yaml, because Compose dey take project name from that directory and dey find the file relative to am. If you run the same command one level up, Compose go stop with no configuration file provided: not found. If file format itself still new to you, start with your first Compose file for VPS, then come back here for the commands.
Lifecycle: commands wey you dey type four times, and the one wey dey remove containers
docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose downup -d go create the network, create the containers, start dem, then return. E go return as soon as e don create the containers. Na why deploy script wey run curl probe after am often fail for the first try. up -d --wait go wait until every service wey declare healthcheck report say e healthy, and e go exit with non-zero status if any one no reach that state. The flag only dey work as well as the check behind am, so write healthcheck wey Compose fit trust before you depend on am for automation.
stop go stop the containers but keep dem, so start go bring back the same containers with the same writable layer. down go stop dem, then remove the containers and the project network. Anything wey you write inside the container and outside a volume go disappear with dem. Na this be the most costly misunderstanding for Compose, and the complete difference between down and stop explain where e fit cause problem.
restart no be reload. E go stop and start the same container with the configuration wey e already get, so changed environment variable, new image tag, or edited port mapping no go get any effect. To apply file change, run up -d again. Compose go compare each service with the container wey dey run, then recreate only the ones wey configuration don change.
Change apply: recreate, pull, or rebuild
docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build webup -d no dey do anything when nothing change, and na wetin make am safe to run again and again. --force-recreate bypass that comparison and replace every container even when the configuration still dey the same, so na the quickest way to clear strange state inside container.
Updating image need two commands because each one dey do different work. pull dey download the current image for every tag wey dem name for the file. up -d then see say the service image ID no longer match the container wey dey run, so e recreate am. If you skip the pull, up -d go keep last month’s latest running without error. The opposite risk dey happen for multi-service stack, where pulling latest for every service at once fit break app wey dey work ten seconds earlier. Na why self-hosted AFFiNE workspace pin each of its four image tags instead. Pinning also make upgrade become deliberate tag edit, followed by that same pull and recreate. For stack wey dey migrate database as e boot, you need get dump ready before either command. Na this routine self-hosted Chatwoot support desk dey follow for every version bump.
build apply to services wey declare a build: section instead of a image:. up -d --build build and start for one step, and na the normal loop when you dey change code. Use --no-cache only when cached layer clearly stale, because e rebuild every layer from scratch.
Wetin dey run
docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose lsps dey list only containers wey dey run. Service wey crash during startup no go show there until you add -a, so if container no dey ps but ps -a show am as Exited (1), na the normal pattern for startup failure. Read the exit code, then read the logs.
logs -f dey follow every service at once and put service name for front of each line. Na this view you need when services dey communicate with each other and event order matter. Put service name to narrow the result. --tail=100 matter for container wey don dey up for one month, because the default go print the complete history and fill the terminal with too much output. --since 15m answer the question wey you normally get: wetin happen during the restart wey you just do.
top dey list the processes inside each container. This one help separate "the container dey run" from "the process inside am dey run". ls comot from the current directory and list every Compose project for the host with its status, so you fit find the stack wey you start three months ago.
Get shell inside service
docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web shexec dey run command inside container wey don already dey up. run dey start new container from the same service definition. Na this one you need when service no stay up long enough make you exec inside am. Always use run together with --rm, because if you no use am, every invocation go leave stopped container behind. Dem go pile up until docker compose ps -a no readable again.
Try sh before bash. Alpine-based images no get bash, and the error message go show exec: "bash": executable file not found in $PATH. If you add --no-deps to run, e go skip the service dependencies. This stops quick config check from starting your whole database.
run --rm web env na the fastest way to see the environment wey service really receive, after e don merge every .env file, environment: block, and shell variable. When value no correct, na usually the merge order cause am. how Compose dey resolve env files and secrets explain which source go win.
Networks, ports, and name resolution
docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networksCompose dey put every service for one project network, and each service name na DNS name for that network. When you run getent hosts db inside web, e go print the container IP if name resolution work, and e no go print anything if e no work. So, within two seconds, e answer “these containers fit see each other?” If the name resolve but connection dey refuse, the process inside db dey bound to 127.0.0.1 instead of 0.0.0.0. Because of this, e no dey accept packet from another container. This same boundary explain why container wey start outside the project, whether na by docker run or as its own stack, no fit resolve name like jellyfin at all. Na the first thing to check when Halcyon front end for your Jellyfin library no fit reach the server wey e point to. You fit read the rest of this model for how Compose networks and service DNS dey work.
port web 80 go print the host address and port wey container port publish to. This one save you from guessing when variable provide the mapping. When you publish port, Docker also write firewall rule wey e manage by itself. That rule dey before your own rule, so service wey you think say na private fit become open to internet. why published Docker ports dey bypass ufw explain this case. The safer arrangement na to leave those ports unpublished and put one authenticating proxy for the project network in front of the services. Na this setup running Authentik as one single sign-on layer provide.
Volumes and data
docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -vconfig --volumes dey print the named volumes wey the project declare, one for each line. Na that list you need back up. When the volumes hold something wey you no fit replace, the exact backup command matter as much as the list. Na why the PhotoPrism and Immich comparison dey show the dump and copy commands wey each photo server need. cp dey copy file enter or comot from container without opening shell, using the service:path form for any side wey container dey.
down -v dey remove those named volumes together with the containers. Na the correct command to tear down test stack, but e wrong for anything wey hold data wey you care about, because e no dey ask for confirmation and you no fit undo am. Bind mounts survive am because dem dey live for host filesystem. This difference for blast radius na one reason to choose carefully between bind mounts and named volumes.
Cleanup wey fit free disk without losing data
docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune--remove-orphans dey delete containers wey belong to the project but dem no dey appear again for the file. Na exactly wetin happen after you rename service. If you no run am, those containers go continue to run, but docker compose ps no go show dem.
docker system df dey show where the disk space dey go before you delete anything. E separate images, containers, local volumes, and build cache, then show reclaimable figure for each one. image prune -a dey remove every image wey no tag dey point to. For server wey don pull several versions of one large image, this one usually dey free the most space. builder prune dey clear build cache. This cache dey grow quietly for any server wey dey build its own images.
None of those commands dey touch named volume. Na only docker volume prune and docker compose down -v dey do that.
Check the file before e cause problem
docker compose config --quiet
docker compose config --services
docker compose --dry-run up -dconfig --quiet dey validate and print nothing when e succeed, so e good for pre-deploy step or git hook. Plain config dey print the fully merged and interpolated file. Na so you fit confirm say variable resolve and override file layer the way you expect. If variable no set, e go show as empty value, together with warning The "X" variable is not set. Defaulting to a blank string.
--dry-run na global flag, no be subcommand flag, so e go come before up. E dey print every action Compose go take and e no change anything. Those thirty seconds worth am before you run down for stack wey matter.
Working across files, profiles, and projects
docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -dMultiple -f flags dey merge in order, and later files dey override earlier ones key by key. Na the standard way to keep one base file with small production override, but the rules dey different for lists and maps, so read how Compose merges multiple files before you debug unexpected result.
--profile dey start services wey get that profile together with the ones wey no get profile, so debug tooling no go enter normal up. -p dey set the project name, so two copies of one stack fit run side by side with separate networks and separate volume names. To bring the stack back after reboot no be command wey you type yourself; na unit wey dey run one for you, as starting Compose stacks on boot describe.
FAQ
Wetin replace docker-compose wey get hyphen?
Compose V2, wey you call as docker compose with space. E na plugin wey dey bundled with Docker Engine, and current packages no dey install the V1 Python tool again. If the space form no print anything, install docker-compose-plugin package for your distribution. Update old scripts to use the space form instead of adding alias, because V2 get flags wey V1 never get.
Why docker compose restart no dey pick my config change?
restart stops and starts the existing container with the configuration wey dem use create am, and e no ever read compose.yaml again. Any change to environment variables, ports, volumes, or image tag need docker compose up -d. E compare each service with the container wey dey run, then e recreate the ones wey differ. Add --force-recreate when you want make e replace am even when nothing for the file change.
How I fit update service to newer image?
Run docker compose pull, then docker compose up -d. The pull go fetch the current image for each tag wey dey the file, and up -d go recreate any service wey image ID no longer match the container. If you run up -d alone, e go reuse the image wey already dey disk. Na so stack wey pin to latest fit remain on build wey don old for months without showing any error.
Which cleanup commands safe for live server?
docker system df, docker image prune -a and docker builder prune remove images and cache only, so services wey dey run go continue working and named volumes no go touch. The dangerous pair na docker compose down -v and docker volume prune, because dem delete named volumes without prompt. Run docker compose config --volumes first so you go know wetin dey at risk.
I fit run one command without starting the whole stack?
Yes. docker compose run --rm --no-deps web sh start one container from the web service definition, e skip the dependencies, and e remove the container when you exit. Use exec instead when the container don already dey run, because exec join the live process and show you the actual state wey the service dey inside.