Skip to content

Dockerfile for Static Website with Caddy Webserver: Modern, Secure, and Simple Deployment

This guide will walk you through creating a robust Dockerfile using Caddy as the web server, exploring best practices, configuration techniques, and practical implementation strategies for containerizing static websites.

Why Caddy? Understanding Its Unique Advantages

Caddy stands out among web servers for several compelling reasons:

  1. Automatic HTTPS: Caddy automatically provisions and renews SSL/TLS certificates using Let's Encrypt, eliminating complex manual configuration.
  2. Simplicity: Its configuration is more readable and concise compared to traditional web servers like Nginx or Apache.
  3. Modern Protocol Support: Built-in support for HTTP/2 and HTTP/3 out of the box.
  4. Security by Default: Implements best security practices natively.

Designing the Dockerfile for a Caddy-Powered Static Website

Let's create a comprehensive Dockerfile that demonstrates Caddy's strengths in static website deployment:

# Use official Caddy image as base
FROM caddy:2.7-alpine

# Set working directory
WORKDIR /app

# Copy website files
COPY ./website/ /app/

# Optional: Custom Caddyfile for advanced configuration
COPY Caddyfile /etc/caddy/Caddyfile

# Expose ports for HTTP and HTTPS
EXPOSE 80 443

# Default Caddy command
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

Dockerfile Breakdown

Base Image Selection

  • We use the official caddy:2.7-alpine image, which provides a minimal Alpine Linux-based Caddy installation.
  • Alpine ensures a lightweight, security-focused container with minimal overhead.

Working Directory

  • /app is set as the working directory for website files.
  • Provides a clear, organized location for static content.

File Copying

  • Copies entire website directory into the container.
  • Allows flexible placement of static assets.

Sample Caddyfile Configuration

{
    # Global options
    email your-email@example.com  # For Let's Encrypt registration
}

example.com {
    # Serve static files
    root * /app

    # Enable compression
    encode gzip

    # Security headers
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-XSS-Protection "1; mode=block"
        X-Frame-Options "DENY"
        Content-Security-Policy "default-src 'self'"
    }

    # File server configuration
    file_server
}

Configuration Insights

  1. Automatic HTTPS: Caddy handles SSL certificate management automatically.
  2. Performance Optimization: Gzip compression enabled.
  3. Security Headers: Implements robust security configurations.
  4. Simple Routing: Straightforward static file serving.

Multi-Stage Build for Enhanced Flexibility

For more complex static sites with build processes, implement a multi-stage build:

# Build Stage
FROM node:alpine AS builder

WORKDIR /build
COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

# Final Stage
FROM caddy:2.7-alpine

WORKDIR /app
COPY --from=builder /build/dist /app
COPY Caddyfile /etc/caddy/Caddyfile

EXPOSE 80 443
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"]

Advanced Deployment Strategies

Docker Compose Integration

version: '3.8'
services:
  website:
    build: .
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./website:/app
      - caddy_data:/data
      - caddy_config:/config

volumes:
  caddy_data:
  caddy_config:

Security Considerations

  1. Non-Root Execution: Run Caddy as a non-privileged user.
  2. Minimal Image: Use Alpine-based images.
  3. Regular Updates: Keep base images and Caddy updated.

Secure Dockerfile Modification

FROM caddy:2.7-alpine

# Create non-root user
RUN addgroup -S webuser && adduser -S webuser -G webuser

# Set proper permissions
COPY --chown=webuser:webuser ./website /app

# Switch to non-root user
USER webuser

EXPOSE 80 443

CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"]

Performance Optimization Techniques

  1. Caching Strategies: Leverage Caddy's built-in caching mechanisms.
  2. Compression: Enable gzip/brotli compression.
  3. HTTP/3 Support: Utilize modern protocol capabilities.

Continuous Integration Considerations

  • Use multi-stage builds for complex projects
  • Implement automated testing before container build
  • Create separate Dockerfiles for development and production

Conclusion

Containerizing static websites with Caddy offers a modern, secure, and simplified approach to web hosting. By leveraging Docker and Caddy's unique capabilities, developers can create robust, easily deployable web applications with minimal configuration overhead.

Key Takeaways

  • Caddy simplifies HTTPS configuration
  • Docker provides consistent deployment environments
  • Security and performance are built into the workflow
  • Minimal configuration required for powerful web hosting