Docker on VPS: Getting Started Guide

Getting started with Docker on a VPS. Install Docker, build images, use docker-compose, and deploy WordPress with MySQL.

Disclosure: This page contains affiliate links. If you purchase a VPS or service through my links, I may earn a commission at no extra cost to you. I only recommend products I have personally used or thoroughly evaluated. This supports the site and allows me to keep creating honest, in-depth content.

Docker on VPS: Getting Started Guide

I remember the first time I tried to deploy a web application on a bare VPS. I spent an entire weekend wrestling with dependency conflicts, broken PHP versions, and a MySQL install that refused to cooperate with everything else on the server. When I finally got it running, I was terrified to touch anything because the whole setup felt like a house of cards. Then I discovered Docker, and honestly, it changed how I think about server management entirely.

If you have a VPS and you have been doing things the old-fashioned way — installing packages directly on the host, managing services by hand, praying that an update does not break something unrelated — this guide is for you. I am going to walk you through Docker from scratch: what it is, why it matters, how to install it on Ubuntu, and how to use it for real-world deployments. By the end, you will have a working WordPress site running in Docker containers on your own server.

If you are still shopping for a server, or if you need a solid foundation to follow along, I recommend InterServer VPS. Their standard plan gives you enough resources to run multiple Docker containers comfortably, and the price-lock guarantee means your bill will not creep up over time. I have used them for several Docker-based projects and they have been reliable.

What Is Docker, Exactly?

Docker is a platform that lets you package an application and all of its dependencies into a standardized unit called a container. Think of a container as a lightweight, isolated environment that has everything your application needs to run: the code, the runtime, the libraries, the system tools, and the configuration files.

This is different from a virtual machine. A VM emulates an entire operating system, complete with its own kernel. A Docker container shares the host machine’s kernel and isolates only the application layer. That makes containers dramatically lighter. You can spin up a container in seconds, not minutes, and you can run dozens of them on a modest VPS without breaking a sweat.

The practical upside is consistency. A container that works on your laptop will work identically on your VPS. No more “it works on my machine” problems. No more dependency conflicts between applications. Each container is its own little world.

Why Use Docker on a VPS?

You might be wondering why you should bother with Docker when you could just install things directly on your VPS. Fair question. Here is what pushed me to make the switch.

Isolation. Every application runs in its own container with its own dependencies. Your WordPress site needs PHP 8.1? Your other project needs PHP 8.3? No problem. They do not interfere with each other.

Reproducibility. Your entire application stack is defined in a file. You can rebuild it identically on any server. Migrating to a new VPS becomes trivial — copy your Docker files, run a command, and you are done.

Easy cleanup. If you want to remove an application, you just delete the container. There are no leftover config files scattered across your filesystem, no orphaned packages, no mystery processes still running.

Resource efficiency. Containers are lean. Compared to running multiple VMs, you can fit significantly more services on a single VPS when you use Docker.

Simplified deployment. Instead of writing long setup scripts or remembering a sequence of manual steps, you define everything in a Dockerfile or a docker-compose file and run it with a single command.

For anyone managing a VPS — especially if you are running multiple sites or services — Docker is not just a convenience. It is a fundamentally better way to work. Check out our best VPS hosting roundup if you are looking for a provider that handles Docker workloads well.

Installing Docker on Ubuntu

Let us get Docker installed. I am using Ubuntu 24.04 LTS here, which is the most common choice for VPS deployments in 2026. If you are on a different version, the process is nearly identical. You will need root access or a user with sudo privileges. If you need a refresher on working with the command line, see our Linux commands for VPS guide.

First, update your package index and install the prerequisites:

sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release

Add Docker’s official GPG key:

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

Set up the Docker repository:

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

Now install Docker Engine, the CLI, containerd, and the Compose plugin:

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Verify that Docker is running:

sudo docker run hello-world

You should see a message confirming that Docker is installed correctly. If you want to run Docker commands without typing sudo every time, add your user to the docker group:

sudo usermod -aG docker $USER

Log out and back in for the group change to take effect. From this point forward, I will write commands without sudo assuming you have done this.

Essential Docker Commands

Before we build anything, let us get comfortable with the basic commands. These are the ones you will use daily.

Pull an image from Docker Hub (the public registry of pre-built images):

docker pull nginx

Run a container from an image:

docker run -d --name my-nginx -p 80:80 nginx

The -d flag runs it in the background (detached mode). The --name flag gives it a human-readable name. The -p 80:80 flag maps port 80 on the host to port 80 in the container.

List running containers:

docker ps

List all containers (including stopped ones):

docker ps -a

Stop a container:

docker stop my-nginx

Start a stopped container:

docker start my-nginx

Remove a container (must be stopped first):

docker rm my-nginx

View container logs:

docker logs my-nginx

Execute a command inside a running container (useful for debugging):

