Production-ready web server configs that prevent SaaS outages
Every SaaS platform eventually faces the same problem: your web server works fine during development, but crumbles under real production load. Users complain about timeouts, revenue drops during traffic spikes, and you're left scrambling to fix configurations that should have been production-ready from day one.
This guide shows you exactly how to configure Nginx and Apache for production stability, with specific configs and commands you can implement today.
What you'll get from this setup
A properly tuned web server maintains consistent response times under load, handles traffic surges without dropping connections, and recovers quickly from resource spikes. For SaaS platforms, this translates directly to better user experience and reduced revenue loss from outages.
Before you start
You'll need:
- Root access to your Linux server
- Nginx 1.18+ or Apache 2.4+ installed
- A staging environment for testing changes
- Basic monitoring tools to track server metrics
Nginx production configuration
Default Nginx installs prioritize simplicity over performance. Here's how to fix that.
First, check your server capacity:
nproc
free -h
Then configure /etc/nginx/nginx.conf 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;
# Optimized buffer sizes
client_body_buffer_size 128k;
client_max_body_size 16M;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
# Production timeouts
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;
# Enable compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/javascript application/json;
}
For your site config, add rate limiting and proper proxy settings:
server {
listen 80;
server_name your-domain.com;
# Prevent abuse
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req zone=api burst=20 nodelay;
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn perip 10;
location / {
# PHP-FPM configuration
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 180s;
fastcgi_read_timeout 180s;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Apache optimization for scale
Apache's default prefork module kills performance. Switch to event module:
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo systemctl restart apache2
Configure /etc/apache2/mods-available/mpm_event.conf:
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 10000
KeepAlive On
KeepAliveTimeout 5
</IfModule>
Enable essential modules:
sudo a2enmod rewrite headers deflate expires ssl
Set up your virtual host with compression and security:
<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
# Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain text/html text/css
AddOutputFilterByType DEFLATE application/javascript application/json
</IfModule>
</VirtualHost>
System-level tweaks that matter
Both servers need proper system limits. Edit /etc/security/limits.conf:
* soft nofile 65535
* hard nofile 65535
Optimize network settings in /etc/sysctl.conf:
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_congestion_control = bbr
net.core.netdev_max_backlog = 5000
Apply changes:
sudo sysctl -p
sudo systemctl restart nginx # or apache2
Verify everything works
Test your configuration:
# Nginx
sudo nginx -t && sudo systemctl reload nginx
# Apache
sudo apache2ctl configtest && sudo systemctl reload apache2
Load test your setup:
sudo apt install apache2-utils
ab -n 1000 -c 50 http://your-domain.com/
Monitor key metrics:
# Active connections
netstat -an | grep :80 | wc -l
# Check for errors
tail -f /var/log/nginx/error.log
Critical mistakes to avoid
Don't max out connections without adjusting system limits. Your worker_processes × worker_connections can't exceed file descriptor limits.
Don't keep default timeouts. They're designed for development, not production traffic patterns.
Always test changes in staging first. A single syntax error can take down your entire application.
What's next
Once your web server configuration is solid, you can focus on higher-level reliability patterns like load balancing, caching strategies, and database optimization. The key is getting these fundamentals right before adding complexity.
Originally published on binadit.com
Top comments (0)