Install Docker and docker compose on a VPS: Step by Step
Run on the server with one command (check the script contents below first):
curl -sSL https://cp.lv/scripts/ustanovit-docker-vps.sh | sudo bash…or with wget:
wget -qO- https://cp.lv/scripts/ustanovit-docker-vps.sh | sudo bashScript contents ustanovit-docker-vps.sh:
#!/usr/bin/env bash
set -e
export DEBIAN_FRONTEND=noninteractive
# 1. Remove old versions
sudo apt-get remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true
# 2. Official Docker repository
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 3. Install Docker Engine and plugins
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
# 4. Run without sudo (takes effect after a new SSH login)
sudo usermod -aG docker $USER
# 5. Cap container log size
sudo tee /etc/docker/daemon.json > /dev/null << 'EOF'
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
EOF
sudo systemctl restart docker
# 6. Verify
sudo docker run hello-world
docker compose version
echo "Docker is ready. Log in over SSH again to use it without sudo."
Docker packs an application and its dependencies into a container that behaves the same on any server. Below is how to install Docker Engine and the docker compose plugin from the official repository on Ubuntu 22.04/24.04. Do not use the docker.io package from the standard Ubuntu repository — it is often outdated.
Step 1. Remove old versions
sudo apt remove docker docker-engine docker.io containerd runc 2>/dev/null
sudo apt update
Step 2. Add the official Docker repository
sudo apt install ca-certificates curl gnupg -y
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Step 3. Install Docker Engine and the plugins
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin -y
Enable autostart and check that it works:
sudo systemctl enable --now docker
sudo docker run hello-world
If you see “Hello from Docker!”, the engine is running.
Step 4. Run Docker without sudo
Add your user to the docker group so you do not have to type sudo before every command:
sudo usermod -aG docker $USER
newgrp docker
docker ps
The group change takes effect after a new SSH session.
Step 5. Check docker compose
In modern Docker, compose is a subcommand rather than a separate binary:
docker compose version
Create a simple stack. The docker-compose.yml file:
services:
web:
image: nginx:alpine
ports:
- "8080:80"
restart: unless-stopped
volumes:
- ./site:/usr/share/nginx/html:ro
Start it and check:
mkdir site && echo "<h1>It works</h1>" > site/index.html
docker compose up -d
curl http://localhost:8080
Stop and remove the stack:
docker compose down
Everyday commands
| Task | Command |
|---|---|
| List containers | docker ps -a |
| Service logs | docker compose logs -f web |
| Update images | docker compose pull && docker compose up -d |
| Clean up junk | docker system prune -a |
| Disk usage | docker system df |
Updates and security
- Cap the log size so containers do not fill the disk. Open
/etc/docker/daemon.jsonin an editor:
sudo nano /etc/docker/daemon.json
File contents:
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
Or create the file with a single command — copy it and paste it into the console:
sudo tee /etc/docker/daemon.json > /dev/null << 'EOF'
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
EOF
After editing, run sudo systemctl restart docker.
- Do not publish database ports (
5432,3306) to the outside without a reason — keep them on the internal compose network. - Update images regularly: vulnerabilities usually live in outdated versions.
FAQ
What is the difference between docker-compose and docker compose?
The old docker-compose (with a hyphen) is the standalone Python binary v1 and is no longer supported. The new docker compose (plugin v2) ships with the engine and is the recommended one.
Does Docker need swap? On a server with little RAM, swap helps survive peaks during image builds. 1–2 GB of swap is usually enough.
How do I start containers automatically after a reboot?
Set restart: unless-stopped in the compose file and make sure the Docker service is enabled: systemctl is-enabled docker.
Docker filled the whole disk — how do I clean it?
docker system prune -a removes unused images, containers and networks. Volumes are removed with the --volumes flag (be careful with your data).
Docker likes a fast disk and spare memory for builds. Suitable configurations are on the VPS hosting page, and for containerised projects there is Docker VPS.