docker exec -it my-nginx /bin/bash

List downloaded images:

docker images

Remove an image:

docker rmi nginx

That is the core vocabulary. Once these commands feel natural, you are ready to build your own images.

Creating a Dockerfile

A Dockerfile is a text file that contains instructions for building a Docker image. It is essentially a recipe: start with a base image, add your code, install dependencies, configure settings, and define how the container should run.

Here is a simple example. Let us say you have a static website and you want to serve it with Nginx. Create a file called Dockerfile (no extension) in your project directory:

FROM nginx:alpine

COPY ./site-content /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

Line by line: FROM nginx:alpine starts with the official Nginx image based on Alpine Linux (a minimal distribution, so the image is small). COPY takes your local site-content folder and places it where Nginx expects to find web files. EXPOSE 80 documents that the container listens on port 80. CMD defines the default command that runs when the container starts.

Build the image:

docker build -t my-website .

The -t flag tags the image with a name. The . tells Docker to look for the Dockerfile in the current directory.

Run it:

docker run -d --name my-site -p 8080:80 my-website

Your static site is now live on port 8080. That is the basic workflow: write a Dockerfile, build an image, run a container.

Docker Compose: WordPress + MySQL Example

In practice, most applications involve multiple services working together. A WordPress site needs both a web server with PHP and a MySQL database. Managing these as separate docker run commands gets messy fast. That is where Docker Compose comes in.

Docker Compose lets you define a multi-container application in a single YAML file. You describe all your services, their configurations, their networks, and their storage volumes in one place, then bring everything up with a single command.

Create a file called docker-compose.yml in a new project directory:

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: your_strong_root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wp_user
      MYSQL_PASSWORD: your_strong_db_password
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - wp_network

  wordpress:
    image: wordpress:latest
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wp_user
      WORDPRESS_DB_PASSWORD: your_strong_db_password
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp_data:/var/www/html
    networks:
      - wp_network

volumes:
  db_data:
  wp_data:

networks:
  wp_network:
    driver: bridge

Let me walk through what this does. We define two services: db (MySQL) and wordpress. Each has its own image, environment variables for configuration, and a named volume for persistent storage. The depends_on directive tells Docker to start the database before WordPress. Both services are on the same internal network so they can communicate, but only WordPress exposes a port to the outside world.

The restart: unless-stopped policy means the containers will automatically restart if they crash or if the server reboots, unless you explicitly stop them. This is important for production deployments.

Bring everything up:

docker compose up -d

That is it. Visit your server’s IP address on port 8080 and you will see the WordPress installation wizard. The entire stack — web server, PHP, MySQL — is running in isolated containers, defined in a single file that you can version control and replicate anywhere.

To stop everything:

docker compose down

To stop everything and also remove the stored data (be careful with this):

docker compose down -v

This is where Docker really shines on a VPS. You can define entire application stacks declaratively and manage them with simple commands. If you are running multiple projects, each one gets its own docker-compose.yml in its own directory, completely independent of the others.

Managing Containers in Production

Running containers on your VPS is straightforward. Keeping them running reliably takes a little more thought. Here are the habits I have settled into.

Use named volumes for persistent data. If you do not mount a volume, all data inside a container is lost when the container is removed. The docker-compose.yml example above already does this correctly. Your database files and WordPress uploads survive container restarts and rebuilds.

Keep images updated. Pull fresh images regularly to get security patches:

docker compose pull
docker compose up -d

This pulls the latest versions of all images defined in your compose file and recreates any containers that have changed.

Monitor resource usage. Docker provides a built-in command for this:

docker stats

This gives you a live view of CPU, memory, network, and disk I/O for each container. If a container is hogging resources, you can set limits in your compose file:

services:
  wordpress:
    image: wordpress:latest
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "0.5"

Clean up unused resources. Over time, old images, stopped containers, and unused volumes accumulate and eat disk space. Run this periodically:

docker system prune -a

This removes all stopped containers, unused networks, dangling images, and build cache. Add --volumes if you also want to remove unused volumes, but be absolutely sure you do not need the data first.

Check logs when something goes wrong:

docker compose logs -f

The -f flag follows the log output in real time. You can also check a specific service: docker compose logs -f wordpress.

A VPS from InterServer with 4 GB of RAM can comfortably run several Docker Compose stacks simultaneously. Their unmetered bandwidth also means you do not need to worry about container image pulls eating into a transfer quota.

Basic Docker Security on a VPS

Docker adds convenience, but it also introduces a new surface area for security concerns. Here are the essentials you should address right away.

Do not run containers as root unless necessary. Many official images already run their main process as a non-root user, but you should verify. In your Dockerfile, you can explicitly set the user:

FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
COPY . /app
CMD ["node", "server.js"]

Do not expose ports you do not need. In the WordPress example, only port 8080 is exposed to the host. The MySQL port (3306) is only accessible from within the Docker network. This is intentional. Never expose database ports to the public internet.

