1.2 · Running containers: ports, names, modes, variables

Level 1 · Containers: images, volumes, networks

1.2Running containers: ports, names, modes, variables

Goal: starting any Hub service while exposing ports and configuration.
Estimated time: 13 min · self-paced reading · If you only have 5 min: read “The essentials in 30s” + the diagram.

The essentials in 30 seconds

  • Publishing a port = the entry door: -p 8080:80 links port 8080 of the machine to port 80 of the container — left = host, right = container; without publishing, the service stays invisible.
  • Detached or interactive, two modes: services run with -d (background), one-off tools with -it (attached terminal) — a server in -it blocks the terminal.
  • Configuring without rebuilding: -e KEY=value drives official images and --name gives a stable identity to target the container (logs, exec, stop).

Running mini-case — Idir launches the test stack

Idir must show the application to his manager: a Postgres database and an Nginx frontend on his machine. He launches the database detached, named bdd, with the password passed via -e — without publishing its port, useless for a local demo. Then he launches the web named web with -p 8080:80 and opens http://localhost:8080: the page displays. When his manager asks « which container is the database? », Idir answers « bdd » — a name, not a hexadecimal identifier.

Continuation of case 1.1 — Idir moves from chosen images to launched containers.

1. Publishing a port: the entry door

A container lives in its isolated network: without publishing, its port 80 is invisible from the machine. -p 8080:80 links port 8080 of the machine to port 80 of the container. The rule: left = host, right = container. Two containers can expose the same internal port with different host ports.

Publish only what must be reached from the outside: the web frontend yes, the database no (it stays reachable internally, section 1.4).

2. Detached or interactive: two modes

Services run detached (-d, in the background). One-off tools run interactive (-it, attached terminal: docker run -it --rm ubuntu:24.04 bash). Never mix them: a server in -it blocks the terminal, a shell in -d is unusable.

The reflex: « is it a service that must run alone? -d. Is it a tool I need the keyboard for? -it. »

3. Configuring without rebuilding: -e and --name

Official images are driven by environment variables (-e POSTGRES_PASSWORD=secret): no need to rebuild an image to change a password. --name gives a stable identity to target the container (logs, exec, stop).

Name + variables + ports: 90% of launches fit on one line. Variables are frozen at creation: to change one, delete and relaunch.

Common misinterpretation: « -p 8080:80 reads both ways, and -it also suits a server ». No. The order is host:container (reversing = exposing the wrong port or failing), and a server launched with -it blocks the terminal: as soon as you close it, the service follows. Services with -d, tools with -it — never the reverse.
Launching a reachable service Naming, publishing the port, injecting the config --name + -d Stableidentity, in background-p host:container Left =host, right = container-e configuration Withoutrebuilding the image
Naming, publishing the port, injecting the config
Text version of the diagram (SEO / screen readers / translation): 1) Name: Idir launches his database with --name bdd detached (-d), so he can target it later. 2) Publish: he launches the web with -p 8080:80 — left host, right container — and opens http://localhost:8080. 3) Configure: the database password goes through -e, without rebuilding the image. Lesson: name + ports + variables on one line; the database stays unpublished because nothing from the outside should reach it.

🔎 Concrete example — 🔎 Concrete example — Reachable Postgres and Nginx

Idir's demo stack: a discreet database, an accessible web.

docker run -d --name bdd -e POSTGRES_PASSWORD=secret postgres:16.4
docker run -d --name web -p 8080:80 nginx:1.27

Reading: the database runs in the background with no published port (useless), the web answers on http://localhost:8080.

Lesson: publish only what must be reached from the outside.

Section vocabulary

-p host:container
Publishing a container port to the host machine; left = host, right = container.

Simple example: -p 8080:80 makes Idir's web reachable on http://localhost:8080.

What it is not: opening a port only inside the container.

Reflex: re-read left/right before each run.

-d (detached)
Background mode: the container runs without blocking the terminal; the mode for services.

Simple example: Idir's bdd database and web run with -d during the demo.

What it is not: an attached terminal you must leave open.

Reflex: long-lived service = -d.

-it (interactive)
Terminal attached to the container (often with --rm for throwaway uses); the mode for one-off tools.

Simple example: docker run -it --rm ubuntu:24.04 bash to tinker.

What it is not: the mode of a production server.

Reflex: need the keyboard = -it, never for a server.

-e and --name
-e injects a configuration variable at startup; --name gives a stable identity to control the container.

Simple example: -e POSTGRES_PASSWORD=secret and --name bdd at Idir's.

What it is not: configuration hard-coded into the image.

Reflex: config in -e, systematic naming on long-lived services.

In practice — In practice — Launching two services

  1. Launch a named postgres database with password via -e.
  2. Launch nginx with 8080:80 publishing and open localhost:8080.
  3. Open a shell in each container (exec) and compare.
  4. Stop and cleanly remove both containers.
You launch any Hub service with ports, name and configuration.

Script ready to say — launching a service (30 s)

« I launch detached with a name: --name web -d. I publish the host port to the container: -p 8080:80, left host, right container. I pass the config via -e variables, without touching the image. I check on localhost:8080. »

Say while typing the command line by line; show the terminal blocked by -it for contrast.

Copy-paste template — the launch line

docker run -d --name MONSERVICE \
  -p HOTE:CONTENEUR \
  -e CLE=valeur \
  image:tag-fige
# E.g. Idir's web:
# docker run -d --name web -p 8080:80 nginx:1.27

Idir's demo in Algiers

As above: unpublished bdd + web on 8080:80 — the manager sees the app, the database stays invisible from the outside.

Throwaway tool

docker run -it --rm ubuntu:24.04 bash: attached terminal, auto-removal on exit — the mode for tools, never for servers.

Two frontends coexist

Two Nginx with the same internal port 80, published as 8080:80 and 8081:80: the host port differs, the container port is identical.

Changing a password

Variables with -e are frozen at creation: delete the container and relaunch with the new value — no magic restart.

Caution: Two points of caution: each published port widens the exposed surface of the machine — publish only what is needed, especially on a shared workstation or server. And a password passed via -e stays visible in the shell history: avoid real secrets in shared demos and prefer test values.

✓ Best practices

  • Systematically name long-lived services.
  • Publish only the needed ports.
  • Pass config via -e, never hard-coded in the image.

✗ Common pitfalls

  • Reversing host:container in -p.
  • Launching a server with -it (blocked terminal).
  • Putting a plain-text password in history without thinking.

Key takeaways

  • -p links host and container (left/right).
  • -d for services, -it for tools.
  • -e configures without rebuilding.
  • --name makes everything manageable.

48h challenge — apply tomorrow

Launch two named services (database with -e unpublished + web on 8080:80), open localhost:8080, then stop and remove cleanly. Note the host:container order without reversing it.

Section exit checklist
  • I publish ports in the right order (host:container).
  • I choose -d for a service, -it for a tool.
  • I configure with -e and name each long-lived service.
Self-assessment 1-5: do I re-read left/right before each -p?does each long-lived container have a --name?

Frequently asked questions

Why does localhost:80 not answer although the container runs?

Because the port is not published: the service listens in the container's isolated network. Add -p host:container to the run — left = host, right = container.

Must I restart to change an -e variable?

Yes: variables are frozen at creation. Delete and relaunch (or move to Compose at level 3 to version it all).

Check your understanding

You run 'docker run -d -p 8080:80 nginx'. What does 8080:80 mean?

Additional resources (optional, to go further)

Level 1 examFresh, harder questions to test what you've learned