• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and MongoDB on AWS for Laravel

The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and MongoDB on AWS for Laravel

Nginx as a High-Performance Frontend for Laravel Applications

When deploying Laravel applications, Nginx serves as an excellent choice for a web server due to its event-driven architecture, making it highly efficient at handling concurrent connections. For PHP-based Laravel apps, we’ll typically pair Nginx with PHP-FPM. For Python-based applications using Gunicorn, Nginx acts as a reverse proxy.

Nginx Configuration for PHP-FPM (Laravel)

The core of Nginx configuration for PHP involves setting up a location block to handle PHP requests and pass them to the PHP-FPM process. This configuration assumes a standard PHP-FPM setup listening on a Unix socket or a TCP port.

Optimizing PHP-FPM Worker Processes

Tuning PHP-FPM’s process management is critical. The pm (process manager) setting dictates how workers are managed. For production, dynamic or ondemand are generally preferred over static to conserve resources when idle, but static can offer lower latency under consistent high load. Adjust pm.max_children, pm.start_servers, pm.min_spare_servers, and pm.max_spare_servers based on your server’s CPU and RAM. A common starting point for a moderately sized EC2 instance (e.g., m5.large) might be:

PHP-FPM Pool Configuration Example (/etc/php/8.1/fpm/pool.d/www.conf)

; Choose how the process manager (pm) should take on the task of managing the processes.
; Available options:
;   'static' - the number of child processes is never changed.
;   'dynamic' - the number of child processes is adjusted dynamically.
;   'ondemand' - the number of child processes is adjusted on demand.
pm = dynamic

; The default value is 'dynamic', and it depends on pm.max_children,
; pm.start_servers, pm.min_spare_servers and pm.max_spare_servers.
; If pm is set to 'static', this value is used directly.
; Default value: 0
pm.max_children = 100

; These values are used when pm is set to 'dynamic', and are ignored when 'static' or 'ondemand'.
; Number of child processes to start when pm is set to 'dynamic' or 'ondemand'.
; Default value: 5
pm.start_servers = 10

; Minimum number of child processes which should be kept active.
; Default value: 2
pm.min_spare_servers = 5

; Maximum number of child processes which should be kept active.
; Default value: 5
pm.max_spare_servers = 20

; The maximum number of requests each child process should execute before re-spawning.
; This can be useful to prevent memory leaks from accumulating over time.
; Default value: 0 (unlimited)
pm.max_requests = 500

; The TCP socket or the pipe address on which to listen.
; Default value: /run/php/php8.1-fpm.sock
; listen = /run/php/php8.1-fpm.sock

; If you are listening on a TCP socket, you can specify the address and port.
; listen = 127.0.0.1:9000

Nginx Server Block for Laravel

The Nginx server block should be configured to serve static assets directly and pass PHP requests to the PHP-FPM pool. Ensure fastcgi_read_timeout is set appropriately for long-running Laravel tasks (e.g., queue workers processing). A common value is 300 seconds, but this can be increased if necessary.

Nginx Site Configuration Example (/etc/nginx/sites-available/your_laravel_app)

server {
    listen 80;
    server_name your_domain.com www.your_domain.com;
    root /var/www/your_laravel_app/public; # Adjust to your Laravel public directory

    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Pass PHP scripts to FastCGI server
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # With php-fpm listening on a Unix socket:
        fastcgi_pass unix:/run/php/php8.1-fpm.sock; # Adjust to your PHP-FPM socket path
        # With php-fpm listening on TCP/IP:
        # fastcgi_pass 127.0.0.1:9000;

        # Increase timeout for long-running scripts
        fastcgi_read_timeout 300s; # 5 minutes
    }

    # Deny access to .htaccess files, if any
    location ~ /\.ht {
        deny all;
    }

    # Serve static files directly
    location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public";
        access_log off;
    }

    # Prevent access to hidden files
    location ~ /\. {
        deny all;
    }
}

Gunicorn Configuration for Python/Laravel (if applicable)

