Deploy Docker To Vps

Deploy Docker To Vps

Reading time1 min
#Docker#VPS#DevOps#DockerDeployment#Containerization#Linux

Deploying Docker on a VPS: A Practical Engineering Walkthrough

Abstracting away all container management to cloud platforms isn’t always optimal. In regulated environments, or just where cost and granular infrastructure control matter, rolling your own Docker deployment on a VPS is still the pragmatic move. Explored below: setting up Docker engine (≥24.0), streaming containers, persistent data strategies, and common pain points—without the abstraction layer.


Why Push Containers to a VPS?

  • Environment Parity: Achieve tight alignment between development and production—same OS, kernel version, and network layout.
  • Performance Profiling: No noisy neighbors unless self-inflicted. Latency and IOPS are predictable relative to hardware, not cloud hypervisor scheduling.
  • Cost Model: $6/month for a 2GB RAM, 1 vCPU instance from the usual suspects (DigitalOcean, Vultr, Hetzner Cloud), vs. managed container price hikes post-free-tier.
  • Root-Level Troubleshooting: Strace, tcpdump, cgroups inspection—available without support tickets.
  • Escape Hatches: Container snapshots, raw backup, or bare-metal migration is viable.

Setup: From Provider Console to Shell

Provider: Any VPS host with KVM or similar (avoid oversold OpenVZ for namespaces!).

Provision:

  • Image: Ubuntu Server 22.04 LTS (jammy)
  • Minimum: 1 vCPU, 2GB RAM, 20GB disk (SSD preferred)
  • SSH key injection (skip password auth if possible):
# Replace $IP and $USER appropriately
ssh $USER@$IP

Immediate patch:

sudo apt update && sudo apt upgrade -y

Gotcha: Some kernel upgrades require a reboot. Double-check uname -a and apt list --upgradable | grep linux-image.

Lock privilege escalation:

adduser dockerops
usermod -aG sudo dockerops
su - dockerops

Docker Engine: Installation & Verification

Docker’s convenience installer script suffices for most VPS use. For airgapped or audited environments, use the official repo and verify GPG signatures.

curl -fsSL https://get.docker.com | sudo sh
docker --version  # e.g., Docker version 24.0.7, build cb74dfc

Permission edge-case: Add user to docker group, then refresh session context.

sudo usermod -aG docker $USER
# Re-login or: exec su -l $USER

If docker ps throws “permission denied”, group membership hasn't propagated.


Sanity Test: Minimal Container Launch

docker run --rm hello-world

Should see:

Hello from Docker!
This message shows that your installation appears to be working correctly.

If instead:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock
—verify service is running:
sudo systemctl status docker


Deploying a Real Container: Nginx Web

The basics matter. Here’s Nginx served stateless.

docker run -d --name mynginx -p 80:80 nginx:1.25-alpine

Access via curl http://<your_vps_ip> or browser. Default welcome page confirms working publish of port 80.

To persist configuration or serve static assets, mount local volumes (see below).


Key Runtime Operations

CommandAction
docker psList running containers
docker ps -aAll containers (stopped/running)
docker logs mynginxPrint logs for named container
docker stop mynginxGraceful shutdown
docker rm mynginxDestroy (after stopping)
docker imagesList available images

Known issue: Zombie containers—cleanup with docker system prune -f occasionally to reclaim orphaned volumes/layers.


Data Persistence: Bind-Mount Volumes

Container ephemeral storage isn’t enough; use host-mounted directories.

mkdir -p ~/webroot/html
echo "<h2>VPS-backed Nginx</h2>" > ~/webroot/html/index.html

docker run -d \
  --name mynginx \
  -p 80:80 \
  -v ~/webroot/html:/usr/share/nginx/html:ro \
  nginx:1.25-alpine

Now curl http://<your_vps_ip> serves your custom content.
Note: File mode mismatches on bind mounts cause 403 errors. Chown as needed.


Orchestrating Multi-Container Apps with Compose

Example use case: Nginx + static HTML.

  1. Install compose plugin (Debian-based):
    sudo apt install docker-compose-plugin -y
    
  2. docker-compose.yml:
    version: '3.8'
    services:
      web:
        image: nginx:1.25-alpine
        ports:
          - "80:80"
        volumes:
          - ./html:/usr/share/nginx/html:ro
    
  3. Launch:
    mkdir ~/compose-demo && cd ~/compose-demo
    mkdir html && echo 'Testing Compose' > html/index.html
    docker compose up -d
    

Failure mode:
If you see ERROR: for web Cannot start service web: Ports are not available, ensure nothing else is bound to 80. Check via sudo lsof -i :80.


Security, Resource, and Recovery Practices

  • Patch: Regularly update engine/plugins: sudo apt upgrade docker-ce docker-compose-plugin
  • Monitor: Live stats: docker stats or host-level with htop, iftop, iotop
  • Restrict: Harden with UFW or firewalld. Allow only required ingress:
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw enable
    
  • Restart policies:
    For production:
    docker run ... --restart unless-stopped ...
    
  • Backup strategy:
    Script volume/tar snapshots, or use rsync/RESTIC to remote storage.
    Gotcha: Live-mounts may yield inconsistent db backups. Use DB-native dumps for data containers.

Troubleshooting: Real-World Faults

  • Out of Memory Kills (OOM):
    dmesg will show msgs like Killed process 1234 (nginx) total-vm:39328kB.
    Solution: monitor with docker stats; raise swap or adjust container memory limits with -m.

  • Disk Full:
    docker: Error response from daemon: no space left on device
    Clean up unused volumes/images:
    docker system df and docker system prune -af


Further Steps

Consider moving toward Docker Compose for complex stacks, failover-ready storage with bind mounts, or even managed orchestration (K3s, Nomad). For declarative setups, check out Ansible automation.

Tip: For fully-scripted deployments, integrating with CI/CD tools (GitHub Actions, GitLab CI) cuts manual setup overhead and improves rollback plans.


Reference: Docker Official Documentation
Open Issues: Some VPS providers apply aggressive conntrack tuning, causing dropped connections on bursty TCP workloads—monitor /proc/net/nf_conntrack if relevant.

This walkthrough isn’t exhaustive, but it hits the operational cornerstones for Docker-on-VPS in a real-world scenario. Any specifics out of scope? Drop to the Docker issues or seek tailored advice from infrastructure peers.