Docker & DevOps

Docker run flags you will actually use (-d, -p, -v, -e, --restart)

The docker run options that matter on a VPS, explained with examples. Covers detached mode, port publishing, volumes, environment variables, names, restart policies and resource limits.

BeginnerLinux server5 min read

docker run has dozens of options, but on a typical VPS you use the same eight or nine again and again. This guide explains each one with an example, then puts them together into a single command you can adapt. Once the command works, you can move it into a Compose file so it is easy to repeat.

Before you start

  • A Linux VPS with Docker Engine installed. See Install Docker and Docker Compose.
  • A user that can run docker commands (in the docker group, or using sudo).
  • Basic familiarity with images, containers and tags.

The general shape of the command is:

docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARGS...]

Options always go before the image name. Anything after the image name is passed to the container as its command.

-d: run in the background

Without -d, the container runs in your terminal and stops when you press Ctrl + C. With -d (detached), Docker starts it in the background and prints the container ID.

Bash
docker run -d nginx:stable

Use -it instead when you want an interactive shell, for example docker run -it --rm debian:12 bash.

--name: give the container a name

Docker invents random names like quirky_turing unless you set one. A fixed name makes logs and exec commands easier:

Bash
docker run -d --name web nginx:stable
docker logs web

Names must be unique. To reuse a name, remove the old container first with docker rm -f web.

-p: publish a port

-p HOST:CONTAINER forwards a port on the VPS to a port inside the container.

Bash
docker run -d --name web -p 8080:80 nginx:stable

The site is now on http://203.0.113.10:8080. To expose it only to the server itself, for example behind a reverse proxy, bind to localhost:

Bash
docker run -d --name web -p 127.0.0.1:8080:80 nginx:stable

Warning: Published ports skip UFW's normal rules, because Docker writes its own firewall rules. Bind private services to 127.0.0.1 or read Fix UFW and Docker bypassing the firewall.

-v: keep data in a volume or folder

Files written inside a container are lost when it is removed. -v mounts storage that survives.

A named volume, managed by Docker:

Bash
docker run -d --name db -v pgdata:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=change-me postgres:16

A bind mount, using a folder on the host:

Bash
docker run -d --name web -p 8080:80 \
  -v /srv/site:/usr/share/nginx/html:ro nginx:stable

The :ro suffix makes the mount read-only inside the container.

-e and --env-file: environment variables

Most images are configured through environment variables:

Bash
docker run -d --name app -e TZ=Europe/London -e APP_ENV=production myapp:1.0

For more than two or three variables, put them in a file, one KEY=value per line, and load it:

Bash
docker run -d --name app --env-file /srv/app/app.env myapp:1.0

Keep that file readable only by its owner (chmod 600), because it often holds passwords.

--restart: come back after a crash or reboot

By default a stopped container stays stopped, even after the VPS reboots. Add a restart policy:

Bash
docker run -d --name web --restart unless-stopped -p 8080:80 nginx:stable

unless-stopped restarts the container after crashes and reboots, unless you stopped it yourself. The other policies are covered in Docker restart policies.

--memory and --cpus: resource limits

On a small VPS, one runaway container can starve everything else. Cap it:

Bash
docker run -d --name app --memory 512m --cpus 1 myapp:1.0

If the app goes over 512 MB, the kernel kills it rather than the whole server slowing down.

Other flags worth knowing

  • --rm removes the container when it exits. Ideal for one-off tasks.
  • --network NAME attaches the container to a user-defined network so containers can reach each other by name.
  • -u 1000:1000 runs the process as a specific user and group ID instead of the image default.
  • -w /app sets the working directory.
  • --read-only makes the container's own filesystem read-only.

Putting it together

A realistic command for a small web app:

Bash
docker run -d \
  --name app \
  --restart unless-stopped \
  -p 127.0.0.1:3000:3000 \
  -v app-data:/app/data \
  --env-file /srv/app/app.env \
  --memory 512m --cpus 1 \
  myapp:1.0

The same thing in Compose is easier to keep and change:

YAML
services:
  app:
    image: myapp:1.0
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - app-data:/app/data
    env_file: /srv/app/app.env
    mem_limit: 512m
    cpus: 1
volumes:
  app-data:

Check it works

Inspect the running container to confirm each option took effect:

Bash
docker ps --filter name=app
docker inspect app --format '{{.HostConfig.RestartPolicy.Name}} {{.HostConfig.Memory}}'

The second command should print unless-stopped 536870912, which is 512 MB in bytes.

Troubleshooting

  • docker: invalid reference format: an option is placed after the image name, or there is a stray space in a -v or -e value. Keep options before the image and quote values with spaces.
  • Conflict. The container name "/web" is already in use: remove the old container with docker rm -f web or choose a new name.
  • Port works locally but not from outside: you bound it to 127.0.0.1, or a provider or host firewall blocks the port.
  • Environment variable has no effect: the image may read a different name. Check the image's documentation on Docker Hub or its project page.

Next steps

  • Turn long commands into files: Docker Compose file explained.
  • Choose how containers recover from crashes: Docker restart policies.
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.