If your Laravel application is part of a larger Python ecosystem or uses Python for specific services, Gunicorn is a common WSGI HTTP Server. Nginx will act as a reverse proxy, forwarding requests to Gunicorn. The key is to configure Gunicorn’s worker processes and bind address.

Gunicorn Worker Processes and Threads

Gunicorn’s worker class and number of workers significantly impact performance. The sync worker class is the default and most basic. For I/O-bound applications, the gevent or eventlet worker classes (which use asynchronous I/O) can offer better concurrency. The number of workers is typically set to (2 * number_of_cores) + 1 as a starting point. Threads can be used with the gthread worker class.

Gunicorn Command Line Example

gunicorn --workers 4 --threads 2 --worker-class gevent --bind 0.0.0.0:8000 your_app.wsgi:application

In this example:

  • --workers 4: Sets 4 worker processes.
  • --threads 2: Sets 2 threads per worker (if using gthread worker class).
  • --worker-class gevent: Uses the gevent worker class for asynchronous I/O.
  • --bind 0.0.0.0:8000: Binds Gunicorn to all network interfaces on port 8000.
  • your_app.wsgi:application: Points to your application’s WSGI entry point.

Nginx Configuration for Gunicorn

Nginx will proxy requests to the Gunicorn server. It’s crucial to set appropriate timeouts and buffer sizes to prevent issues with long-running requests.

Nginx Server Block for Gunicorn

server {
    listen 80;
    server_name your_python_app.com www.your_python_app.com;

    location / {
        proxy_pass http://127.0.0.1:8000; # Matches Gunicorn's bind address
        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;

        # Timeouts for proxying
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s; # Crucial for long-running requests
    }

    # Serve static files directly if Gunicorn is not handling them
    location /static/ {
        alias /path/to/your/app/static/; # Adjust to your static files directory
        expires 1y;
        add_header Cache-Control "public";
    }

    location /media/ {
        alias /path/to/your/app/media/; # Adjust to your media files directory
        expires 1y;
        add_header Cache-Control "public";
    }
}

MongoDB Tuning for Laravel Applications

Optimizing MongoDB involves several aspects, from schema design to server configuration. For Laravel applications, common bottlenecks include inefficient queries, lack of proper indexing, and insufficient server resources.

Indexing Strategies

The most impactful optimization is proper indexing. Analyze your application’s queries using MongoDB’s explain() method. Identify slow queries in the MongoDB logs (if enabled) or via monitoring tools.

Identifying Slow Queries

# Connect to MongoDB
mongo

# Enable slow query logging (e.g., log queries slower than 100ms)
db.setProfilingLevel(1, 100)

# Perform application actions that trigger slow queries

# View slow queries
db.system.profile.find().pretty()

# Disable profiling when done
db.setProfilingLevel(0)

Once slow queries are identified, create appropriate indexes. For example, if you frequently query a `users` collection by `email` and `status`:

Creating Compound Indexes

db.users.createIndex( { email: 1, status: 1 } )

Consider the order of fields in compound indexes based on query selectivity and sort order. Use tools like mongodbatlas.com/tools/db-schema-advisor for schema analysis and index recommendations.

MongoDB Server Configuration (mongod.conf)

Key parameters in mongod.conf affect performance and stability. On AWS EC2 instances, ensure you’re using appropriate instance types (e.g., memory-optimized or storage-optimized) and EBS volumes (e.g., `gp3` or `io1` for higher IOPS).

Key `mongod.conf` Parameters

# mongod.conf

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
  # For SSDs, consider WiredTiger with compression
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 0.75 # Example: 75% of available RAM, adjust based on system usage

# network interfaces
net:
  port: 27017
  bindIp: 0.0.0.0 # Or specific IPs for security

# logging
systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true
  verbosity: 0 # Increase for debugging, decrease for production

# operation profiling
# profiling:
#   slowOpThresholdMs: 100 # Log operations slower than 100ms
#   mode: slowOp # Log only slow operations

