Streamlined Docker Deployment: DigitalOcean Droplets for Production-Grade Containers
Modern teams need deployment strategies that don’t introduce unnecessary complexity. DigitalOcean droplets, coupled with Docker, provide a straightforward, cost-conscious backbone for small-scale production workloads or staging environments. This guide emphasizes the real-world practices: less theory, more sustained operation.
When Container Management Should Stay Simple
Orchestration platforms like Kubernetes shine at scale but introduce overhead. For single-service apps or lightweight projects, DigitalOcean droplets with Docker hit a pragmatic balance—root-level access, tight resource control, and rapid recovery via droplet snapshots. The result: lean deployments, minimal latency.
Baselines
Before proceeding, ensure the following:
- DigitalOcean account with billing set up
- SSH keypair registered (see “Security Shortcuts” below)
- CLI access (macOS/Linux:
ssh
; Windows: WSL or PuTTY; or try DigitalOcean’s web console) - Docker CLI installed locally (for building and pushing images; not strictly required on the droplet)
1. Provision the Droplet
Parameter | Recommendation |
---|---|
Image | Ubuntu 22.04 LTS |
Plan | 1 vCPU, 1GB RAM ($5/mo) |
Data Center | Choose per user geo |
SSH Key | Always use; avoid passwords |
From the control panel, select Create > Droplet. Assign your SSH key. After provisioning, a public IPv4 will be shown—this is your jump point.
2. SSH Access: First Principles
Default root login is enabled on new droplets.
ssh root@<DROPLET_IP>
If you see Permission denied (publickey)
, troubleshoot with ssh -vvv root@<DROPLET_IP>
. Misconfigured keys or disabled agent forwarding are typical causes.
Gotcha: DigitalOcean assigns regular root shell; harden with a non-root user post-setup if intended for long-living environments.
3. Docker Installation (Ubuntu 22.04)
Install latest Docker packages—avoid snap and OS repos (they lag).
apt-get update && apt-get install -y \
ca-certificates curl gnupg lsb-release
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
| tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update && apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Check status:
docker info | grep 'Server Version'
Known issue: If
systemctl status docker
showsfailed
, check/var/log/syslog
for overlay filesystem errors. Sometimes, resizing the droplet resolves initialization hangs.
4. Sanity Check: Hello World
Confirm a functioning Docker daemon.
docker run --rm hello-world
Expected output (truncated):
Hello from Docker!
This message shows that your installation appears to be working correctly.
If you see:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock
check that the daemon is running (systemctl restart docker
).
5. Ship Your Own Containers
Assume an example Node.js application:
Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Note: npm ci --omit=dev
skips devDependencies—vital for minimizing image size in production.
Build and publish from your workstation (Docker Hub example):
docker build -t yourrepo/myapp:2024.06.12 .
docker push yourrepo/myapp:2024.06.12
Tag with date/version for traceable deployments. Avoid latest
except in test loops.
6. Retrieve & Run on Droplet
On the droplet, pull the image:
docker pull yourrepo/myapp:2024.06.12
Deploy:
docker run -d --name myapp -p 80:3000 --restart=unless-stopped yourrepo/myapp:2024.06.12
Access at http://<DROPLET_IP>
. If port 80 is in use, substitute above (e.g., -p 8080:3000
).
Trade-off: Mapping container’s app port to 80 bypasses the need for nginx/traefik, but limits flexibility for multi-app hosting.
7. Compose: Multiple Containers Without Orchestration Bloat
For stateful/multi-service apps, docker-compose
supports consistent, easy setups.
docker-compose.yml:
version: '3.8'
services:
web:
image: yourrepo/myapp:2024.06.12
ports: ["80:3000"]
restart: unless-stopped
environment:
NODE_ENV: production
db:
image: postgres:15.4-alpine
restart: unless-stopped
environment:
POSTGRES_PASSWORD: example_pw
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Start all:
docker compose up -d
Remember: Volumes mounted only exist on this droplet. Data persistence is not “cloud native” here unless bound to external storage or periodically snapshotted.
8. Security & Maintenance
- Firewall: Harden ingress rules. Shortest path:
ufw allow ssh
ufw allow http
ufw allow https
ufw enable
- User Management: For long-term hosts, add a sudo user; disable root SSH:
adduser deployer
usermod -aG docker deployer
- Logs/Monitoring:
docker logs myapp
for quick check; deploydocker events
or integratepromtail
to centralize logs for production. - Image Refresh: Schedule a service (
cron
, GitHub Actions CI) to pull fresh images—even on single-server setups, drift leads to issues.
Non-Obvious: Zero Downtime Container Restarts (No Orchestrator)
Performing live deployments:
docker pull yourrepo/myapp:2024.06.13
docker run -d --name myapp-v2 -p 8080:3000 --restart=unless-stopped yourrepo/myapp:2024.06.13
# Wait for healthcheck, then swap iptables/nginx mapping, or adjust DNS if using internal LB.
docker stop myapp && docker rm myapp
docker rename myapp-v2 myapp
This approach minimizes downtime without full orchestration.
Side Notes
- Snapshots: Use DigitalOcean’s droplet snapshots for rollback; there is a lag of several minutes.
- Secrets management: Avoid embedding secrets in images; pass as environment variables or mount via secrets volume (manual on single droplets).
- Persistent data: Leverage DigitalOcean Volumes if database durability is critical.
Conclusion
For projects where Kubernetes is excessive but manual deployment is too brittle, Docker with DigitalOcean droplets strikes a usable middle ground. With these real-world workflows, expect predictable deployments and simpler rollbacks—provided operational hygiene is maintained.
Alternatives: DigitalOcean App Platform abstracts even further but at the cost of less granular control.
On constrained budgets or when hands-on access is essential, this is a sensible, maintainable deployment baseline.
Questions on more advanced multi-node setups, HA proxies, or GitOps flows? Comments open.