What you'll achieve and why it matters
A properly configured web server handles traffic spikes smoothly, recovers gracefully from resource constraints, and maintains consistent response times under load. When your SaaS platform depends on stable web serving, getting these fundamentals right prevents revenue loss from downtime and keeps customer experience consistent.
Prerequisites and assumptions
This guide assumes you have:
- Root access to your web server (Linux-based system)
- Nginx 1.18+ or Apache 2.4+ installed
- Basic familiarity with configuration files and log analysis
- A test environment where you can safely apply changes
- Monitoring tools to track server metrics (CPU, memory, connections)
We'll cover configurations for both single-server setups and load-balanced environments.
Step-by-step implementation with concrete commands and configs
Setting up Nginx for production stability
Default Nginx installations are configured for basic functionality, not production load. Here's how to configure it properly:
First, determine your server's capacity. Check available CPU cores and memory:
nproc free -h
Edit your main Nginx configuration file:
sudo nano /etc/nginx/nginx.conf
Configure worker processes and connections based on your hardware:
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
keepalive_requests 1000;
# Buffer sizes
client_body_buffer_size 128k;
client_max_body_size 16M;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
# Timeouts
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;
# Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
}For your virtual host configuration, add connection limits and caching headers:
server {
listen 80;
server_name your-domain.com;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req zone=api burst=20 nodelay;
# Connection limiting
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn perip 10;
location / {
try_files $uri $uri/ /index.php?$query_string;
# Proxy settings if using PHP-FPM
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Timeouts
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 180s;
fastcgi_read_timeout 180s;
}
}Configuring Apache for high availability
Apache's default configuration often uses the prefork module, which doesn't scale well. Switch to the event module for better performance:
sudo a2dismod mpm_prefork sudo a2enmod mpm_event sudo systemctl restart apache2
Configure the event module in /etc/apache2/mods-available/mpm_event.conf:
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 10000
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
</IfModule>Enable essential modules for stability and performance:
sudo a2enmod rewrite sudo a2enmod headers sudo a2enmod deflate sudo a2enmod expires sudo a2enmod ssl
Configure your virtual host with proper limits:
<VirtualHost *:80>
ServerName your-domain.com
DocumentRoot /var/www/html
# 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"
# Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
</IfModule>
# Logging with rotation
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>Optimizing system-level settings
Both Nginx and Apache benefit from system-level optimizations. Edit /etc/security/limits.conf:
* soft nofile 65535 * hard nofile 65535 root soft nofile 65535 root hard nofile 65535
Optimize kernel network settings in /etc/sysctl.conf:
# Network performance net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.ipv4.tcp_rmem = 4096 8192 16777216 net.ipv4.tcp_wmem = 4096 8192 16777216 net.core.netdev_max_backlog = 5000 net.ipv4.tcp_congestion_control = bbr # Connection tracking net.netfilter.nf_conntrack_max = 262144 net.ipv4.ip_local_port_range = 1024 65535
Apply the changes:
sudo sysctl -p sudo systemctl restart nginx # or apache2
Setting up proper logging and log rotation
Configure logrotate to prevent disk space issues. Create /etc/logrotate.d/nginx:
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 nginx adm
sharedscripts
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi \
endscript
postrotate
invoke-rc.d nginx rotate >/dev/null 2>&1
endscript
}Verification: how to confirm it works
Test your configuration before putting it into production:
For Nginx:
sudo nginx -t sudo systemctl reload nginx
For Apache:
sudo apache2ctl configtest sudo systemctl reload apache2
Monitor key metrics to verify stability improvements:
# Check active connections sudo netstat -an | grep :80 | wc -l # Monitor memory usage free -h # Check error logs sudo tail -f /var/log/nginx/error.log # or sudo tail -f /var/log/apache2/error.log
Use load testing tools to verify your configuration handles traffic properly:
# Install Apache Bench sudo apt install apache2-utils # Test with concurrent connections ab -n 1000 -c 50 http://your-domain.com/
Monitor response times and error rates during the test. A properly configured server should maintain consistent response times and show zero connection errors under normal load.
Set up basic monitoring with system metrics:
# Create a simple monitoring script
#!/bin/bash
echo "$(date): Active connections: $(netstat -an | grep :80 | wc -l)" >> /var/log/connection-monitor.log
echo "$(date): Memory usage: $(free | grep Mem | awk '{printf("%.2f%%", $3/$2 * 100.0)}')" >> /var/log/connection-monitor.logAdd this to your crontab to run every minute:
* * * * * /path/to/your/monitoring-script.sh
Common pitfalls to avoid
Don't set worker connections too high without increasing system limits. The combination of worker_processes × worker_connections shouldn't exceed your system's file descriptor limits.
Avoid keeping the default timeout values in production. Long timeouts can exhaust connection pools during traffic spikes, while very short timeouts can cause legitimate requests to fail.
Don't forget to test configuration changes in a staging environment first. A syntax error in your web server config can bring down your entire application.
Be careful with aggressive caching headers on dynamic content. What works for static assets can cause stale data issues for API responses or user-specific content.
Next steps and related reading
Once your basic web server configuration is stable, consider implementing more advanced reliability patterns. Understanding when high availability infrastructure becomes a bottleneck covers scaling beyond single-server setups.
For database-heavy applications, web server stability is only part of the equation. Measuring database performance degradation shows you how to identify and resolve database bottlenecks that can make even perfectly configured web servers appear unstable.
Monitor your infrastructure continuously. Set up alerts for connection count spikes, memory usage above 80%, and response time degradation. Consider implementing health checks that go beyond simple ping tests to verify your application stack is functioning properly.
Build stable infrastructure without the complexity
Proper web server configuration requires ongoing attention to security updates, performance tuning, and capacity planning. Getting it wrong means instability exactly when your business needs reliability most.
Need this running in production without building it yourself? See our managed infrastructure services or schedule a call.