Skip to main content
Tools

Varnish Cache Dockerfile

Dockerfile for tools projects

View on GitHub

Dockerfile Content

# ============================================================================
# Created by https://Dockerfile.io/
# TOOL-SPECIFIC TEMPLATE for Varnish Cache
# Website: https://varnish-cache.org/
# Repository: https://github.com/varnishcache/varnish-cache
# ============================================================================

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# TEMPLATE OVERVIEW & USAGE NOTES
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# • TEMPLATE TYPE: TOOL-SPECIFIC TEMPLATE
# • PURPOSE: Varnish HTTP accelerator and reverse proxy cache
# • DESIGN PHILOSOPHY: High-performance caching with security hardening
# • COMBINATION GUIDANCE: Use as reverse proxy in front of web applications
# • SECURITY CONSIDERATIONS: Access control, request filtering, TLS termination
# • BEST PRACTICES: Cache tuning, purging strategies, monitoring
# • OFFICIAL SOURCES: Varnish documentation and Docker best practices

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# VARNISH CACHE CONFIGURATION
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FROM varnish:7.4-alpine

# Build arguments for configuration
ARG VARNISH_VERSION=7.4
ARG VARNISH_PORT=80
ARG VARNISH_BACKEND_PORT=8080
ARG VARNISH_BACKEND_HOST=backend
ARG VARNISH_MEMORY_SIZE=256m
ARG VARNISH_STORAGE_SIZE=1G
ARG VARNISH_TTL=120
ARG VARNISH_GRACE=10
ARG VARNISH_USER=varnish
ARG VARNISH_GROUP=varnish
ARG VARNISH_UID=1001
ARG VARNISH_GID=1001

# Environment variables for Varnish configuration
ENV VARNISH_VERSION=${VARNISH_VERSION} \
    VARNISH_PORT=${VARNISH_PORT} \
    VARNISH_BACKEND_PORT=${VARNISH_BACKEND_PORT} \
    VARNISH_BACKEND_HOST=${VARNISH_BACKEND_HOST} \
    VARNISH_MEMORY_SIZE=${VARNISH_MEMORY_SIZE} \
    VARNISH_STORAGE_SIZE=${VARNISH_STORAGE_SIZE} \
    VARNISH_TTL=${VARNISH_TTL} \
    VARNISH_GRACE=${VARNISH_GRACE} \
    VARNISH_USER=${VARNISH_USER} \
    VARNISH_GROUP=${VARNISH_GROUP} \
    VARNISH_UID=${VARNISH_UID} \
    VARNISH_GID=${VARNISH_GID}

# Create custom user and group if they don't exist
RUN if ! getent group ${VARNISH_GID} > /dev/null; then \
        groupadd -g ${VARNISH_GID} ${VARNISH_GROUP}; \
    fi && \
    if ! getent passwd ${VARNISH_UID} > /dev/null; then \
        useradd -u ${VARNISH_UID} -g ${VARNISH_GID} ${VARNISH_USER}; \
    fi

# Create directories with proper permissions
RUN mkdir -p /var/lib/varnish && \
    mkdir -p /var/log/varnish && \
    chown -R ${VARNISH_USER}:${VARNISH_GROUP} /var/lib/varnish && \
    chown -R ${VARNISH_USER}:${VARNISH_GROUP} /var/log/varnish && \
    chmod -R 750 /var/lib/varnish && \
    chmod -R 750 /var/log/varnish

# Copy custom VCL configuration
COPY <<'EOF' /etc/varnish/default.vcl
vcl 4.1;

# Default backend definition
backend default {
    .host = "${VARNISH_BACKEND_HOST}";
    .port = "${VARNISH_BACKEND_PORT}";
    .connect_timeout = 5s;
    .first_byte_timeout = 60s;
    .between_bytes_timeout = 60s;
    .max_connections = 1000;
}

# Access control list for purge operations
acl purge {
    "localhost";
    "127.0.0.1";
    "::1";
}

