If you've ever heard "it works on my machine" or spent hours debugging environment differences between development and production, Docker for web applications solves that problem completely. Docker packages your app with its exact dependencies, configuration, and runtime into a portable container that runs identically everywhere — your laptop, a staging server, or production VPS.
This guide walks you through containerizing a real web application, from first Dockerfile to production deployment.
What Docker Actually Does
Docker creates isolated, lightweight environments called containers. Unlike virtual machines, containers share the host OS kernel, making them fast to start (seconds, not minutes) and efficient with resources.
Think of it this way: a VM is like renting an entire apartment building. A container is like renting just the apartment you need — same isolation, fraction of the overhead.
Without Docker:
Your App → Different OS → Different PHP version → Different config → 🔥 Bugs
With Docker:
Your App → Same container everywhere → ✅ Works identically
Installing Docker
Ubuntu/Debian
# Remove old versions
sudo apt remove docker docker-engine docker.io containerd runc
# Install Docker
curl -fsSL https://get.docker.com | sudo sh
# Add your user to the docker group (no sudo needed for docker commands)
sudo usermod -aG docker $USER
# Verify installation
docker --version
docker compose version
macOS
Download Docker Desktop from docker.com — it includes everything you need.
Docker for Web Applications: Your First Dockerfile
A Dockerfile is a recipe that tells Docker how to build your container image. Here's a practical example for a Node.js application:
# Use official Node.js image as base
FROM node:20-alpine
# Set working directory inside the container
WORKDIR /app
# Copy dependency files first (better caching)
COPY package*.json ./
# Install production dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Expose the port your app listens on
EXPOSE 3000
# Start the application
CMD ["node", "server.js"]
Build and run it:
# Build the image
docker build -t myapp .
# Run the container
docker run -d -p 3000:3000 --name myapp myapp
Your app is now running in a container, accessible at http://localhost:3000.
Dockerizing Common Web Stacks
PHP/Laravel Application
FROM php:8.3-fpm-alpine
RUN docker-php-ext-install pdo pdo_mysql opcache
WORKDIR /var/www/html
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader
COPY . .
RUN php artisan config:cache && \
php artisan route:cache && \
php artisan view:cache
EXPOSE 9000
CMD ["php-fpm"]
Python/Django Application
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
WordPress with Custom Theme
FROM wordpress:6.7-php8.3-fpm
COPY wp-content/themes/mytheme /var/www/html/wp-content/themes/mytheme
COPY wp-content/plugins/myplugin /var/www/html/wp-content/plugins/myplugin
Docker Compose: Multi-Container Applications
Most web applications need more than one container — your app, a database, maybe Redis for caching. Docker Compose orchestrates multiple containers together.
docker-compose.yml for a Typical Web App
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@db:5432/myapp
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
volumes:
- pgdata:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
restart: unless-stopped
volumes:
pgdata:
Start everything with one command:
docker compose up -d
All four services start together, connected on an internal Docker network where they can reach each other by service name (db, redis, app).
Dockerfile Best Practices
Use Multi-Stage Builds
Reduce your final image size by separating build and runtime stages:
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Production
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
This produces a much smaller image because build tools and dev dependencies stay in the builder stage.
Use .dockerignore
Just like .gitignore, a .dockerignore file prevents unnecessary files from being copied into your image:
node_modules
.git
.env
*.md
.github
tests
coverage
Don't Run as Root
# Create a non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
Layer Caching
Docker caches each layer. Put things that change frequently (your code) after things that change rarely (dependencies):
# Dependencies change less often — cached
COPY package*.json ./
RUN npm ci
# Code changes often — rebuilds from here
COPY . .
Deploying Docker Containers to a VPS
Once your app is containerized, deploying to a VPS becomes straightforward. If you've been following our guide on staging environment setup, Docker makes staging even easier — identical containers across all environments.
Step 1: Push Your Image to a Registry
# Tag your image
docker tag myapp registry.example.com/myapp:latest
# Push to Docker Hub or a private registry
docker push registry.example.com/myapp:latest
Step 2: Pull and Run on Your VPS
# On your VPS
docker pull registry.example.com/myapp:latest
docker compose up -d
Step 3: Set Up Automated Deployments
Combine Docker with CI/CD for push-to-deploy workflows:
# GitHub Actions example
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push Docker image
run: |
docker build -t myapp:latest .
docker save myapp:latest | ssh user@vps 'docker load'
- name: Restart on VPS
run: ssh user@vps 'cd /app && docker compose up -d'
Monitoring Docker Containers
Keep your containers healthy in production:
# Check running containers
docker ps
# View logs
docker logs myapp --tail 100 -f
# Resource usage
docker stats
# Restart a container
docker compose restart app
When your app needs to scale horizontally, Docker makes it simple — spin up more container instances behind a load balancer.
FAQ
Is Docker overkill for a simple website?
For a static site or basic WordPress blog, Docker adds unnecessary complexity. Docker shines when you need reproducible environments, run multiple services, or deploy across different servers consistently.
Does Docker replace my web hosting?
No. Docker runs on top of your hosting. You still need a VPS or server to run your containers. Docker simplifies what runs on that server and how you deploy updates.
How much memory does Docker use?
Docker itself uses minimal resources. Each container adds the memory your application actually needs — typically 50-200MB for a web app. A 2GB VPS can comfortably run 3-5 containers.
Can I use Docker with shared hosting?
No. Docker requires root access and a Linux kernel, which shared hosting doesn't provide. You need a VPS or dedicated server.
Containerize Your Stack with DeployBase
Docker for web applications eliminates deployment headaches by ensuring your app runs identically in development, staging, and production. Once containerized, you can deploy with confidence knowing there are no environment surprises.
At DeployBase, our VPS plans come with Docker pre-available, full root access, and NVMe SSD storage for fast container builds and pulls. Starting at $5/month with 24/7 support, you get the infrastructure your containerized applications need.
Get your VPS at DeployBase → — deploy containers with confidence.



