Deploy Docker To Digitalocean

Deploy Docker To Digitalocean

Reading time1 min
#Cloud#DevOps#Containers#Docker#DigitalOcean#Droplets

Streamlining Production: Deploying Docker Containers on DigitalOcean Droplets for Scalable Apps

Avoid unnecessary overhead. Not every application needs Kubernetes. For startups, small teams, or situations demanding simplicity and price predictability, Docker on DigitalOcean Droplets remains a direct, highly controllable approach.

A quick review of why:

  • Immediate access to raw Linux hosts (no managed cluster).
  • Costing starts as low as $5/month per droplet, billed hourly or monthly.
  • Docker containers enable app-level portability and build reproducibility.
  • Operational complexity is minimal: direct SSH, direct logs, simple networking.

Experienced teams use this pattern to ship services rapidly, bootstrap MVPs, or operate low-maintenance prod workloads.


Provision a DigitalOcean Droplet

Provisioning via the DigitalOcean CLI (doctl) or dashboard is straightforward. Example via UI:

  1. Image: Ubuntu 22.04 LTS (tested, receives regular security updates).
  2. Plan: For a typical web app, s-1vcpu-1gb ($5/mo) is workable; jump to s-2vcpu-2gb if expecting CI-driven load or more containers.
  3. Region: Minimize latency—NYC3 or FRA1 common picks.
  4. Authentication: Always upload your SSH public key. Password access is slow and discouraged.
  5. Hostname: Name according to your fleet’s convention (api-prod-01, etc).
  6. Click Create Droplet.
  7. Note assigned IPv4 address.

Gotcha: By default, root login is enabled. Should be disabled later for production hardening.


SSH In and Install Docker

Minimum tested versions: Docker 20.10.x, Ubuntu 22.04. Confirm current latest; upgrade if needed.

Connect:

ssh root@<droplet_ip>

Update system and install dependencies:

apt update && apt upgrade -y
apt install -y apt-transport-https ca-certificates curl gnupg lsb-release

Install Docker’s official GPG key and repo (backports safer than Ubuntu’s default):

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker Engine and CLI:

apt update
apt install -y docker-ce docker-ce-cli containerd.io

Enable and start the daemon:

systemctl enable --now docker

Check install:

docker --version  # e.g. Docker version 24.0.5, build 24.0.5-0ubuntu1~22.04.1

Non-obvious tip: Add a non-root user to the docker group instead of running everything as root. For production, configure SSH to disable root login once your user is ready.


Containerizing Your Application

Assume a Node.js project for illustration, though the steps translate easily to Python, Go, or static binaries.

Example Dockerfile:

FROM node:18.17-alpine AS base

WORKDIR /srv/app

COPY package*.json ./
RUN npm ci --omit=dev

COPY . .

EXPOSE 3000
CMD ["node", "index.js"]

Why npm ci and --omit=dev? Faster, deterministic installs in prod images.

Build and test locally:

docker build -t acme-node-app:1.0.0 .
docker run --rm -it -p 3000:3000 acme-node-app:1.0.0

Before pushing, fix .dockerignore to prevent uploading big files (e.g. node_modules/, .git/).


Push to a Registry

For simplicity, demonstrate with Docker Hub. Alternatives: GHCR, private registries.

  1. Tag for push:
    docker tag acme-node-app:1.0.0 mydockerhub/acme-node-app:1.0.0
    
  2. Login:
    docker login
    
  3. Push:
    docker push mydockerhub/acme-node-app:1.0.0
    

Known issue: Docker Hub’s free tier rate-limits unauthenticated pulls. Configure auth or use your org’s registry for critical workloads.


Deploy: Pull and Run on Droplet

Back on the droplet:

docker pull mydockerhub/acme-node-app:1.0.0

docker run -d \
  --name=acme-app \
  --restart unless-stopped \
  -p 80:3000 \
  mydockerhub/acme-node-app:1.0.0
  • --restart unless-stopped: Service-style autostart.
  • -p 80:3000: Maps container port to droplet port 80.

Check container health:

docker ps
docker logs acme-app

If port 80 is occupied (Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use), diagnose with ss -tlnp.


Hardening: Basic Firewall and Updates

Enable UFW:

ufw allow OpenSSH
ufw allow 80/tcp
ufw --force enable
ufw status

Note: UFW rules persist reboots. For HTTPS, also allow 443/tcp. For additional hardening, consider fail2ban and restrict SSH to your office IP.

Update Docker and system on a regular schedule:

apt update && apt upgrade -y
docker --version

Scaling and Extending

A single droplet can typically push a Node.js/Go service to 500–1000 req/sec before network or CPU bottlenecks. Scale horizontally by imaging droplets or scripting with Terraform/Ansible. DigitalOcean Load Balancers slot in front of droplets—note the $12/mo starting price.

For stateless apps, DNS-based cutover between droplets is trivial:

      +---------------+         +--------------------+
      | Load Balancer +---80/443+ droplet-01 (app)   |
      +---------------+         +--------------------+
                 |               + droplet-02 (app)  |
                 |               + ...               |
             Users

Beware upgrade coordination and persistent state—there’s no orchestrator here to handle rolling restarts.


TL;DR Table

FeatureDroplets + DockerKubernetes (for comparison)
Setup time<10 minutes1+ hours
Pricing transparencyFixed per-dropletVariable (per-node, + mgmt)
ScalingManual but simpleAutomated, more knobs
Deployment complexityLowModerate to high
App portabilityHigh via DockerHigh

Non-obvious Tip

DigitalOcean offers prebuilt “Docker” one-click images—but regular Ubuntu + manual Docker installation gives you more control, completeness, and transparency over package versions and security updates.

Missed perfection: No built-in blue/green deployment. For that, integrate a load balancer with health checks, or script the cutover via DNS.


References


Questions or edge cases not addressed here? Audit your firewall config and container restart policy before deploying at scale.