# Subroutine called at the beginning of a request
sub vcl_recv {
    # Allow purge requests only from authorized clients
    if (req.method == "PURGE") {
        if (!client.ip ~ purge) {
            return (synth(405, "Method not allowed"));
        }
        return (purge);
    }

    # Only cache GET and HEAD requests
    if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
    }

    # Remove cookies for static assets to improve cache hit rate
    if (req.url ~ "\.(css|js|png|gif|jp(e?)g|ico|webp|svg|woff2?|ttf|eot)$") {
        unset req.http.Cookie;
    }

    # Normalize Accept-Encoding header
    if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
            # No point in compressing these
            unset req.http.Accept-Encoding;
        } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
        } elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
        } else {
            unset req.http.Accept-Encoding;
        }
    }

    # Remove tracking and analytics cookies
    if (req.http.Cookie) {
        set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(__[a-z]+|_ga|_gat|utm[a-z]+|gclid|fbclid)=", "; \1");
        set req.http.Cookie = regsuball(req.http.Cookie, "^;+", "");

        if (req.http.Cookie == "") {
            unset req.http.Cookie;
        }
    }

    return (hash);
}

# Subroutine called after an object has been retrieved from the backend
sub vcl_backend_response {
    # Set default TTL
    set beresp.ttl = ${VARNISH_TTL}s;
    set beresp.grace = ${VARNISH_GRACE}s;

    # Cache static assets for longer
    if (bereq.url ~ "\.(css|js|png|gif|jp(e?)g|ico|webp|svg|woff2?|ttf|eot)$") {
        set beresp.ttl = 1w;
        unset beresp.http.Set-Cookie;
    }

    # Don't cache responses with Set-Cookie header
    if (beresp.http.Set-Cookie) {
        set beresp.uncacheable = true;
        set beresp.ttl = 120s;
        return (deliver);
    }

    # Don't cache error responses
    if (beresp.status >= 400) {
        set beresp.uncacheable = true;
        set beresp.ttl = 120s;
        return (deliver);
    }

    # Enable ESI (Edge Side Includes) processing
    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
        unset beresp.http.Surrogate-Control;
        set beresp.do_esi = true;
    }

    return (deliver);
}

# Subroutine called before delivering the object to the client
sub vcl_deliver {
    # Add cache hit/miss header for debugging
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
    } else {
        set resp.http.X-Cache = "MISS";
    }

    # Add security headers
    set resp.http.X-Content-Type-Options = "nosniff";
    set resp.http.X-Frame-Options = "SAMEORIGIN";
    set resp.http.X-XSS-Protection = "1; mode=block";
    set resp.http.Referrer-Policy = "strict-origin-when-cross-origin";

    # Remove internal headers
    unset resp.http.Via;
    unset resp.http.X-Varnish;
    unset resp.http.Server;

    return (deliver);
}

# Subroutine called when there's a cache miss
sub vcl_miss {
    return (fetch);
}

# Subroutine called when there's a cache hit
sub vcl_hit {
    if (obj.ttl >= 0s) {
        return (deliver);
    }

    if (obj.ttl + obj.grace > 0s) {
        return (deliver);
    }

    return (fetch);
}

# Subroutine called for synthetic responses
sub vcl_synth {
    set resp.http.Content-Type = "text/html; charset=utf-8";
    set resp.http.Retry-After = "5";

    synthetic( {"<!DOCTYPE html>
<html>
  <head>
    <title>"} + resp.status + " " + resp.reason + {"</title>
  </head>
  <body>
    <h1>Error "} + resp.status + " " + resp.reason + {"</h1>
    <p>"} + resp.reason + {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"} );

    return (deliver);
}
EOF

# Copy startup script with configuration
COPY <<'EOF' /docker-entrypoint.sh
#!/bin/sh
set -e

# Set Varnish configuration
export VARNISH_STORAGE="malloc,${VARNISH_MEMORY_SIZE}"
export VARNISH_LISTEN=":${VARNISH_PORT}"

# Start Varnish
exec varnishd \
    -F \
    -a ${VARNISH_LISTEN} \
    -f /etc/varnish/default.vcl \
    -s malloc,${VARNISH_MEMORY_SIZE} \
    -p http_resp_hdr_len=8192 \
    -p http_resp_size=98304 \
    -p workspace_backend=64k \
    -p workspace_client=64k \
    -p vcc_allow_inline_c=on
EOF

# Make startup script executable
RUN chmod +x /docker-entrypoint.sh

# Switch to non-root user
USER ${VARNISH_USER}

# Expose Varnish port
EXPOSE ${VARNISH_PORT}

# Health check for Varnish
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
    CMD varnishadm backend.list | grep -q "Healthy" || exit 1

