How to run Docker on a VPS
Docker packages apps into portable containers. Learn to install Docker and Compose on a VPS, run your first container, and deploy a multi-service app.
Docker packages an application and everything it needs into a portable container that runs the same way anywhere. On a VPS, Docker makes deployments clean and repeatable: no more "works on my machine," easy rollbacks, and multiple isolated apps on one server. Here's how to get running.
Step 1: Install Docker
On a fresh Ubuntu VPS, install Docker from the official repository:
sudo apt update
sudo apt install ca-certificates curl -y
sudo install -m 0755 -d /etc/apt/keyrings
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 $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
Verify:
sudo docker run hello-world
Step 2: Run Docker without sudo
Add your user to the docker group so you don't type sudo every time:
sudo usermod -aG docker $USER
Log out and back in for it to take effect.
Step 3: Run your first real container
Let's run an Nginx web server in seconds:
docker run -d --name web -p 80:80 nginx
The -d runs it in the background, -p 80:80 maps the container's port 80 to the server's port 80. Visit http://YOUR_SERVER_IP and you'll see Nginx. Manage it with:
docker ps
docker logs web
docker stop web
docker rm web
Step 4: Persist data with volumes
Containers are ephemeral โ data inside them vanishes when they're removed. Volumes keep data outside the container:
docker run -d --name db -v db-data:/var/lib/postgresql/data -e POSTGRES_PASSWORD=secret postgres
The named volume db-data survives container restarts and recreations.
Step 5: Multi-service apps with Compose
Real apps have several parts โ a web app, a database, a cache. Docker Compose describes them all in one file. Create docker-compose.yml:
services:
app:
image: my-app:latest
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:secret@db:5432/mydb
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: secret
POSTGRES_DB: mydb
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
Bring the whole stack up:
docker compose up -d
Compose creates a private network so app reaches db by name. Tear it down with docker compose down.
Step 6: Put HTTPS in front
Don't expose app ports directly. Run a reverse proxy โ Caddy in a container gives you automatic HTTPS, or use Nginx on the host. A minimal Caddy service in Compose:
caddy:
image: caddy:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
Step 7: Firewall
Only open what you actually serve:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Housekeeping
Docker images and volumes accumulate. Reclaim space periodically:
docker system prune -a
Be careful โ that removes unused images and stopped containers.
Why Docker suits a VPS
You get root, a full Linux kernel, and dedicated resources โ exactly what Docker wants. A Nxeon NVMe VPS pulls images fast and runs containers with real, guaranteed CPU and RAM, unlike constrained shared hosts where Docker isn't even allowed. Package your app once and deploy it identically every time.