Use environment variables carefully. Hardcoding passwords in a docker-compose.yml file that gets committed to a Git repository is a common mistake. For production, use a .env file:

# .env
MYSQL_ROOT_PASSWORD=your_strong_root_password
MYSQL_PASSWORD=your_strong_db_password

Then reference the variables in your compose file:

environment:
  MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
  MYSQL_PASSWORD: ${MYSQL_PASSWORD}

Make sure the .env file is in your .gitignore and has restrictive file permissions (chmod 600 .env).

Keep Docker itself updated. Docker security patches are released regularly. Update the engine along with the rest of your system packages:

sudo apt update && sudo apt upgrade -y

Limit container capabilities. By default, Docker containers have a reduced set of Linux capabilities, but you can restrict them further. In your compose file:

services:
  my-app:
    image: my-app:latest
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE

This drops all capabilities and only adds back the specific one the application needs (in this case, the ability to bind to privileged ports).

Use a firewall. Docker manipulates iptables directly, which can bypass UFW rules. This catches a lot of people off guard. If you are using UFW, you need to configure Docker to respect it by editing /etc/docker/daemon.json:

{
  "iptables": false
}

Then restart Docker and manage your port exposure carefully through your compose files and UFW rules. Be aware that setting "iptables": false means Docker will not automatically set up NAT rules, so you may need to handle routing manually. Test thoroughly after making this change.

Scan images for vulnerabilities. Docker Scout is built into Docker Desktop and the CLI. Run it against your images:

docker scout cves my-website

This reports known vulnerabilities in the image’s packages so you can address them before deployment.

Frequently Asked Questions

How much RAM does my VPS need to run Docker?

Docker itself uses very little RAM. The containers are what consume memory. For a single WordPress + MySQL stack, 1 GB of RAM is the bare minimum and 2 GB is more comfortable. If you plan to run multiple stacks or heavier applications, aim for 4 GB or more. InterServer VPS plans let you scale resources as your needs grow.

Is Docker the same as a virtual machine?

No. A virtual machine emulates an entire operating system including the kernel. A Docker container shares the host kernel and only isolates the application layer. Containers are much lighter, start faster, and use fewer resources. However, VMs provide stronger isolation since each one has its own kernel.

Can I use Docker on any VPS operating system?

Docker runs natively on Linux, which is the standard choice for VPS deployments. It works on all major distributions including Ubuntu, Debian, CentOS, Rocky Linux, and Fedora. Ubuntu is the most commonly used and best-documented option, which is why I used it in this guide.

Will Docker slow down my VPS?

The overhead of Docker itself is negligible. Containers run at near-native performance because they share the host kernel directly. The only overhead is a thin abstraction layer for filesystem and network isolation. In practical terms, you will not notice a difference compared to running applications directly on the host.

How do I back up Docker containers?

You do not back up the containers themselves — they are disposable. You back up the data volumes and your Docker Compose files. For the WordPress example, you would back up the db_data and wp_data volumes, plus your docker-compose.yml and .env files. You can use docker run --rm -v db_data:/data -v /backup:/backup alpine tar czf /backup/db_backup.tar.gz /data to create a compressed archive of a volume.

What is the difference between docker compose and docker-compose?

The hyphenated docker-compose is the older standalone tool (V1), which was a separate Python application. The space-separated docker compose is the newer Compose V2 plugin that is integrated directly into the Docker CLI. V2 is the current standard and what gets installed with modern Docker packages. The commands are functionally equivalent for most use cases, but V2 is faster and actively maintained.

Can I run Docker containers on a 1-core VPS?

Yes. Containers are processes, not virtual machines, so they do not each need a dedicated CPU core. A single-core VPS can run several lightweight containers without issues. Performance depends on the workload inside the containers, not the number of containers. CPU-intensive applications will benefit from more cores, but a standard WordPress site on a 1-core VPS runs fine.

Where to Go from Here

You now have a working mental model of Docker and the practical skills to deploy containerized applications on a VPS. The WordPress + MySQL stack is a real, production-viable setup — add a reverse proxy like Nginx or Traefik in front of it with SSL termination via Let’s Encrypt, and you have a complete hosting environment.

If you are looking for next steps, explore multi-site setups with Traefik as a reverse proxy, automated backups with cron jobs, and container orchestration with Docker Swarm for redundancy. Each of these builds naturally on the foundation covered here.

The key insight I want to leave you with is this: Docker does not add complexity to VPS management. It replaces fragile, manual complexity with structured, repeatable complexity that you can reason about and version control. Once you start thinking in containers, you will not want to go back.

If you are ready to get started, grab a VPS from InterServer and follow this guide from the top. You can have a fully containerized WordPress deployment running in under thirty minutes.

Leave a Reply

Your email address will not be published. Required fields are marked *