📋 Introduction
This comprehensive guide covers advanced NGINX configuration techniques to optimize performance, security, and resource management. We'll explore worker processes, timeout configurations, compression settings, caching mechanisms, and integration with MariaDB and PHP-FPM.
🔧 Initial Configuration Setup
Creating the Includes Directory
First, we'll create a dedicated directory for modular configuration files:
cd /etc/nginx/
sudo mkdir includes/
ls
Backing Up the Configuration
cd /etc/nginx
sudo cp nginx.conf nginx.conf.bak
sudo nano nginx.conf
⚙️ Main Context Configuration
The main context directives control global NGINX behavior and worker process settings.
worker_rlimit_nofile 30000;
worker_priority -10;
timer_resolution 100ms;
pcre_jit on;
| Directive | Value | Description |
|---|---|---|
worker_rlimit_nofile |
30000 | Maximum number of open files per worker process |
worker_priority |
-10 | Worker process priority (negative = higher priority) |
timer_resolution |
100ms | Reduces timer resolution to improve performance |
pcre_jit |
on | Enables Just-In-Time compilation for regular expressions |
🔄 Events Context Configuration
The events context controls how NGINX handles connections at the network level.
worker_connections 4096;
accept_mutex on;
accept_mutex_delay 200ms;
use epoll;
Connection Processing Flow
| Directive | Value | Description |
|---|---|---|
worker_connections |
4096 | Maximum simultaneous connections per worker |
accept_mutex |
on | Serializes accept() calls to prevent thundering herd |
accept_mutex_delay |
200ms | Delay before attempting to acquire mutex again |
use |
epoll | Uses epoll for efficient event processing (Linux) |
📝 Creating Modular Configuration Files
We'll create separate configuration files for better organization and maintainability:
cd /etc/nginx/includes/
sudo touch basic_settings.conf buffers.conf timeouts.conf file_handle_cache.conf gzip.conf brotli.conf
ls -l
1. Basic Settings Configuration
File: basic_settings.conf
##
# BASIC SETTINGS
##
charset utf-8;
sendfile on;
sendfile_max_chunk 512k;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
more_clear_headers 'Server';
more_clear_headers 'X-Powered';
server_name_in_redirect off;
server_names_hash_bucket_size 64;
variables_hash_max_size 2048;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on- Uses kernel sendfile() for efficient file transferstcp_nopush on- Optimizes packet transmissiontcp_nodelay on- Disables Nagle's algorithm for low latencyserver_tokens off- Hides NGINX version for security
2. Buffer Settings Configuration
File: buffers.conf
##
# BUFFERS
##
client_body_buffer_size 256k;
client_body_in_file_only off;
client_header_buffer_size 64k;
client_max_body_size 100m;
connection_pool_size 512;
directio 4m;
ignore_invalid_headers on;
large_client_header_buffers 8 64k;
output_buffers 8 256k;
postpone_output 1460;
request_pool_size 32k;
client_max_body_size is set to 100m to allow theme and
plugin uploads. Reduce to 8m after initial site setup for security.
3. Timeout Configuration
File: timeouts.conf
##
# TIMEOUTS
##
keepalive_timeout 5;
keepalive_requests 500;
lingering_time 20s;
lingering_timeout 5s;
keepalive_disable msie6;
reset_timedout_connection on;
send_timeout 15s;
client_header_timeout 8s;
client_body_timeout 10s;
Timeout Types in NGINX
client_body_timeout
client_header_timeout
keepalive_timeout
keepalive_requests
fastcgi_connect_timeout
fastcgi_send_timeout
send_timeout
lingering_timeout
Keepalive allows multiple HTTP requests to reuse the same TCP connection, avoiding the overhead of establishing new connections. This is particularly beneficial for applications making many small requests.
- keepalive_timeout 5 - Connection stays open for 5 seconds after last request
- keepalive_requests 500 - Maximum 500 requests per connection
- Benefits: Reduced latency, lower CPU usage, fewer socket operations
4. Gzip Compression Configuration
File: gzip.conf
##
# GZIP
##
gzip on;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
gzip_static on;
gzip_min_length 1400;
gzip_buffers 32 8k;
gzip_http_version 1.0;
gzip_comp_level 5;
gzip_proxied any;
gzip_types text/plain text/css text/xml application/javascript application/x-javascript application/xml application/xml+rss application/ecmascript application/json image/svg+xml;
- Reduces bandwidth usage by 50-70%
- Faster page load times
- Lower data transfer costs
- Improved user experience
| Compression Level | CPU Usage | Compression Ratio | Recommended Use |
|---|---|---|---|
| 1-3 | Low | Basic | High-traffic sites |
| 4-6 | Medium | Good | Balanced performance |
| 7-9 | High | Excellent | Low-traffic sites |
5. Brotli Compression Configuration
File: brotli.conf
##
# BROTLI
##
brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_types application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml;
Brotli is a modern compression algorithm developed by Google that typically achieves 15-25% better compression than gzip, especially for text content.
- Compression: Brotli provides better compression ratios
- Speed: Gzip is faster at compression
- Support: Brotli requires modern browsers
- Best Practice: Enable both for maximum compatibility
6. File Handle Cache Configuration
File: file_handle_cache.conf
##
# FILE HANDLE CACHE
##
open_file_cache max=50000 inactive=60s;
open_file_cache_valid 120s;
open_file_cache_min_uses 2;
open_file_cache_errors off;
File Handle Cache Operation
Yes: Return metadata
No: Read from disk
The file handle cache can dramatically improve performance by caching file metadata (size, modification time, permissions) in memory, reducing filesystem access overhead.
🔗 Integrating Configuration Files
Now we'll include all our modular configuration files in the main nginx.conf:
cd /etc/nginx
sudo nano nginx.conf
HTTP Context Structure
Remove the old directives and add includes:
http {
##
# Basic Settings
##
include /etc/nginx/includes/basic_settings.conf;
##
# Gzip and Brotli Settings
##
include /etc/nginx/includes/gzip.conf;
include /etc/nginx/includes/brotli.conf;
##
# Buffer Settings
##
include /etc/nginx/includes/buffers.conf;
##
# Timeout Settings
##
include /etc/nginx/includes/timeouts.conf;
##
# File Handle Cache Settings
##
include /etc/nginx/includes/file_handle_cache.conf;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
✅ Testing and Validating Configuration
Configuration Syntax Testing
Always test your configuration before applying changes:
sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Common Errors and Solutions
| Error Message | Cause | Solution |
|---|---|---|
| Invalid number of arguments | Missing semicolon | Add semicolon at end of directive |
| No such file or directory | Incorrect file path or typo | Verify path with ls command |
| Unexpected token | Syntax error in directive | Check directive syntax in documentation |
Debugging with Line Numbers
Use the -L flag to open files with line numbers:
sudo nano -L /etc/nginx/nginx.conf
Applying Changes
- Reload: Gracefully applies changes without dropping connections
- Restart: Stops all processes and restarts (drops active connections)
- Best Practice: Always use
reloadin production
sudo systemctl reload nginx
📊 Managing Resource Limits
Checking NGINX Open File Limits
Determine the NGINX worker process ID and verify limits:
ps aux | grep www-data
View the limits for a specific process (replace XXX with actual PID):
cat /proc/XXX/limits
Adjusting Open File Limits
Update the worker file limit in nginx.conf:
worker_rlimit_nofile 45000;
Test and reload:
sudo nginx -t
sudo systemctl reload nginx
Verifying New Limits
Get the new PID and verify:
ps aux | grep www-data
cat /proc/XXX/limits
⚡ Creating Useful BASH Aliases
Aliases improve workflow efficiency by creating shortcuts for common commands:
cd ~
nano .bash_aliases
System Maintenance Aliases
alias server_update='sudo apt update && sudo apt upgrade && sudo apt autoremove'
NGINX Management Aliases
alias ngt='sudo nginx -t'
alias ngr='sudo systemctl reload nginx'
alias fpmr='sudo systemctl restart php8.3-fpm'
alias ngsa='cd /etc/nginx/sites-available/ && ls'
alias ngin='cd /etc/nginx/includes/ && ls'
Activating Aliases
Switch to your user to load the new aliases:
su andrew
ngt- Test NGINX configurationngr- Reload NGINXfpmr- Restart PHP-FPMngsa- Navigate to sites-availablengin- Navigate to includes directory
🗄️ MariaDB Optimization
Initial Security Setup
sudo mysql_secure_installation
Performance Schema Configuration
Navigate to MariaDB configuration directory:
cd /etc/mysql/mariadb.conf.d/
sudo cp 50-server.cnf 50-server.cnf.bak
sudo nano 50-server.cnf
Enabling Performance Schema
# Performance Schema
performance_schema=ON
performance-schema-instrument='stage/%=ON'
performance-schema-consumer-events-stages-current=ON
performance-schema-consumer-events-stages-history=ON
performance-schema-consumer-events-stages-history-long=ON
Additional Optimizations
Skip Name Resolution
skip-name-resolve
Binary Log Retention
expire_logs_days = 3
This directive prevents MariaDB from performing DNS lookups on connecting clients, which can significantly improve connection times, especially if DNS is slow or unavailable.
InnoDB Buffer Pool Configuration
Memory Allocation for 1GB Server
| Component | Allocation | Percentage |
|---|---|---|
| InnoDB Buffer Pool | 800M | 80% |
| InnoDB Log Files | 200M | 20% |
| System & Other | ~200M | Remaining |
For a 1GB RAM server:
innodb_buffer_pool_size = 800M
innodb_log_file_size = 200M
innodb_log_file_size as it
requires recreation of log files.
sudo systemctl stop mariadb
sudo nano 50-server.cnf
# Add the directives above
sudo systemctl start mariadb
MariaDB Aliases
nano ~/.bash_aliases
alias mariare='sudo systemctl restart mariadb'
Using MySQLTuner
MySQLTuner analyzes your MariaDB performance and provides recommendations:
cd ~
mkdir MySQLTuner/
cd MySQLTuner/
wget http://mysqltuner.pl/ -O mysqltuner.pl
chmod +x mysqltuner.pl
sudo ./mysqltuner.pl
Setting MariaDB Open File Limits
Create systemd override directory:
cd /etc/systemd/system/
sudo mkdir mariadb.service.d/
cd mariadb.service.d/
sudo nano limits.conf
Add the following content:
[Service]
LimitNOFILE=40000
Apply changes:
sudo systemctl daemon-reload
sudo systemctl restart mariadb
Verifying MariaDB Limits
ps aux | grep mysql
cat /proc/XXX/limits
🐘 PHP-FPM Optimization
Creating Server Override Configuration
cd /etc/php/8.3/fpm/conf.d/
sudo nano server_override.ini
Security and Performance Settings
# HARDENING PHP
allow_url_fopen = Off
cgi.fix_pathinfo=0
expose_php = Off
# OPTIMIZE PHP
upload_max_filesize = 100M
post_max_size = 125M
max_input_vars = 3000
memory_limit = 256M
| Directive | Value | Purpose |
|---|---|---|
| allow_url_fopen | Off | Security - prevents remote file inclusion |
| cgi.fix_pathinfo | 0 | Security - prevents path disclosure attacks |
| expose_php | Off | Security - hides PHP version |
| upload_max_filesize | 100M | Allows large file uploads |
| post_max_size | 125M | Must be larger than upload_max_filesize |
| memory_limit | 256M | Maximum memory per script |
Configuring PHP-FPM Resource Limits
Open PHP-FPM configuration:
cd /etc/php/8.3/fpm/
sudo cp php-fpm.conf php-fpm.conf.bak
sudo nano php-fpm.conf
Find and update the resource limits:
rlimit_files = 32768
rlimit_core = unlimited
Applying PHP-FPM Changes
sudo systemctl reload nginx
sudo systemctl restart php8.3-fpm
Verifying PHP-FPM Limits
ps aux | grep php-fpm
cat /proc/XXX/limits
- NGINX worker limits increased
- MariaDB file limits configured
- PHP-FPM resource limits set
- All services reloaded successfully
🎯 Best Practices Summary
Configuration Management
- Always backup: Create .bak files before editing
- Test first: Run
nginx -tbefore applying changes - Use reload: Never use restart in production
- Modular configs: Keep configurations organized in separate files
- Document changes: Add comments explaining custom settings
Performance Optimization
- Enable compression: Use both gzip and Brotli
- Tune buffers: Adjust based on your traffic patterns
- Set proper timeouts: Balance performance and resource usage
- Use caching: Enable file handle cache for static content
- Monitor limits: Regularly check and adjust resource limits
Security Considerations
- Hide server version information
- Disable unnecessary PHP functions
- Set appropriate file upload limits
- Use skip-name-resolve in MariaDB
- Regularly update all software components
🔍 Troubleshooting Guide
Common Issues and Solutions
| Issue | Diagnosis | Solution |
|---|---|---|
| Configuration test fails | Check error message and line number | Open file with nano -L, fix syntax error |
| Service won't start | Check logs: journalctl -xe |
Review error logs, restore from backup if needed |
| High CPU usage | Check worker processes and compression level | Reduce gzip/brotli compression levels |
| Connection errors | Check worker_connections and limits | Increase worker_connections and file limits |
| Slow database | Run MySQLTuner | Adjust InnoDB buffer pool size |
Useful Diagnostic Commands
# Check NGINX status
sudo systemctl status nginx
# Check error logs
sudo tail -f /var/log/nginx/error.log
# Check MariaDB status
sudo systemctl status mariadb
# Check PHP-FPM status
sudo systemctl status php8.3-fpm
# Monitor system resources
htop
# Check listening ports
sudo netstat -tulpn | grep LISTEN
📖 Quick Reference
Essential Commands
NGINX Commands
sudo nginx -t- Test configurationsudo systemctl reload nginx- Reload configurationsudo systemctl restart nginx- Restart servicesudo systemctl status nginx- Check status
MariaDB Commands
sudo mysql- Connect to MariaDBsudo systemctl restart mariadb- Restart serviceSHOW VARIABLES LIKE '%var_name%'- Check variable
PHP-FPM Commands
sudo systemctl restart php8.3-fpm- Restart PHP-FPMphp -v- Check PHP versionphp -m- List installed modules
🎓 Conclusion
This comprehensive guide has covered the essential aspects of NGINX performance optimization, including:
- Worker process and event handling configuration
- Timeout and keepalive optimization
- Compression with gzip and Brotli
- File handle caching for improved performance
- MariaDB tuning and security hardening
- PHP-FPM optimization and resource management
- Workflow enhancement with BASH aliases
Remember to always test configurations in a development environment before applying to production, and maintain regular backups of your configuration files.
Continue to monitor your server performance using tools like MySQLTuner, and adjust settings based on your specific workload and traffic patterns. Regular optimization reviews will help maintain peak performance.