# Sharding (if applicable)
# sharding:
#   clusterRole: configsvr
#   configsvrFile: /var/lib/mongodb/mongod.conf
#   configdb: your_mongos_host:27019

# Security (essential for production)
# security:
#   authorization: enabled

The cacheSizeGB parameter is crucial. It dictates the WiredTiger cache size. A common recommendation is to allocate 50-75% of the system’s RAM to the WiredTiger cache, leaving enough for the OS and other processes. Monitor memory usage closely.

Connection Pooling

Ensure your Laravel application is configured to use connection pooling for MongoDB. Libraries like jenssegers/mongodb typically handle this automatically, but verify the pool size settings. An insufficient pool size can lead to connection exhaustion under load.

Example (config/database.php for jenssegers/mongodb)

<?php

return [

    // ... other configurations

    'mongodb' => [
        'driver' => 'mongodb',
        'host' => env('DB_HOST', 'localhost'),
        'port' => env('DB_PORT', 27017),
        'database' => env('DB_DATABASE'),
        'username' => env('DB_USERNAME'),
        'password' => env('DB_PASSWORD'),
        'options' => [
            'database' => env('DB_DATABASE'), // This is the database name
            'ssl' => env('DB_SSL', false),
            'replicaSet' => env('DB_REPLICA_SET'),
            'poolsize' => env('DB_POOL_SIZE', 5), // Default pool size, adjust as needed
        ],
    ],

    // ... other configurations
];

Adjust poolsize based on your application’s concurrency and MongoDB’s connection limits. Monitor the number of active connections in MongoDB.

AWS Specific Considerations

On AWS, leverage managed services where possible (e.g., Amazon RDS for relational databases, Amazon ElastiCache for caching). For self-managed MongoDB, consider:

  • EC2 Instance Types: Choose instance types that match your workload (e.g., m5 for general purpose, r5 for memory-intensive, i3 for I/O intensive).
  • EBS Volumes: Use gp3 for a good balance of performance and cost, or io1/io2 for demanding workloads requiring provisioned IOPS.
  • Network Configuration: Ensure security groups allow necessary traffic between your application servers and MongoDB instances. Use VPC endpoints for private connectivity.
  • Monitoring: Utilize Amazon CloudWatch for metrics on CPU, memory, disk I/O, and network traffic. Set up alarms for critical thresholds.

For MongoDB, consider Amazon DocumentDB if you want a managed, highly available, and scalable MongoDB-compatible database service. It offloads operational burdens like patching, backups, and scaling.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Orchestrating Microservices with Docker Swarm: A Deep Dive into High Availability and Scalability for Laravel Applications
  • Leveraging PHP 8.3 JIT and FFI for High-Performance Microservices with Laravel Octane and Docker Swarm
  • Leveraging PHP 8.3 JIT and Vector API for Sub-Millisecond WordPress REST API Responses with Laravel Octane
  • Orchestrating Serverless PHP 9 with AWS Lambda and API Gateway: A Deep Dive into Performance and Cost Optimization
  • Leveraging PHP 8.3 JIT and Vectorization for Extreme Performance in Laravel Applications

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (664)
  • Desktop Applications (14)
  • DevOps (12)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (6)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • Performance & Security Optimization (1)
  • PHP (20)
  • PHP Development (49)
  • Plugins & Themes (244)
  • Programming Languages (10)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (650)
  • SEO & Growth (492)
  • Server (118)
  • Softwares (1)
  • Ubuntu (9)
  • Uncategorized (27)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (26)
  • WordPress Plugin Development (728)
  • WordPress Theme Development (357)

Recent Posts

  • Orchestrating Microservices with Docker Swarm: A Deep Dive into High Availability and Scalability for Laravel Applications
  • Leveraging PHP 8.3 JIT and FFI for High-Performance Microservices with Laravel Octane and Docker Swarm
  • Leveraging PHP 8.3 JIT and Vector API for Sub-Millisecond WordPress REST API Responses with Laravel Octane

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (728)
  • Debugging & Troubleshooting (664)
  • Security & Compliance (650)
  • SEO & Growth (492)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala