Introduction to Web Server Configuration
Web server configuration is a critical aspect of system administration that directly impacts website performance, security, and reliability. Apache HTTP Server and Nginx are the two most popular web servers powering the modern internet, each offering unique advantages for different use cases.
This comprehensive guide will walk you through the complete setup and configuration of both Apache and Nginx web servers, providing practical examples and best practices for production environments.
Apache HTTP Server Configuration
Installing Apache
Apache installation varies by operating system. Here are the commands for popular distributions:
Ubuntu/Debian:
sudo apt update
sudo apt install apache2
sudo systemctl enable apache2
sudo systemctl start apache2
CentOS/RHEL:
sudo yum install httpd
sudo systemctl enable httpd
sudo systemctl start httpd
Apache Directory Structure
Understanding Apache’s directory structure is essential for effective configuration:
- /etc/apache2/ – Main configuration directory
- /etc/apache2/apache2.conf – Main configuration file
- /etc/apache2/sites-available/ – Virtual host configuration files
- /etc/apache2/sites-enabled/ – Active virtual host links
- /etc/apache2/mods-available/ – Available modules
- /etc/apache2/mods-enabled/ – Active modules
- /var/www/html/ – Default document root
Basic Apache Configuration
The main Apache configuration file contains global settings. Here’s a basic configuration example:
# /etc/apache2/apache2.conf
# Server Root
ServerRoot /etc/apache2
# Process ID file
PidFile ${APACHE_PID_FILE}
# Timeout settings
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
# User and Group
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
# Host name and port
ServerName example.com:80
# Directory permissions
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
Virtual Host Configuration
Virtual hosts allow hosting multiple websites on a single server. Create a new virtual host configuration:
# /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
# Logging
ErrorLog ${APACHE_LOG_DIR}/example.com_error.log
CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
# Directory configuration
<Directory /var/www/example.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Enable the virtual host:
sudo a2ensite example.com.conf
sudo systemctl reload apache2
SSL Configuration for Apache
Enable SSL module and configure HTTPS:
sudo a2enmod ssl
sudo a2enmod rewrite
# /etc/apache2/sites-available/example.com-ssl.conf
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
# SSL Configuration
SSLEngine on
SSLCertificateFile /path/to/certificate.crt
SSLCertificateKeyFile /path/to/private.key
SSLCertificateChainFile /path/to/chain.crt
# Security headers
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options DENY
# Logging
ErrorLog ${APACHE_LOG_DIR}/example.com_ssl_error.log
CustomLog ${APACHE_LOG_DIR}/example.com_ssl_access.log combined
</VirtualHost>
Nginx Configuration
Installing Nginx
Ubuntu/Debian:
sudo apt update
sudo apt install nginx
sudo systemctl enable nginx
sudo systemctl start nginx
CentOS/RHEL:
sudo yum install nginx
sudo systemctl enable nginx
sudo systemctl start nginx
Nginx Directory Structure
Nginx follows a different organizational structure:
- /etc/nginx/ – Main configuration directory
- /etc/nginx/nginx.conf – Main configuration file
- /etc/nginx/sites-available/ – Virtual host configurations
- /etc/nginx/sites-enabled/ – Active virtual host links
- /etc/nginx/conf.d/ – Additional configuration files
- /var/www/html/ – Default document root
Basic Nginx Configuration
The main Nginx configuration file structure:
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
# MIME types
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging format
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# Performance settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private must-revalidate max-age=0;
gzip_types text/plain text/css text/xml text/javascript
application/x-javascript application/xml+rss;
# Include virtual hosts
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Nginx Virtual Host Configuration
Create a new server block for your website:
# /etc/nginx/sites-available/example.com
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
index index.html index.htm index.php;
# Access and error logs
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
# Location blocks
location / {
try_files $uri $uri/ =404;
}
# PHP processing
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Deny access to hidden files
location ~ /\. {
deny all;
}
# Static file caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Nginx SSL Configuration
# /etc/nginx/sites-available/example.com-ssl
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
# SSL certificates
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
# SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security headers
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
location / {
try_files $uri $uri/ =404;
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
Performance Optimization
Apache Performance Tuning
Configure Apache’s Multi-Processing Module (MPM):
# /etc/apache2/mods-available/mpm_prefork.conf
<IfModule mpm_prefork_module>
StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit 256
MaxRequestWorkers 256
MaxConnectionsPerChild 0
</IfModule>
Enable compression:
# Enable mod_deflate
LoadModule deflate_module modules/mod_deflate.so
<Location />
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \
\.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
</Location>
Nginx Performance Tuning
Optimize worker processes and connections:
# Performance optimization in nginx.conf
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
# Buffer sizes
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
output_buffers 1 32k;
postpone_output 1460;
# Timeouts
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
# Connection processing
keepalive_timeout 65;
keepalive_requests 100000;
reset_timedout_connection on;
}
Load Balancing Configuration
Nginx as Load Balancer
Configure Nginx to distribute traffic across multiple backend servers:
# /etc/nginx/nginx.conf
http {
# Upstream backend servers
upstream backend_servers {
least_conn;
server 192.168.1.10:80 weight=3;
server 192.168.1.11:80 weight=2;
server 192.168.1.12:80 weight=1 backup;
# Health check
keepalive 32;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Proxy timeouts
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
}
Apache with mod_proxy_balancer
# Enable required modules
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
# Load balancer configuration
<Proxy balancer://mycluster>
BalancerMember http://192.168.1.10:80
BalancerMember http://192.168.1.11:80
BalancerMember http://192.168.1.12:80 status=+H
ProxySet lbmethod=byrequests
</Proxy>
<VirtualHost *:80>
ServerName example.com
ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/
</VirtualHost>
Security Configuration
Apache Security Hardening
# Security configuration in apache2.conf
# Hide server information
ServerTokens Prod
ServerSignature Off
# Prevent access to .htaccess files
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
# Security headers
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options SAMEORIGIN
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Disable unnecessary HTTP methods
<Directory />
<LimitExcept GET POST HEAD>
Require all denied
</LimitExcept>
</Directory>
Nginx Security Hardening
# Security configuration in nginx.conf
# Hide server information
server_tokens off;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
# Rate limiting
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
# Apply rate limiting
limit_req zone=one burst=10 nodelay;
# Disable unwanted HTTP methods
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 405;
}
}
Monitoring and Logging
Apache Monitoring
Enable server status module:
# Enable mod_status
LoadModule status_module modules/mod_status.so
<Location "/server-status">
SetHandler server-status
Require local
Require ip 192.168.1
</Location>
<Location "/server-info">
SetHandler server-info
Require local
Require ip 192.168.1
</Location>
Nginx Monitoring
Configure status module:
server {
listen 8080;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
allow 192.168.1.0/24;
deny all;
}
}
Log Analysis
Configure detailed logging for both servers:
# Custom Nginx log format
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
access_log /var/log/nginx/detailed.log detailed;
Best Practices and Troubleshooting
Configuration Best Practices
- Regular Backups: Always backup configuration files before making changes
- Version Control: Use Git to track configuration changes
- Testing: Test configurations in staging environments
- Documentation: Document all custom configurations
- Security Updates: Keep servers updated with latest security patches
- Monitoring: Implement comprehensive monitoring and alerting
Common Troubleshooting Commands
Apache diagnostics:
# Test configuration syntax
sudo apache2ctl configtest
# Check enabled modules
apache2ctl -M
# View error logs
sudo tail -f /var/log/apache2/error.log
# Check virtual host configuration
apache2ctl -S
Nginx diagnostics:
# Test configuration syntax
sudo nginx -t
# Reload configuration
sudo nginx -s reload
# View error logs
sudo tail -f /var/log/nginx/error.log
# Check configuration
nginx -T
Performance Monitoring
Use these tools to monitor server performance:
- htop/top: System resource monitoring
- iotop: Disk I/O monitoring
- netstat: Network connection monitoring
- apache2buddy.pl: Apache performance analysis
- nginx-amplify: Nginx monitoring service
Conclusion
Proper web server configuration is crucial for maintaining secure, performant, and reliable web applications. Apache excels in environments requiring extensive module support and .htaccess flexibility, while Nginx shines in high-concurrency scenarios and as a reverse proxy.
Both servers can be configured to handle modern web application demands effectively. Regular monitoring, security updates, and performance optimization ensure your web infrastructure remains robust and scalable as your applications grow.
Remember to always test configurations in staging environments, maintain backups, and implement comprehensive monitoring to catch issues before they impact production systems.