# Start Varnish
CMD ["/docker-entrypoint.sh"]

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# USAGE EXAMPLES & BEST PRACTICES
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

# USAGE EXAMPLES
# ==============

# Example 1: Build Varnish image
# docker build -t my-varnish:7.4 .

# Example 2: Run Varnish as reverse proxy for backend application
# docker run -d \
#   --name varnish-cache \
#   -p 80:80 \
#   -e VARNISH_BACKEND_HOST=backend-app \
#   -e VARNISH_BACKEND_PORT=8080 \
#   my-varnish:7.4

# Example 3: Run with custom memory allocation
# docker run -d \
#   --name varnish-large \
#   -p 80:80 \
#   -e VARNISH_MEMORY_SIZE=512m \
#   -e VARNISH_BACKEND_HOST=backend \
#   my-varnish:7.4

# Example 4: Run with Docker Compose
# docker-compose up -d

# Example 5: Run with custom VCL configuration
# docker run -d \
#   --name varnish-custom \
#   -p 80:80 \
#   -v ./custom.vcl:/etc/varnish/default.vcl \
#   my-varnish:7.4

# Example 6: Run with resource limits
# docker run -d \
#   --name varnish-prod \
#   -p 80:80 \
#   --memory=1g \
#   --cpus=2 \
#   -e VARNISH_MEMORY_SIZE=512m \
#   my-varnish:7.4

# Example 7: Run with health check verification
# docker run -d \
#   --name varnish-monitored \
#   -p 80:80 \
#   --health-cmd="varnishadm backend.list | grep -q 'Healthy' || exit 1" \
#   my-varnish:7.4

# Example 8: Run with TLS termination (using external proxy)
# docker run -d \
#   --name varnish-tls \
#   -p 443:443 \
#   -e VARNISH_PORT=443 \
#   -v ./ssl:/etc/ssl \
#   my-varnish:7.4

# BEST PRACTICES
# ==============

# Security Best Practices:
# • Restrict purge operations to authorized IP addresses only
# • Implement request filtering to block malicious traffic
# • Use TLS termination for secure connections
# • Regularly update Varnish and Alpine dependencies
# • Monitor access logs for suspicious activity
# • Implement rate limiting for API endpoints
# • Use secure headers for web application protection
# • Restrict backend access to trusted networks

# Performance Optimization:
# • Adjust VARNISH_MEMORY_SIZE based on available RAM
# • Tune TTL and grace periods for your specific workload
# • Implement proper cache invalidation strategies
# • Use edge-side includes (ESI) for dynamic content caching
# • Monitor cache hit rates and adjust configuration accordingly
# • Implement compression for text-based content
# • Use persistent storage for large cache objects
# • Optimize VCL configuration for your application patterns

# Operations & Maintenance:
# • Use specific version tags for Varnish images (avoid 'latest')
# • Implement proper logging and log rotation
# • Monitor backend health and implement failover strategies
# • Use health checks for container orchestration
# • Implement automated cache warming after deployments
# • Set up monitoring for cache performance metrics
# • Regularly review and optimize VCL configuration
# • Implement backup strategies for critical configurations

# Varnish-Specific Considerations:
# • Configure appropriate TTL values for different content types
# • Implement proper cache purging mechanisms
# • Use Varnish Administration Console (varnishadm) for management
# • Monitor backend response times and implement timeouts
# • Use Varnish Custom Statistics (varnishstat) for monitoring
# • Implement request coalescing for high-traffic endpoints
# • Configure appropriate workspace sizes for your workload
# • Use Varnish's built-in load balancing capabilities

# Cache Strategy:
# • Implement different caching strategies for static vs dynamic content
# • Use cache variations for user-specific content
# • Implement cache warming for critical pages
# • Monitor cache efficiency and adjust strategies
# • Use cache tags for granular invalidation
# • Implement stale-while-revalidate patterns
# • Configure appropriate cache headers for CDN integration
# • Monitor cache memory usage and fragmentation

# Development & Testing:
# • Use Docker Compose for local development environments
# • Implement integration tests with backend applications
# • Test cache invalidation strategies thoroughly
# • Use Varnish's test tools for configuration validation
# • Set up development environments with realistic traffic patterns
# • Monitor cache behavior during development
# • Implement proper error handling in VCL
# • Test performance under load with different configurations

Note: This file is fetched from GitHub and cached for 7 days.