Reliability

How to stabilize your Nginx or Apache setup for managed infrastructure for SaaS

Binadit Tech Team · May 03, 2026 · 6 min lire
How to stabilize your Nginx or Apache setup for managed infrastructure for SaaS

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.log

Add 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.