hectoday
DocsCoursesChangelog GitHub
DocsCoursesChangelog GitHub

Access Required

Enter your access code to view courses.

Invalid code

← All courses Deploying Node.js Apps with Docker

Why Docker

  • The "Works on My Machine" Problem
  • Docker Concepts

Your First Dockerfile

  • Writing a Dockerfile
  • Multi-Stage Builds
  • The .dockerignore File

Running Containers

  • Running and Managing Containers
  • Environment Variables and Secrets
  • Health Checks

Multi-Container Apps

  • Docker Compose
  • Adding a Reverse Proxy
  • Persistent Data

Deploying to Production

  • Deploying to a VPS
  • HTTPS with Let's Encrypt
  • Zero-Downtime Deploys

CI/CD

  • Building Images in CI
  • Automated Deployment

Production Hardening

  • Container Security
  • Logging and Monitoring
  • Deployment Checklist and Capstone

Deploying to a VPS

The simplest production deployment

A VPS (Virtual Private Server) is a Linux machine in the cloud. You SSH into it, install Docker, pull your image, and run it. No Kubernetes. No AWS services. Just Docker on a server.

This is how most small-to-medium apps are deployed. It is simple, cheap ($5-20/month), and sufficient until you need horizontal scaling.

Get a VPS

Providers: DigitalOcean, Hetzner, Linode, Vultr. Create an Ubuntu 22.04+ server with at least 1 GB RAM.

You will receive an IP address and SSH credentials.

Install Docker on the server

# SSH into the server
ssh root@your-server-ip

# Install Docker (official method)
curl -fsSL https://get.docker.com | sh

# Verify
docker --version
docker compose version

# (Optional) Add your user to the docker group
# so you do not need sudo for every docker command
usermod -aG docker your-username

Push your image to a registry

You need the image in a registry so the server can pull it. Docker Hub is the simplest:

# On your local machine
# Log in to Docker Hub
docker login

# Tag your image for the registry
docker tag myapp yourusername/myapp:latest

# Push
docker push yourusername/myapp:latest

For private images, use GitHub Container Registry (ghcr.io) or a private Docker Hub repository.

Deploy

# On the server
# Pull the image
docker pull yourusername/myapp:latest

# Create the env file
nano .env.production
# Add your production environment variables

# Run
docker run -d \
  --name myapp \
  -p 80:3000 \
  --restart unless-stopped \
  --env-file .env.production \
  -v app-data:/data \
  yourusername/myapp:latest

Your app is live at http://your-server-ip.

Using Docker Compose on the server

For multi-container apps, copy the compose file to the server:

# On your local machine
scp docker-compose.yml root@your-server-ip:/app/
scp nginx.conf root@your-server-ip:/app/
scp .env.production root@your-server-ip:/app/

# On the server
cd /app
docker compose up -d

Updating the app

# On your local machine
docker build -t yourusername/myapp:latest .
docker push yourusername/myapp:latest

# On the server
docker pull yourusername/myapp:latest
docker compose up -d   # Recreates containers with the new image

Firewall

Configure the server’s firewall to only allow necessary ports. UFW (Uncomplicated Firewall) is Ubuntu’s built-in firewall tool. By default, a fresh server has all ports open — anyone can probe every port. UFW lets you whitelist specific ports and block everything else:

# UFW — Ubuntu's firewall
ufw allow 22/tcp    # SSH — so you can still connect to the server
ufw allow 80/tcp    # HTTP — for web traffic and Let's Encrypt verification
ufw allow 443/tcp   # HTTPS — for encrypted web traffic
ufw enable          # Activate the firewall (blocks all other ports)

After ufw enable, only ports 22, 80, and 443 are accessible from the internet. Your app container’s internal port (3000) is blocked — traffic must go through Nginx on port 80/443. This prevents anyone from bypassing the reverse proxy.

Exercises

Exercise 1: Set up a VPS (most providers offer $5/month plans or free trials). Install Docker.

Exercise 2: Push your image to Docker Hub. Pull and run it on the server. Access your app at the server’s IP.

Exercise 3: Set up the firewall. Verify that only ports 22, 80, and 443 are open.

Why deploy with docker pull instead of copying files with scp?

← Persistent Data HTTPS with Let's Encrypt →

© 2026 hectoday. All rights reserved.