• Indonesian
  • English
  • Docker VPS Setup: Production-Ready Complete Guide 2026

    Kecepatan:
    ⏱ 9 min read

    How to Set Up Docker on a VPS: Complete Step-by-Step Guide for Production

    Difficulty: Intermediate
    Last Updated: August 2026
    Tested On: Ubuntu 24.04 LTS, Rocky Linux 9, Docker Engine 27.x, Docker Compose v2

    Skip the small talk. You need containers running on a VPS, you need them stable, and you don’t have all day. This is the exact path I use on fresh servers — tested on Ubuntu 24.04 and Rocky Linux 9 — from a bare OS to a container stack that survives a reboot. Follow the order. It matters more than you think.

    Think of it like moving into a new apartment with pre-packed boxes. Every app ships with everything it needs inside its own box. Unpack, plug in, done. No more “works on my machine” drama. That’s what we’re building here.

    Now, the “why” — because if you’re here, you’ve probably hit the classic wall. Your app runs fine in dev, then you deploy to the VPS and it breaks. Different PHP version. Missing extension. Wrong folder permissions. A library that changed behavior silently between environments. Debugging that on a production box under load is miserable, and it burns hours you simply don’t have. Containerizing the app removes that entire class of problems, because the image you test locally is the exact same image that runs on the server. That consistency alone justifies the setup time, and it’s precisely why teams keep moving workloads to containers even on small single-VPS setups.

    The second reason is dependency hell — I see it in real tickets constantly. A Python service pins thirty pip packages to specific versions. A PHP app on the same box needs its own runtime and extensions. A database wants dedicated resource limits. On bare metal, all of that fights over one OS. Containers give you isolation instead: each service lives in its own world with its own OS layer, dependencies, and config. Two apps needing different PHP versions on one VPS? No problem at all.

    But let’s be honest before you start: containers are not magic. They share the host kernel, so a sloppy image or a container with a memory leak can still take your VPS down. You need resource limits, log rotation, and proper restart policies. That’s exactly what the second half of this guide covers. Installing Docker takes five minutes — running it safely takes the whole guide. Don’t skip the hardening and troubleshooting sections. I’ve cleaned up after enough “just pulled an image and forgot about it” disasters to know the difference.

    What You Need Before Starting

    • A VPS with at least 2GB RAM. 1GB works for light stacks, but you’ll fight for memory.
    • A 64-bit Linux OS: Ubuntu 22.04/24.04, Debian 12, or Rocky/AlmaLinux 9.
    • Root access or a sudo user.
    • Your VPS public IP handy, for testing container access.

    If the box isn’t hardened yet, check the SSH hardening guide first. Root login over SSH with password auth is basically an open invitation for botnets.

    Step-by-Step Docker Setup on a VPS

    1. Update the System

    sudo apt update && sudo apt upgrade -y
    

    On RHEL-family systems:

    sudo dnf update -y
    

    2. Install Docker Engine

    Use Docker’s official repository. Don’t use the distro package — it lags behind. And absolutely do not pipe random install scripts from the internet into your shell. Ubuntu/Debian, in order:

    sudo apt install -y ca-certificates curl
    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 > /dev/null
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    

    Rocky/Alma:

    sudo dnf -y install dnf-plugins-core
    sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    sudo systemctl enable --now docker
    

    Note: docker-ce-cli, containerd.io, buildx, and the compose plugin aren’t optional extras. They’re part of the stack. Install the whole set, not just docker-ce, or some features will silently not work.

    3. Add Your User to the docker Group

    sudo usermod -aG docker $USER
    

    Log out and back in (or run newgrp docker) so the group takes effect. Verify with groups — you should see docker in the list.

    Security note: docker group membership equals root access to the host. A member can mount the root filesystem and escape into the host as root. Only add users you fully trust. On a single-admin box this is fine; on multi-user servers, think twice.

    4. Verify the Install

    docker --version
    docker compose version
    sudo systemctl status docker
    

    Expected output, roughly:

    Docker version 27.4.1, build 9c5847f
    Docker Compose version v2.31.0
    ● docker.service - Docker Application Container Engine
         Loaded: loaded (...; enabled; preset: enabled)
         Active: active (running) since ...
    

    If it’s not running, sudo systemctl start docker and check again. That fixes it nine times out of ten.

    5. Run Your First Container

    docker run hello-world
    

    You’ll get the classic “Hello from Docker!” message. Then run something actually useful — Nginx on port 8080 so it doesn’t collide with anything already on port 80:

    docker run -d --name nginx-test -p 8080:80 nginx:alpine
    

    Test with curl http://IP_VPS:8080. Welcome page? Done. That’s a working Docker setup on your VPS, and honestly the fastest I’ve ever gone from zero to serving traffic on a fresh box.

    docker vps production setup first container running

    6. Set Up Docker Compose for Multi-Container Stacks

    mkdir -p ~/app/html && cd ~/app
    nano docker-compose.yml
    

    Minimal compose file:

    services:
      web:
        image: nginx:alpine
        container_name: web-server
        restart: unless-stopped
        ports:
          - '8081:80'
        volumes:
          - ./html:/usr/share/nginx/html
    
    docker compose up -d
    

    That restart: unless-stopped line is what keeps the container alive across host reboots unless you stop it manually. Non-negotiable for anything touching production.

    7. Make Containers Survive a Reboot

    No restart policy means a host reboot kills your containers permanently. Fix existing containers:

    docker update --restart unless-stopped nginx-test
    

    Or set it at run time:

    docker run -d --restart unless-stopped --name app-web -p 8082:80 nginx:alpine
    

    Policy reference:

    Policy Behavior Use When
    no Never restarts Testing only
    on-failure Restarts on error exit One-shot jobs
    always Always restarts, incl. daemon start Services that must never stop
    unless-stopped Restarts unless you stopped it manually Safest default for production

    Also make sure the daemon itself starts on boot: sudo systemctl enable docker.

    docker restart policy for production vps

    Essential Docker Commands

    These are the commands I run daily. Memorize them slowly, they’ll stick:

    Command What It Does
    docker ps List running containers
    docker ps -a List all containers, including stopped
    docker images List local images
    docker pull name Fetch an image from a registry
    docker run -d -p 80:80 name Start a container detached
    docker exec -it name bash Get a shell inside a container
    docker logs name View container logs
    docker stop / start / restart Control container lifecycle
    docker system df Show disk usage for images, containers, volumes
    docker inspect name Dump low-level container details

    Production Hardening for Docker on a VPS

    Install is step one. Running it safely is step two. These are the limits I set on every production container:

    • Set memory and CPU limits: docker run -m 512m --cpus 1 .... A runaway container can drain host RAM and take everything down with it.
    • Enable log rotation: without it, container logs grow forever and fill the disk. Set max-size: 10m and max-file: 3 in the logging driver config or in Compose.
    • Don’t run as root inside the container: use user in the image or --user at runtime.
    • Pin image versions: nginx:1.27-alpine, not a moving latest tag in production.
    • Keep images updated: rebuild or re-pull on a schedule; old images carry old CVEs.

    This pairs well with the VPS monitoring with Netdata guide — you want to see memory and disk trends before they bite you, not after.

    Troubleshooting Common Docker Issues on a VPS

    Symptom Cause Fix
    Can’t connect to the Docker daemon User not in docker group, or daemon down Check systemctl status docker; re-login after usermod
    Port already in use Another service holds the port ss -tulpn to find the holder; change the port mapping
    Container exits immediately App crashes on start, or wrong CMD docker logs name — the answer is always there
    Permission denied User missing from docker group Add the user, re-login
    Container killed by OOM Host RAM exhausted dmesg | tail, add memory limits, or add RAM
    Disk full Images and volumes piling up docker system df, prune what’s unused
    WARNING — Careful with docker system prune: docker system prune -a removes ALL images not used by running containers. Keep a backup of your Dockerfiles and compose files before pruning. When unsure, use docker container prune — that only removes stopped containers.

    FAQ

    Q: What’s the difference between a Docker container and a VM?

    A VM carries a full OS with its own kernel — heavy and resource-hungry. A container shares the host kernel and carries only the app and its dependencies, so it’s far lighter and boots in seconds. The trade-off: containers can’t run a different OS family than the host.

    Q: Is 1GB RAM enough for Docker on a VPS?

    For a light stack, yes — Nginx plus a small database fits. The catch is discipline: set memory limits on every container, or one hungry service will eat the host RAM. 2GB is noticeably more comfortable, and I’d start there for anything beyond experiments.

    Q: Is Docker safe for production servers?

    Yes, when configured properly. Non-negotiable items: don’t run containers as root, only use images you trust, set restart policies and resource limits, keep the engine and images updated. The danger is almost never Docker itself — it’s the sloppy way it gets deployed.

    Q: Dockerfile or docker-compose.yml — what’s the difference?

    A Dockerfile is the recipe for building one image — the instructions for installing your app. docker-compose.yml is the recipe for running a set of containers together — services, ports, volumes, environment. They usually work as a pair: Dockerfile builds, compose runs.

    Q: How do I update an image that’s already running?

    Pull the new image, stop the old container, and start it again with the new image. With Compose: docker compose pull then docker compose up -d. Check docker logs after the update, and back up anything stored in volumes first — updates that touch state deserve extra caution.

    Author: Syslog Solutions — NOC & Server Management Team. We handle 500+ servers daily, from shared hosting to enterprise dedicated infrastructure.

    That’s the whole path — install, run, harden, troubleshoot. Try it on a fresh VPS in order, and resist the urge to skip the hardening section. If you want to keep going down the rabbit hole, the Nginx tuning on low-RAM VPS guide is a solid next read for squeezing performance out of the same box. Done.