
Apache Web Server Dockerfile Example
When you’re setting up containerized web services, Apache HTTP Server remains one of the most reliable and widely-used web servers for hosting everything from simple static sites to complex web applications. Building a proper Dockerfile for Apache requires understanding the container ecosystem, Apache configuration nuances, and Docker best practices to create secure, efficient, and maintainable images. This guide walks through creating production-ready Apache Dockerfiles, covers common configuration scenarios, troubleshooting techniques, and compares different approaches to help you deploy robust web services in containers.
How Apache Docker Containers Work
Apache runs as the main process inside a Docker container, typically listening on port 80 (HTTP) and 443 (HTTPS). The container includes the Apache binary, configuration files, modules, and your web content. When you start the container, Apache becomes the primary process (PID 1), which means proper signal handling and graceful shutdowns become crucial for production deployments.
The key components in an Apache Docker setup include:
- Base operating system (usually Ubuntu, Debian, or Alpine)
- Apache HTTP Server package and essential modules
- Configuration files (httpd.conf, sites-enabled, etc.)
- SSL certificates and security configurations
- Your web application files and assets
- Log management and volume mounting strategies
Basic Apache Dockerfile Implementation
Here’s a straightforward Dockerfile that sets up Apache with common configurations:
FROM ubuntu:22.04
# Avoid interactive prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive
# Install Apache and essential tools
RUN apt-get update && \
apt-get install -y \
apache2 \
apache2-utils \
curl \
vim \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Enable Apache modules
RUN a2enmod rewrite ssl headers deflate
# Create directory for SSL certificates
RUN mkdir -p /etc/apache2/ssl
# Copy custom configuration
COPY apache2.conf /etc/apache2/apache2.conf
COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
# Copy web content
COPY ./html/ /var/www/html/
# Set proper permissions
RUN chown -R www-data:www-data /var/www/html \
&& chmod -R 755 /var/www/html
# Expose ports
EXPOSE 80 443
# Start Apache in foreground
CMD ["apache2ctl", "-D", "FOREGROUND"]
This Dockerfile creates a solid foundation, but you’ll need supporting configuration files. Here’s a sample apache2.conf with security hardening:
# /etc/apache2/apache2.conf
DefaultRuntimeDir ${APACHE_RUN_DIR}
PidFile ${APACHE_PID_FILE}
Timeout 60
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
HostnameLookups Off
LogLevel warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# Security headers
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options DENY
Header always set X-XSS-Protection "1; mode=block"
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# Hide Apache version
ServerTokens Prod
ServerSignature Off
# Include module configuration
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
IncludeOptional conf-enabled/*.conf
IncludeOptional sites-enabled/*.conf
Advanced Multi-Stage Build Example
For production environments, you’ll want to optimize image size and security using multi-stage builds. This approach separates the build environment from the runtime environment:
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY src/ ./src/
RUN npm run build
# Production stage
FROM httpd:2.4-alpine
# Install additional packages
RUN apk add --no-cache \
openssl \
curl \
bash
# Copy built application
COPY --from=builder /app/dist/ /usr/local/apache2/htdocs/
# Copy Apache configuration
COPY httpd.conf /usr/local/apache2/conf/httpd.conf
COPY ssl.conf /usr/local/apache2/conf/extra/httpd-ssl.conf
# Create SSL directory and generate self-signed certificate for development
RUN mkdir -p /usr/local/apache2/conf/ssl && \
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /usr/local/apache2/conf/ssl/apache.key \
-out /usr/local/apache2/conf/ssl/apache.crt \
-subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
# Set proper permissions
RUN chown -R daemon:daemon /usr/local/apache2/htdocs/
EXPOSE 80 443
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
CMD ["httpd-foreground"]
Real-World Use Cases and Examples
PHP Application with Apache
Many developers need Apache with PHP support. Here’s a Dockerfile for a PHP web application:
FROM php:8.2-apache
# Install PHP extensions and system dependencies
RUN apt-get update && apt-get install -y \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libzip-dev \
unzip \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd pdo pdo_mysql zip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Enable Apache modules
RUN a2enmod rewrite ssl headers
# Copy application files
COPY ./src/ /var/www/html/
# Copy custom Apache configuration
COPY apache-php.conf /etc/apache2/sites-available/000-default.conf
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Install PHP dependencies
WORKDIR /var/www/html
RUN composer install --no-dev --optimize-autoloader
# Set permissions
RUN chown -R www-data:www-data /var/www/html
EXPOSE 80 443
Reverse Proxy Configuration
Apache can also serve as a reverse proxy for backend services. Here’s a configuration example:
# reverse-proxy.conf
ServerName api.example.com
ProxyPreserveHost On
ProxyRequests Off
# Load balancing between backend servers
ProxyPass /api/ balancer://backend-cluster/
ProxyPassReverse /api/ balancer://backend-cluster/
BalancerMember http://backend1:3000
BalancerMember http://backend2:3000
ProxySet hcmethod GET
ProxySet hcuri /health
# Static files served directly
ProxyPass /static/ !
Alias /static/ /var/www/static/
LogLevel info
ErrorLog ${APACHE_LOG_DIR}/proxy_error.log
CustomLog ${APACHE_LOG_DIR}/proxy_access.log combined
Performance Optimization and Best Practices
Apache performance in containers requires specific tuning approaches. Here’s a performance-optimized configuration:
# performance-tuned.conf
# MPM Configuration for containers
StartServers 2
MinSpareServers 2
MaxSpareServers 5
MaxRequestWorkers 150
MaxConnectionsPerChild 1000
# Enable compression
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
DeflateCompressionLevel 6
# Cache static files
ExpiresActive On
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# Limit request size and timeouts for container environments
LimitRequestBody 10485760
Timeout 30
KeepAliveTimeout 2
Comparison with Alternative Approaches
Approach | Image Size | Security | Performance | Maintenance | Best Use Case |
---|---|---|---|---|---|
Official Apache (httpd:2.4) | ~200MB | High | Excellent | Low | Static sites, reverse proxy |
PHP-Apache (php:8.2-apache) | ~500MB | Medium | Good | Medium | PHP applications |
Alpine-based custom | ~50MB | High | Very Good | High | Production microservices |
Ubuntu-based custom | ~300MB | Medium | Good | Medium | Development, complex apps |
Common Issues and Troubleshooting
Here are the most frequent problems you’ll encounter and their solutions:
Permission Issues
One of the most common problems involves file permissions. Apache runs as www-data user but files are often copied as root:
# Fix in Dockerfile
RUN chown -R www-data:www-data /var/www/html && \
find /var/www/html -type d -exec chmod 755 {} \; && \
find /var/www/html -type f -exec chmod 644 {} \;
# Or use COPY with ownership
COPY --chown=www-data:www-data ./html/ /var/www/html/
Apache Won’t Start in Container
Apache needs to run in foreground mode inside containers. Check these common issues:
# Wrong - Apache will start and immediately exit
CMD ["service", "apache2", "start"]
# Correct - Apache runs in foreground
CMD ["apache2ctl", "-D", "FOREGROUND"]
# Alternative correct approach
CMD ["/usr/sbin/apache2", "-D", "FOREGROUND"]
Module Loading Issues
Enable required modules explicitly in your Dockerfile:
# Check available modules
RUN apache2ctl -M
# Enable specific modules
RUN a2enmod rewrite ssl headers deflate proxy proxy_http proxy_balancer lbmethod_byrequests
# Verify configuration
RUN apache2ctl configtest
Log Management
Container logs should go to stdout/stderr for proper Docker log handling:
# Link Apache logs to stdout/stderr
RUN ln -sf /dev/stdout /var/log/apache2/access.log && \
ln -sf /dev/stderr /var/log/apache2/error.log
# Or configure in apache2.conf
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 combined
Docker Compose Integration
Here’s a complete docker-compose.yml example that demonstrates Apache integration with other services:
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile.apache
ports:
- "80:80"
- "443:443"
volumes:
- ./html:/var/www/html:ro
- ./ssl:/etc/apache2/ssl:ro
- apache-logs:/var/log/apache2
environment:
- APACHE_LOG_LEVEL=warn
depends_on:
- db
networks:
- webnet
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: webapp
volumes:
- mysql-data:/var/lib/mysql
networks:
- webnet
volumes:
apache-logs:
mysql-data:
networks:
webnet:
driver: bridge
Security Considerations
Securing Apache in containers requires both container-level and Apache-level configurations:
# Dockerfile security improvements
FROM httpd:2.4-alpine
# Run as non-root user
RUN addgroup -g 1001 appgroup && \
adduser -D -s /bin/sh -u 1001 -G appgroup appuser
# Remove unnecessary packages and files
RUN apk del --purge wget curl && \
rm -rf /var/cache/apk/* && \
rm -rf /usr/local/apache2/htdocs/index.html
# Copy security-hardened configuration
COPY --chown=appuser:appgroup security.conf /usr/local/apache2/conf/extra/
# Set secure file permissions
RUN chmod -R o-rwx /usr/local/apache2/conf/ && \
chown -R appuser:appgroup /usr/local/apache2/
USER appuser
EXPOSE 8080
For comprehensive Apache documentation and advanced configuration options, check the official Apache HTTP Server documentation. The Docker development best practices guide provides additional insights for container optimization.
Running Apache in Docker containers offers excellent flexibility for both development and production environments. The key to success lies in understanding the interaction between Apache’s process model and Docker’s container lifecycle, implementing proper security measures, and optimizing for your specific use case. Whether you’re serving static sites, running PHP applications, or setting up reverse proxies, these patterns and configurations provide a solid foundation for reliable Apache deployments.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.