To set up Docker on a VPS from scratch and deploy your first container on Ubuntu 22.04, you'll need a minimum of 1 GB RAM and 1 vCPU, and a full production stack with Traefik, automatic HTTPS, and reliable backups can be implemented in 30-40 minutes by following this step-by-step guide.
Docker has radically simplified application development, deployment, and management. It allows you to package applications with all their dependencies into isolated containers that run consistently across any machine. This article is your guide to the world of Docker on a Virtual Private Server (VPS) from Valebyte.com, from basic installation to advanced techniques for production environments, including automatic HTTPS, backups, and container updates.
Why Docker on a VPS is the Optimal Choice for Your Projects
Deploying applications on a VPS traditionally required manual environment setup, dependency installation, and version conflict resolution. Docker eliminates these complexities by offering a standardized approach to containerization. A VPS, in turn, provides an ideal platform for Docker, combining the flexibility of dedicated resources with affordability.
Flexibility and Resource Savings: How Docker Changes the Approach to Hosting
Docker containers are isolated from each other but share the host operating system's kernel. This results in significantly lower overhead compared to virtual machines, where each VM requires its own copy of the OS. On a single VPS, you can run dozens of different services, each in its own container, without worrying about dependency conflicts or excessive resource consumption.
For example, you can simultaneously host WordPress (PHP, Nginx, MySQL), Node.js APIs, Python scripts, and even your own VPN server, each in a separate container, using the same VPS. This significantly reduces infrastructure costs and simplifies scaling.
When Does a VPS with Docker Become the Ideal Solution?
Docker on a VPS is an ideal choice for:
- Developers who need a reproducible development environment and rapid deployment to production.
- Small and medium-sized business owners looking to host multiple internal or external services (CRM, ERP, corporate website) on a single machine with minimal costs.
- Self-hosting enthusiasts who want to run media servers (Plex, Jellyfin), home automation (Home Assistant), or other personal projects.
- Projects with microservice architecture, where each service is deployed in a separate container.
How to Install Docker on a VPS from Scratch
Getting started with Docker on your Valebyte.com VPS is surprisingly simple. We'll cover the installation process on the popular Ubuntu 22.04 LTS operating system, which is a common choice for servers.
Server Preparation and Docker Engine Installation
Before proceeding with the installation, ensure your VPS is updated. Connect to the server via SSH and execute the following commands:
sudo apt update
sudo apt upgrade -y
Now, let's install the necessary packages that allow apt to use repositories over HTTPS:
sudo apt install ca-certificates curl gnupg lsb-release -y
Add Docker's official GPG key:
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
Add the Docker repository to apt's source list:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Update the apt package list and install Docker Engine, Docker CLI, and Containerd:
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
To avoid using sudo every time you work with Docker, add your user to the docker group:
sudo usermod -aG docker $USER
newgrp docker # Apply group changes immediately, or reconnect via SSH
Verify that Docker is installed correctly by running a test container:
docker run hello-world
If you see the message "Hello from Docker!", the installation was successful.
Your First Docker Container: Hello World and Nginx
After successfully installing Docker, let's run something more useful than hello-world. For example, an Nginx web server. This only takes one command:
docker run --name my-nginx -p 80:80 -d nginx
--name my-nginx: Assigns the container the namemy-nginxfor easier management.-p 80:80: Maps host port 80 to container port 80. Your web server is now accessible via the VPS's IP address.-d: Runs the container in detached mode (background).nginx: The name of the Docker image to be downloaded and run.
Now, if you enter your VPS's IP address into your browser, you will see the standard Nginx welcome page.
To stop and remove the container:
docker stop my-nginx
docker rm my-nginx
This demonstrates the simplicity of deploying applications with Docker. But for more complex projects involving multiple services, we'll need Docker Compose.
Looking for a reliable server for your projects?
VPS from $10/month and dedicated servers from $9/month with NVMe, DDoS protection, and 24/7 support.
View offers →Managing Multiple Services with Docker Compose in Production
Most real-world applications require more than one container. For example, a web application might consist of a container for the web server (Nginx/Apache), a container for the application logic (PHP/Node.js/Python), and a container for the database (MySQL/PostgreSQL). Managing them individually with docker run commands becomes cumbersome. This is where Docker Compose comes in, allowing you to define and run multi-container applications using a single configuration file.
Creating docker-compose.yml: Structure and Key Parameters
The docker-compose.yml (or docker-compose.yaml) file describes your application's services, networks, and volumes. Let's create an example for WordPress with a MySQL database:
mkdir wordpress-app
cd wordpress-app
nano docker-compose.yml
Contents of the docker-compose.yml file:
version: '3.8'
services:
wordpress:
image: wordpress:latest
container_name: wordpress
restart: always
ports:
- "80:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: super_secret_password
WORDPRESS_DB_NAME: wordpress_db
volumes:
- wordpress_data:/var/www/html
networks:
- app-network
db:
image: mysql:8.0
container_name: mysql-db
restart: always
environment:
MYSQL_DATABASE: wordpress_db
MYSQL_USER: wordpress
MYSQL_PASSWORD: super_secret_password
MYSQL_ROOT_PASSWORD: another_super_secret_root_password
volumes:
- db_data:/var/lib/mysql
networks:
- app-network
volumes:
wordpress_data:
db_data:
networks:
app-network:
driver: bridge
In this file, we defined two services: wordpress and db. Each service has:
image: The Docker image to be used.container_name: A unique name for the container.restart: always: An important parameter for production, ensuring the container automatically restarts on failure or VPS reboot.ports: Port mapping (for WordPress).environment: Environment variables for configuring the application and database.volumes: Binding persistent data storage (volumes).networks: Assigning containers to a specific network.
To launch the application, just one command is needed in the directory containing docker-compose.yml:
docker compose up -d
The -d option runs all services in detached mode. WordPress will now be accessible via your VPS's IP address.
Local Networks and Persistent Storage (Volumes)
Networks: Docker Compose automatically creates its own network for your application by default. In our example, we explicitly defined the app-network. This allows containers to communicate with each other using their service names (e.g., wordpress can access the database via the hostname db), while isolating them from other Docker networks and the host system. Such separation is critical for security and organization.
Volumes: Data inside a container is ephemeral by default: all data is lost when the container is removed. Docker Volumes are used to persist data. In our example, wordpress_data and db_data are named volumes that Docker creates and manages. They are stored on the host system (usually in /var/lib/docker/volumes/) and remain untouched even after containers are removed. This ensures your WordPress and MySQL data is preserved when containers are updated or recreated.
To ensure data and configuration reliability, especially for critical services, automatic backups are recommended. For example, you can set up regular backups of all important files and configurations, similar to what is described in the article Automatic VPN Config Backup on VPS: Don't Rebuild From Scratch.
Setting Up a Production Environment: Traefik, HTTPS, and Resource Limits
In a production environment, direct port mapping (like -p 80:80) for every service quickly becomes unmanageable. Additionally, we need HTTPS for security. This is where reverse proxies like Traefik come in, automatically managing request routing and SSL/TLS certificates.
Automatic HTTPS with Traefik and Let's Encrypt
Traefik is a modern reverse proxy and load balancer that integrates seamlessly with Docker. It can automatically discover new containers, route traffic to them, and even obtain and renew SSL certificates from Let's Encrypt.
Create a new directory for Traefik and its configuration:
mkdir traefik-app
cd traefik-app
nano docker-compose.yml
Contents of docker-compose.yml for Traefik:
version: '3.8'
services:
traefik:
image: traefik:v2.10
container_name: traefik
restart: always
command:
- --api.insecure=true # For debugging only, use secured access in production
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --certificatesresolvers.myresolver.acme.tlschallenge=true
- --certificatesresolvers.myresolver.acme.email=your_email@example.com # Enter your email
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
ports:
- "80:80"
- "443:443"
- "8080:8080" # Traefik Dashboard (debugging only, secure or don't publish in production)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
networks:
- web
volumes:
letsencrypt:
networks:
web:
external: true
Create the external web network if it doesn't exist:
docker network create web
Start Traefik:
docker compose up -d
Now, modify your docker-compose.yml for WordPress to use Traefik. Remove the ports section from the wordpress service and add labels:
version: '3.8'
services:
wordpress:
image: wordpress:latest
container_name: wordpress
restart: always
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: super_secret_password
WORDPRESS_DB_NAME: wordpress_db
volumes:
- wordpress_data:/var/www/html
networks:
- app-network
- web # Add Traefik network
labels:
- "traefik.enable=true"
- "traefik.http.routers.wordpress.rule=Host(`your-domain.com`)" # Replace with your domain
- "traefik.http.routers.wordpress.entrypoints=websecure"
- "traefik.http.routers.wordpress.tls.certresolver=myresolver"
- "traefik.http.services.wordpress.loadbalancer.server.port=80"
- "traefik.http.routers.wordpress.middlewares=redirect-to-https@docker" # Optional: redirect HTTP to HTTPS
db:
image: mysql:8.0
container_name: mysql-db
restart: always
environment:
MYSQL_DATABASE: wordpress_db
MYSQL_USER: wordpress
MYSQL_PASSWORD: super_secret_password
MYSQL_ROOT_PASSWORD: another_super_secret_root_password
volumes:
- db_data:/var/lib/mysql
networks:
- app-network
# Important: No need to publish ports externally or use Traefik for the DB
volumes:
wordpress_data:
db_data:
networks:
app-network:
driver: bridge
web:
external: true # Indicate that the 'web' network already exists
Don't forget to configure the DNS record for your-domain.com to point to your VPS's IP address. After updating the docker-compose.yml for WordPress and starting it (docker compose up -d), Traefik will automatically discover WordPress, configure routing, and obtain a Let's Encrypt certificate. Your WordPress will now be accessible via HTTPS!
Container Resource Limits and Log Rotation
In production, it's crucial to control how many resources each container consumes so that one "hungry" service doesn't "choke" the entire VPS. Docker Compose allows you to set CPU and RAM limits:
services:
wordpress:
# ...
deploy:
resources:
limits:
cpus: '0.5' # 50% of one CPU core
memory: 512M # 512 MB RAM
reservations:
cpus: '0.25' # Reserve 25% of a CPU core
memory: 256M # Reserve 256 MB RAM
# ...
limits: Maximum resources the container can use.reservations: Guaranteed resources.
Log Rotation: Containers generate logs that can quickly fill up disk space. Configure log rotation in docker-compose.yml:
services:
wordpress:
# ...
logging:
driver: "json-file"
options:
max-size: "10m" # Maximum log file size 10 MB
max-file: "3" # Keep 3 latest files
This ensures Docker automatically removes old log files, preventing disk overflow.
Updating and Securing Docker Containers
Keeping your Docker containers up-to-date and secure is an ongoing process. It's important to have a strategy for updating images and following security best practices.
Automatic and Manual Docker Image Updates
Manual Update: To update a container to a new image version (e.g., wordpress:latest), you need to stop it, remove it, and then restart it:
docker compose pull # Download new images
docker compose down # Stop and remove old containers
docker compose up -d # Start new containers
This is safe because your data is stored in volumes and is not deleted.
Automatic Update: To automate this process in a production environment, you can use the Watchtower utility. Watchtower monitors Docker Hub (or other image registries) and, when a new image version appears, automatically downloads it, stops the old container, starts the new one, and removes the old image.
services:
watchtower:
image: containrrr/watchtower
container_name: watchtower
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 300 # Check for updates every 300 seconds (5 minutes)
# Add labels so Watchtower doesn't update itself if you don't want it to
labels:
- "com.centurylinklabs.watchtower.enable=false" # Disable Watchtower updates
networks:
- app-network # Or any network where your services are located
Be cautious with automatic updates for production services, as a new version might contain breaking changes. Often, manual or semi-automatic updates with prior testing are preferred.
If you manage complex systems like Xray-core, where updates require careful attention, a manual approach with compatibility checks will be preferable.
Docker Environment Security Basics on a VPS
Security is a critically important aspect when working with Docker in production:
- Do not expose ports externally unnecessarily: Use a reverse proxy (Traefik) for web services. Databases and internal APIs should not be accessible from the internet. In our WordPress example, the MySQL container has no exposed ports and is only accessible from within the Docker network.
- Use separate networks for databases: Create a dedicated network only for containers that need database access. This further isolates the database from the rest of the application.
- Principle of least privilege:
- Run containers as a non-privileged user inside the container (not
root). - Use minimal images (e.g., Alpine versions) that contain only essential components.
- Limit access to
/var/run/docker.sockonly to containers that genuinely need it (like Watchtower or Traefik).
- Run containers as a non-privileged user inside the container (not
- Regularly update Docker Engine and images: Vulnerabilities are constantly discovered, and timely updates patch them.
- Use a firewall: Configure a firewall on your VPS (e.g., UFW) to restrict inbound traffic to only necessary ports (SSH, HTTP/S, etc.).
Backing Up and Restoring Docker Volumes: Protecting Your Data
Data loss is one of the biggest risks. With Docker, all data that needs to be preserved resides in volumes. Therefore, backing up volumes is a key element of a production strategy.
Strategies for Creating Backups for Docker Volumes
The simplest way to back up a Docker Volume is to use a temporary container that mounts the desired volume and saves its contents to an archive.
Example of backing up the db_data volume:
docker run --rm --volumes-from mysql-db -v $(pwd):/backup ubuntu tar cvf /backup/mysql_db_backup_$(date +%F).tar /var/lib/mysql
--rm: Remove the temporary container after the command execution.--volumes-from mysql-db: Attach volumes from themysql-dbcontainer (in this case,db_data, which is attached to/var/lib/mysql).-v $(pwd):/backup: Mount the current host directory as/backupinside the temporary container.ubuntu: Use a minimal Ubuntu image to execute the command.tar cvf /backup/mysql_db_backup_$(date +%F).tar /var/lib/mysql: Create a tar archive of/var/lib/mysqlcontents and save it to/backup(i.e., to the current directory on the host).
Before backing up a database, it's recommended to stop the DB container or create a database dump using mysqldump to ensure data consistency.
docker exec mysql-db mysqldump -u wordpress -p'super_secret_password' wordpress_db > ./wordpress_db_backup_$(date +%F).sql
For automated backups, you can use Cron jobs on the host or specialized Docker backup containers that send archives to cloud storage.
Data Recovery and Migration to a New Server
Recovery: To restore a volume from an archive:
- Ensure the container using that volume is stopped.
- Create a new empty volume (or use an existing one).
- Use a temporary container to extract the archive into the desired volume:
docker run --rm --volumes-from mysql-db -v $(pwd):/backup ubuntu tar xvf /backup/mysql_db_backup_2023-10-27.tar -C / - Start your main container with the restored volume.
Migration to a new server: The process of migrating a Docker application to a new VPS includes:
- Installing Docker Engine and Docker Compose on the new server.
- Copying the
docker-compose.ymlfile and all volume backups to the new server. - Restoring volumes from backups on the new server.
- Starting the application with
docker compose up -d.
This process allows for easy transfer of even complex multi-container applications. For example, migrating specific configurations like 3x-ui will follow a very similar approach, as described in the article Backup and Migration of 3x-ui to Another VPS Without Losing Users.
How Much VPS Resources Do You Need for Docker Projects?
Choosing the right VPS configuration is critical for the performance and stability of your Docker applications. While Docker itself is efficient, the services running inside it still consume CPU, RAM, and disk space. Below is an approximate table of recommendations for selecting a VPS for various Docker usage scenarios.
For 50 concurrent web application users or several microservices, 4 vCPUs, 8 GB RAM, and an 80 GB NVMe disk are sufficient.
| Scenario / Load | vCPU | RAM (GB) | Disk (GB, Type) | Network Port | Estimated Valebyte.com Price ($/month, Oct 2023) |
|---|---|---|---|---|---|
| Personal Project / 1-2 Simple Services (Nginx, Blog, VPN) (up to 5 concurrent users) |
1-2 | 1-2 | 20-40 (SSD) | 1 Gbps | From $4.99 |
| Small Website / WordPress / Several Microservices (up to 20 concurrent users) |
2 | 2-4 | 40-60 (NVMe) | 1 Gbps | From $8.99 |
| Medium Website / E-commerce / Several APIs (up to 50 concurrent users) |
4 | 8 | 80-120 (NVMe) | 1 Gbps | From $15.99 |
| High-Load Project / Large DBs / CI/CD (up to 100+ concurrent users) |
6-8+ | 16-32+ | 200+ (NVMe) | 1-10 Gbps | From $29.99 |
Optimal VPS Selection for Various Docker Use Cases
When choosing a VPS for Docker, consider the following factors:
- Processor (vCPU): Most web applications are not very CPU-intensive unless there are intense computations. 2-4 vCPUs are sufficient for most medium-sized projects. High-load APIs or tasks requiring multi-threading will need more.
- RAM: This is often the most critical resource. Each container (and its application) consumes RAM. Databases, Java applications, Node.js servers can be memory-hungry. Start with 2 GB and increase as needed. For production servers with multiple services, 4-8 GB RAM is a good starting point.
- Storage:
- Type: For Docker, an NVMe disk is highly desirable. It provides significantly higher read/write speeds compared to regular SSDs, which is critical for database performance and fast container startup.
- Size: Besides your application data, Docker Engine itself takes up space (images, volumes, logs). A buffer of 20-30% free space is good practice.
- Network Port: For most web applications, 1 Gbps is sufficient. If you plan to host streaming services or work with large data volumes, consider a VPS with a wider channel.
VPS Configuration Recommendation Table for Docker Containers
As the table shows, even for serious projects, you can find a suitable VPS configuration at a reasonable price. The key is to monitor resource usage and scale promptly if the load increases.
Frequently Asked Questions
How much RAM do I need for Docker on a VPS?
For a basic Docker installation and running one or two simple containers, such as Nginx or a light blog, 1-2 GB of RAM is sufficient. If you plan to host WordPress with MySQL or several microservices, it's recommended to start with 4 GB of RAM. For more demanding systems with databases and numerous services, 8 GB of RAM or higher will be an optimal choice for stable operation.
Can Docker be used for production applications on a VPS?
Yes, Docker on a VPS is widely used for production applications. It provides isolation, scalability, and simplifies deployment. With proper configuration (Traefik for HTTPS, automatic volume backups, resource limiting, and regular updates), your VPS with Docker will become a reliable foundation for any production services, from small websites to complex APIs.
How do I secure Docker containers on a VPS?
To secure Docker containers on a VPS, you need to follow several rules. First, do not expose container ports directly to the internet without a reverse proxy like Traefik, which manages HTTPS. Second, use separate Docker networks for databases to isolate them from web services. Third, run containers as non-privileged users and regularly update images and the Docker Engine to patch known vulnerabilities.
What is Docker Compose and why is it needed?
Docker Compose — is a tool for defining and running multi-container Docker applications. It allows you to describe all services, networks, and volumes of your application in a single YAML file (docker-compose.yml). With a single command, docker compose up -d, you can launch the entire application infrastructure, which significantly simplifies the management of complex projects consisting of multiple interconnected containers, such as WordPress with a MySQL database.
Conclusion
Docker on a VPS is a powerful and flexible solution for deploying and managing applications, ideal for both personal projects and production environments. By following this step-by-step guide from installation and your first container to configuring Traefik with HTTPS, resource limiting, and reliable volume backups, you can create a stable and secure infrastructure. Choose a VPS with NVMe disks and sufficient RAM to ensure high performance for your Docker containers.
NVMe VPS with 60-second activation: full root access, 20+ locations, pay with card or crypto.
Choose a plan