
If you just got a new VPS or are looking for a cleaner, more manageable way to run multiple applications on a single server, Docker is the tool you need to know. This guide takes you from understanding what Docker is all the way to installing it on Ubuntu and running your first real application.
What Is Docker?
Docker is a platform for developing, shipping, and running applications inside containers — self-contained units that package everything an application needs: code, runtime, libraries, and configuration. Containers run consistently regardless of the underlying server environment.
Containers vs. Virtual Machines (VMs)
The two are often confused, but they work in fundamentally different ways.
- Virtual Machines: Emulate full hardware, require a complete guest OS for each instance, consume significant RAM and CPU, and take minutes to start.
- Containers: Share the host OS kernel, carry only application-level dependencies, are extremely lightweight, and start in seconds.
A useful analogy: if a VM is a standalone house with its own plumbing and wiring, a container is a flat in an apartment building — it has its own private space, but shares the building's infrastructure (the kernel).
Key takeaway: Docker containers use 5–10x fewer resources than VMs, start faster, and are far easier to deploy. They are ideal for VPS environments where RAM is at a premium.
Why Docker Is Popular on VPS
Docker has become a go-to tool for VPS users for several compelling reasons.
- Isolation: Each application runs in its own container. You can run PHP 7.4 and PHP 8.2 side by side on the same server without conflicts.
- Portability: Build once, run anywhere. Move a container from your laptop to a VPS without reconfiguration.
- Precise version control: Pin the exact version of every dependency. No more "it works on my machine" surprises.
- Easy rollbacks: If an update breaks something, switching back to the previous image takes one command.
- Resource efficiency: Run multiple services on a 1 GB RAM VPS without adding hardware.
- Docker Hub: Tens of thousands of ready-made images — WordPress, MySQL, Nginx, Node.js, Redis, and more — available with a single pull.
Requirements Before Installing Docker
Make sure your VPS meets these requirements before proceeding.
- OS: Ubuntu 20.04 LTS or Ubuntu 22.04 LTS (recommended), or Debian 11/12
- RAM: At least 1 GB (2 GB+ recommended if running multiple containers)
- Disk: At least 5 GB of free space
- Access: root or a user with sudo privileges
- Internet: The VPS must be able to reach the internet to download Docker
Connect to your VPS via SSH first. If you need help with that, see the SSH Connection Guide.
Installing Docker on Ubuntu
The recommended approach is to install from Docker's official repository, which always provides the latest stable version.
Step 1: Update the system and install dependencies
apt update && apt upgrade -y
apt install -y ca-certificates curl gnupg lsb-releaseStep 2: Add Docker's GPG key and repository
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
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" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt updateStep 3: Install Docker Engine
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginStep 4: Verify the installation
docker --version
# Expected: Docker version 26.x.x, build xxxxxxx
docker run hello-world
# Expected: Hello from Docker!Step 5 (optional): Run Docker without sudo
If you work as a non-root user, add that user to the docker group.
usermod -aG docker $USER
# Log out and back in for the change to take effectEssential Docker Commands
With Docker installed, here are the commands you will reach for most often.
docker pull — download an image
docker pull nginx # Latest Nginx image
docker pull nginx:1.25 # Specific version
docker pull ubuntu:22.04 # Ubuntu 22.04 base imagedocker run — start a container
docker run nginx # Run Nginx (foreground)
docker run -d nginx # Run in background (detached)
docker run -d -p 80:80 --name web nginx # Map port 80, name the container "web"
docker run -d -p 8080:80 nginx # Map host port 8080 to container port 80docker ps — list running containers
docker ps # Show running containers
docker ps -a # Show all containers including stopped onesdocker stop and docker rm — stop and remove
docker stop web # Stop the container named "web"
docker stop abc123 # Stop by container ID
docker rm web # Remove a stopped container
docker rm -f web # Force-remove even if runningOther useful commands
docker images # List all local images
docker rmi nginx # Remove an image
docker logs web # View container logs
docker exec -it web bash # Open a shell inside a running containerWhat Is Docker Compose and How to Install It
Docker Compose lets you define and run multi-container applications using a single docker-compose.yml file. Instead of typing long docker run commands for each service, you describe the entire stack in one file and bring it up with one command.
If you installed Docker using the steps above (including docker-compose-plugin), Compose is already available.
docker compose version
# Docker Compose version v2.x.xNote: Docker Compose v2 uses docker compose (with a space). The older v1 used docker-compose (with a hyphen). This guide uses v2.
Example: Running WordPress + MySQL with Docker Compose
Here is a working example that launches a full WordPress site backed by MySQL — no manual Apache or PHP installation required.
Create a project directory and compose file
mkdir ~/wordpress && cd ~/wordpress
nano docker-compose.ymlContents of docker-compose.yml
services:
db:
image: mysql:8.0
restart: always
environment:
MYSQL_ROOT_PASSWORD: your_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wpuser
MYSQL_PASSWORD: your_wp_password
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:latest
restart: always
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: your_wp_password
volumes:
- wp_data:/var/www/html
depends_on:
- db
volumes:
db_data:
wp_data:Start the WordPress stack
docker compose up -d
# Docker pulls the images and creates both containers automatically
docker compose ps
# Verify both services are running
# Open your browser to http://YOUR_VPS_IP:8080
# You will see the WordPress setup wizardCommon Docker Compose commands
docker compose up -d # Start all services in the background
docker compose down # Stop and remove all containers
docker compose down -v # Stop + delete volumes (data will be lost!)
docker compose logs -f # Tail logs in real time
docker compose restart # Restart all services
docker compose ps # Show service statusDocker Networking and Volumes: Fundamentals You Must Understand
Once you start running multiple containers on a VPS, two concepts become critical: Docker networking (how containers talk to each other) and Docker volumes (how data persists). By default, containers are stateless — all data inside a container disappears the moment it is removed.
Docker Networks
Docker ships with three main network types.
- bridge (default): Containers in the same group communicate over a private internal network. Best for multi-container setups on a single server.
- host: The container shares the host's network stack directly with no NAT. Useful for performance-critical apps that need minimal latency.
- none: No network access at all. For isolated batch processing jobs.
When you use Docker Compose, it automatically creates a custom bridge network for your project. Containers in the same Compose file can reach each other by service name — for example, the WordPress container can connect to MySQL simply using the hostname db.
# Create a custom network
docker network create mynetwork
# Run a container attached to that network
docker run -d --name app --network mynetwork nginx
# List all networks
docker network ls
# Inspect a network
docker network inspect mynetworkDocker Volumes: Keeping Data Alive
A Docker volume is a storage area managed by Docker that lives outside the container filesystem. Data in a volume survives container removal and recreation — making volumes essential for databases, user-uploaded files, and critical configuration.
# Create a volume
docker volume create mydata
# List all volumes
docker volume ls
# Mount a volume when running a container
docker run -d -v mydata:/var/lib/mysql mysql:8.0
# Remove a volume (warning: data is permanently deleted)
docker volume rm mydata
# Remove all unused volumes
docker volume pruneGolden rule: Every piece of important data — databases, uploaded files, configuration — must live in a Docker volume. Never store it inside the container; the container is ephemeral and will be recreated during updates or restarts.
Managing a Multi-Container Stack on VPS with Docker Compose
In real VPS deployments, you will almost always run several containers together — a web server, database, cache, and reverse proxy at minimum. Below is a production-ready example stack.
Example: Nginx + PHP-FPM + MySQL + Redis
This stack suits modern PHP applications that need high performance and Redis-based caching.
services:
nginx:
image: nginx:1.25-alpine
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./app:/var/www/html
- ./ssl:/etc/ssl/certs
depends_on:
- php
php:
image: php:8.3-fpm-alpine
restart: always
volumes:
- ./app:/var/www/html
depends_on:
- mysql
- redis
mysql:
image: mysql:8.0
restart: always
environment:
MYSQL_ROOT_PASSWORD: strong_root_pw_here
MYSQL_DATABASE: appdb
MYSQL_USER: appuser
MYSQL_PASSWORD: strong_app_pw_here
volumes:
- db_data:/var/lib/mysql
ports:
- "127.0.0.1:3306:3306"
redis:
image: redis:7-alpine
restart: always
volumes:
- redis_data:/data
ports:
- "127.0.0.1:6379:6379"
volumes:
db_data:
redis_data:Note that MySQL and Redis bind their ports to 127.0.0.1 only — accessible from the VPS itself but not from the public internet. This is an important security best practice.
Starting and inspecting the stack
# Start all services
docker compose up -d
# Check the status of every service
docker compose ps
# Follow logs in real time
docker compose logs -f
# Restart a misbehaving service
docker compose restart php
# Pull the latest images and redeploy
docker compose pull && docker compose up -dBacking Up and Restoring Docker Data on VPS
Docker volumes are far safer than storing data inside containers, but you still need a solid backup strategy. Volume data lives on the VPS disk — if the VPS itself fails, the data is gone too.
Backup a database from a running container
# Back up a specific MySQL database
docker exec mysql_container mysqldump -u root -p'strong_root_pw_here' appdb > backup_$(date +%Y%m%d).sql
# Back up all databases
docker exec mysql_container mysqldump -u root -p'strong_root_pw_here' --all-databases > all_backup.sql
# Restore a database
docker exec -i mysql_container mysql -u root -p'strong_root_pw_here' appdb < backup_20260608.sqlBackup an entire Docker volume
# Back up a volume using a temporary Alpine container
docker run --rm \
-v db_data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/db_data_backup.tar.gz -C /source .
# Restore a volume from a backup archive
docker run --rm \
-v db_data:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/db_data_backup.tar.gz -C /targetAutomated daily backup with cron
Add a cron job to the VPS to run database backups automatically every day.
# Run: crontab -e, then add this line
# Back up daily at 2 AM, keep 7 days of history
0 2 * * * docker exec mysql_container mysqldump -u root -p'PWD' appdb > /backups/db_$(date +\%Y\%m\%d).sql && find /backups -name "db_*.sql" -mtime +7 -deleteBest practice: A good backup strategy stores copies in multiple locations — on the VPS, downloaded to cloud storage (e.g., Google Drive), or on a separate server. A backup that only lives on the same machine as the data it is protecting is not true redundancy.
Docker vs. Direct Installation on VPS
Many people wonder whether to use Docker or simply install Apache, PHP, and MySQL directly. Here is an honest comparison.
Bare-metal installation
- Easier initial setup for beginners
- Marginally better raw performance (no container overhead)
- Upgrading software can break the system if dependencies clash
- Running multiple PHP versions simultaneously is complex
- Moving to a new server requires full manual reconfiguration
Using Docker
- Complete isolation between applications
- Upgrade or downgrade by pulling a new image
- Migrate to a new server with just a
docker-compose.ymlfile - Backup and restore via Docker Volumes is straightforward
- Run complex stacks (WordPress + Redis + Nginx) with a single command
- Requires an upfront investment in learning Docker concepts
Recommendation: If you plan to run multiple applications on one VPS or deploy frequently, Docker pays off quickly. If you only need a single WordPress site, a traditional LAMP stack is still a perfectly valid choice.
Security Tips for Docker on VPS
- Avoid exposing ports unnecessarily. For databases, bind to localhost:
127.0.0.1:3306:3306instead of3306:3306. - Always change the default passwords in
docker-compose.ymlbefore starting services. - Keep Docker images updated with
docker compose pullfollowed bydocker compose up -d. - Store persistent data in Docker Volumes, not inside the container — containers are ephemeral and data is lost when they are removed.
- Configure a firewall to block unused ports. See the VPS security hardening guide for details.
Ready to Run Docker on a VPS?
AsiaGB Linux VPS starts from 500 THB/month — 1 GB RAM and up, full root access, Docker-ready out of the box. Data centers in Thailand and Singapore.
View VPS Plans