Independent hosting operator since 2014 · New York · Dallas · Amsterdam Status Looking Glass Contact
D4 NetworksD4 Networks
Client area Deploy a server
Home / Resources / Install Docker on a VPS and run your first app

Tutorials

Install Docker on a VPS and run your first app

Jun 6, 2026 · 8 min read

Docker packages an application with everything it needs, so you can run it on any server with one command. This guide installs Docker Engine from the official repository and runs a real app on it.

1. Install Docker Engine

Do not use the docker.io package from your distribution. It is usually old. Use Docker's own repository.

Ubuntu and Debian
$ sudo apt-get update
$ sudo apt-get install -y ca-certificates curl
$ sudo install -m 0755 -d /etc/apt/keyrings
$ . /etc/os-release
$ echo "$ID $VERSION_CODENAME"
$ sudo curl -fsSL https://download.docker.com/linux/$ID/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$ID $VERSION_CODENAME stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

The . /etc/os-release line loads your distribution name and codename into the shell, so the same commands work on both Ubuntu and Debian. It prints nothing by itself; the echo after it shows what was loaded, for example ubuntu noble or debian trixie. If that line prints nothing at all, you are not on a Debian-based system, so use the block below instead.

RHEL-based
$ sudo dnf -y install dnf-plugins-core
$ sudo curl -fsSL https://download.docker.com/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker-ce.repo
$ sudo dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
$ sudo systemctl enable --now docker

The repository says centos, which is correct for AlmaLinux, Rocky Linux, and RHEL, because they are binary compatible. We download the repository file with curl because the dnf config-manager syntax changed between AlmaLinux 9 and AlmaLinux 10, and downloading the file works on both.

Check that it works:

ssh session
$ sudo docker run --rm hello-world
$ docker compose version

Note the command is docker compose with a space. The old docker-compose with a hyphen is version 1 and no longer maintained.

2. Run Docker without sudo (optional)

ssh session
$ sudo usermod -aG docker $USER

Log out and log in again for the change to apply.

The docker group equals root

Any user in the docker group can start a container that mounts the whole filesystem, which means they can become root. Only add users you would trust with the root password. On a server where you already work as one admin user, this is fine. On a shared server, skip this step and keep using sudo.

3. Run your first real app

Here is a monitoring tool, Uptime Kuma, in one command:

ssh session
$ docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:2

What the parts mean:

  • -d runs it in the background.
  • --restart=always starts it again after a reboot or a crash.
  • -p 3001:3001 maps port 3001 on the server to port 3001 in the container.
  • -v uptime-kuma:/app/data stores the app data in a Docker volume, outside the container.
  • louislam/uptime-kuma:2 is the image and its major version.

Open http://YOUR.SERVER.IP:3001 in a browser to reach it.

4. Volumes keep your data

A container is disposable. When you delete it, everything inside it is gone. Anything you want to keep must live in a volume, which is the -v part above.

ssh session
$ docker volume ls
$ docker ps
$ docker logs uptime-kuma
$ docker stop uptime-kuma && docker rm uptime-kuma

You can delete and recreate the container with the same -v option, and your data is still there. That is also how you update: pull the new image, remove the container, run it again.

5. Use Compose for anything with more than one part

Long docker run commands are hard to remember. A Compose file stores the same settings in a file you can read and edit:

/opt/kuma/compose.yaml
services:
  uptime-kuma:
    image: louislam/uptime-kuma:2
    container_name: uptime-kuma
    restart: always
    ports:
      - "3001:3001"
    volumes:
      - uptime-kuma:/app/data

volumes:
  uptime-kuma:
ssh session
$ cd /opt/kuma
$ docker compose up -d
$ docker compose logs -f
$ docker compose pull && docker compose up -d

The last line is how you update: pull new images and recreate the containers. Your volumes are not touched.

6. Do not expose containers to the internet directly

Port 3001 in the example above is open to everyone, over plain HTTP. That is fine for a first test and wrong for anything real. Bind the container to localhost only, then put a reverse proxy with HTTPS in front of it:

/opt/kuma/compose.yaml
    ports:
      - "127.0.0.1:3001:3001"

Our guide on Nginx and Let's Encrypt covers the proxy and the certificate.

Quick reference

TaskCommand
List running containersdocker ps
See logsdocker logs NAME or docker compose logs -f
Stop and removedocker stop NAME && docker rm NAME
Update an imagedocker compose pull && docker compose up -d
List volumesdocker volume ls
Free unused spacedocker system prune

Where to go next

Add a reverse proxy so your app is served over HTTPS on your own domain. Keep an eye on disk usage: Docker images and build cache grow quietly, and our guide on freeing disk space covers the cleanup commands.

docker containers compose ubuntu debian almalinux

Related articles