Docker packages an app and its dependencies into a container. The Compose plugin (docker compose) starts a group of those containers from one YAML file. This article installs Docker Engine from Docker's official repository on a LochStudios KVM VPS.
Shared hosting (cPanel) is a different product. You cannot run Docker there. You need a VPS.
The IPv4, username, password, and an out-of-band console sit on that server in the portal. Sign in at the portal, open the VPS service, and copy the login from there.
Before you start
- Sign in at the portal, open the VPS service, and keep that page open.
- Connect with a sudo user, or
rooton a fresh box. See Connect to your VPS via SSH from macOS or Linux or from Windows. - Prefer a sudo user for daily work: First steps on a new VPS.
- Use Ubuntu 22.04 or 24.04, or Debian 12. If you are on AlmaLinux or Rocky Linux, skip to AlmaLinux or Rocky Linux.
If SSH from your PC will not connect, open the console on the same service. That session does not need port 22 from your network.
If you are logged in as root, omit sudo from the commands below.
Ubuntu or Debian
1. Update packages
sudo apt update
sudo apt upgrade -y
2. Remove older Docker packages (if any)
Ubuntu and Debian ship docker.io in their own repos. Remove those so they do not fight Docker Engine:
sudo apt remove -y docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc
It is fine if apt says some of those packages were not installed.
3. Install the tools the repo needs
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
4. Add Docker's official repository
Ubuntu:
sudo curl -fsSL https://download.docker.com/linux/ubuntu/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/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Debian:
sudo curl -fsSL https://download.docker.com/linux/debian/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/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Use the Ubuntu block on Ubuntu and the Debian block on Debian. Mixing the two leaves apt unable to find packages.
5. Install Docker Engine and Compose
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
That is Docker Engine, the CLI, containerd, Buildx, and Compose v2 (docker compose, two words). You do not need a separate docker-compose binary.
AlmaLinux or Rocky Linux
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Docker publishes that repo for RHEL-compatible systems. If dnf config-manager is missing, install dnf-plugins-core first, then retry.
Start Docker and confirm it works
sudo systemctl enable --now docker
sudo docker --version
sudo docker compose version
sudo docker run --rm hello-world
You should see version strings and a Hello from Docker! message. The test container is removed afterwards (--rm).
Check the service if a command fails:
sudo systemctl status docker
You want active (running).
Optional: run Docker without sudo
sudo usermod -aG docker $USER
Then log out of SSH and log back in. Group membership only applies on a new session. After that, docker and docker compose work without sudo.
Do not skip the reconnect. newgrp docker only fixes the current shell.
Anyone in the docker group can become root on the box. Only add accounts you trust. Prefer SSH keys: Secure SSH with key-based authentication and disable password login.
A first Compose file
Create a directory and a compose.yaml:
mkdir -p ~/docker-demo
cd ~/docker-demo
services:
web:
image: nginx:latest
ports:
- "80:80"
restart: unless-stopped
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: change-me
volumes:
- db_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
db_data:
The database has no ports: line, so Postgres is only reachable from other containers on this Compose network, not from the internet. Change change-me before you store anything real.
Start it:
docker compose up -d
Watch logs:
docker compose logs -f
Stop and remove the containers (the named volume stays):
docker compose down
Add -v only when you intend to delete the volume and the data in it.
Publish ports on the VPS
A ports: mapping such as "80:80" listens on the VPS IPv4. UFW still has to allow that traffic. On our VPS you run UFW yourself. See Set up a UFW firewall on Ubuntu.
For a public website:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Always allow SSH (port 22) before you enable UFW. If a rule locks you out, open the console on the VPS service in the portal.
Do not publish a database port (5432, 3306) to the whole internet. If another machine must connect, pin the source IPv4 in UFW instead of ports: "5432:5432" plus a wide allow.
Point the domain at this VPS IPv4 in the portal under Domains → the domain → DNS. AtlasDNS is the default. See Point your domain at your hosting. For TLS on the host, use Get a Free SSL Certificate with Certbot, or terminate TLS in a reverse-proxy container.
Everyday commands
- Images:
docker pull nginx:latestbefore you recreate a service. - Status:
docker compose ps - Logs:
docker compose logs -f web - Restart one service:
docker compose up -d web - Disk:
docker system df, thendocker image pruneanddocker container prunefor unused objects.docker system prune -aalso deletes unused images. Read the prompt. - Data: keep databases and uploads in named volumes or a bind mount. Files written only inside the container filesystem disappear when the container is removed.
Smaller VPS plans fill RAM quickly with several containers. Add overflow with Add Swap Space to Your VPS and watch usage with Monitor Server Resources.
Keep the host patched: Enable Automatic Security Updates. That updates Ubuntu or Debian packages, not the images you pulled. Rebuild or docker pull those yourself.
If something goes wrong
Cannot connect to the Docker daemon
sudo systemctl start docker
sudo systemctl status docker
If you dropped sudo after adding the docker group, log out and SSH in again.
permission denied while talking to the socket
You are not in the docker group yet, or this login started before usermod. Run the group command again, then reconnect.
apt cannot find docker-ce
You used the Ubuntu repo on Debian, or the other way around. Remove /etc/apt/sources.list.d/docker.list, add the matching block from above, then sudo apt update.
The site is not reachable after compose up
- Confirm the container is up:
docker compose ps - Confirm it is listening:
sudo ss -tlnp - Confirm UFW:
sudo ufw status verbose - Confirm the IPv4 you are hitting is the one on the VPS in the portal
- Confirm the domain A record, if you are using a name
You cannot SSH after opening UFW
Open the console on the VPS service in the portal, then:
sudo ufw allow 22/tcp
sudo ufw status verbose
Still stuck? Open a support ticket. Tell us the VPS service, the IPv4, the OS, and the command or error you saw. Do not send the password in the ticket.
What to do next
- First login and a sudo user: First steps on a new VPS
- Host firewall: Set up a UFW firewall on Ubuntu
- TLS: Get a Free SSL Certificate with Certbot
- A reverse proxy on the host instead of publishing every container port: Install Nginx on Ubuntu/Debian and Create an Nginx Server Block
Need a VPS first? See VPS.
Unsure about a step? Open a support ticket and we will walk through it with you.