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

Vengala Vinay

Having 9+ 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 Google Cloud for Magento 2

The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and MongoDB on Google Cloud for Magento 2

Nginx Configuration for Magento 2 on Google Cloud

Optimizing Nginx is paramount for serving Magento 2 efficiently, especially on Google Cloud where network latency and resource availability are key factors. We’ll focus on tuning worker processes, caching mechanisms, and static file serving.

Nginx Worker Processes and Connections

The worker_processes directive controls how many worker processes Nginx spawns. A common recommendation is to set it to the number of CPU cores available. For Google Cloud Compute Engine instances, this can be dynamically determined or set to a fixed value based on your instance type. The worker_connections directive limits the number of simultaneous connections a worker can handle.

Edit your main Nginx configuration file (typically /etc/nginx/nginx.conf):

# Determine the number of CPU cores. For a 4-core instance, this would be 4.
# You can also use 'auto' if Nginx supports it on your version and OS.
worker_processes 4;

# Set the maximum number of open file descriptors per worker process.
# This should be set high enough to accommodate all expected connections.
# A common starting point is 1024, but it can be increased.
# Ensure your OS limits are also increased (e.g., via /etc/security/limits.conf).
worker_connections 4096;

# Enable the event-driven model for better scalability.
events {
    worker_connections 4096; # Redundant if set globally, but good practice
    multi_accept on;
    use epoll; # For Linux systems
}

# ... other Nginx configurations ...

After modifying nginx.conf, test the configuration and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

Nginx Caching Strategies

Leveraging Nginx’s built-in caching can significantly reduce load on your backend application servers (Gunicorn/FPM) and database. We’ll configure browser caching for static assets and potentially server-side caching for dynamic content (though Magento’s Varnish or Redis is often preferred for full-page caching).

Browser Caching for Static Assets

Set appropriate Cache-Control and Expires headers for static files like CSS, JS, images, and fonts. This is typically done within your Magento 2 site’s server block.

server {
    # ... other server configurations ...

    # Magento static files
    location ~ ^/static/.* {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
        log_not_found off;
    }

    # Magento media files
    location ~ ^/media/.* {
        expires 1y;
        add_header Cache-Control "public";
        access_log off;
        log_not_found off;
    }

    # Other static assets (e.g., favicon, robots.txt)
    location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1M;
        add_header Cache-Control "public";
        access_log off;
        log_not_found off;
    }

    # ... other location blocks ...
}

Nginx FastCGI Cache (Optional for Dynamic Content)

While Magento’s full-page cache is usually handled by Varnish or Redis, Nginx’s FastCGI cache can be a useful layer for specific API endpoints or less dynamic sections if Varnish is not in use. This requires enabling the ngx_http_fastcgi_cache_module.

# In nginx.conf or a separate conf file loaded by nginx.conf
fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=magento_cache:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 404 1m;
fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
fastcgi_cache_revalidate on;
fastcgi_cache_min_uses 1;
fastcgi_cache_lock on;

# In your Magento server block
location ~ \.php$ {
    # ... other fastcgi_pass and fastcgi_param directives ...

    fastcgi_cache magento_cache;
    fastcgi_cache_bypass $http_cache_control;
    fastcgi_cache_valid 200 302 10m; # Override global settings if needed
    add_header X-FastCGI-Cache $upstream_cache_status;

    # ... rest of fastcgi configuration ...
}

Remember to create the cache directory and set appropriate permissions:

sudo mkdir -p /var/cache/nginx/fastcgi
sudo chown www-data:www-data /var/cache/nginx/fastcgi # Or your Nginx user

Optimizing Static File Serving

Nginx is highly efficient at serving static files directly. Ensure that your Magento 2 pub/static and pub/media directories are configured to be served by Nginx, bypassing PHP entirely for these resources.

server {
    # ... other server configurations ...

    root /var/www/html/magento2; # Adjust to your Magento root directory
    index index.php index.html index.htm;

    # Serve static files directly
    location /pub/static/ {
        alias /var/www/html/magento2/pub/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
        log_not_found off;
        try_files $uri $uri/ /pub/static/index.php?$args; # Fallback for symlinks
    }

    location /pub/media/ {
        alias /var/www/html/magento2/pub/media/;
        expires 1y;
        add_header Cache-Control "public";
        access_log off;
        log_not_found off;
        try_files $uri $uri/ /pub/media/index.php?$args; # Fallback for symlinks
    }

    # Magento's front controller
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        # ... fastcgi_pass and other PHP-related directives ...
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_read_timeout 300; # Increase timeout for long-running PHP scripts
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Adjust to your PHP-FPM version and socket
    }

    # ... other configurations ...
}

The try_files directive is crucial. For static files, it attempts to serve the requested URI directly. If it’s a directory, it looks for an index file. The fallback to index.php is important for Magento’s symlink strategy for static content.

Gunicorn Configuration for Magento 2 (PHP-FPM Backend)

While Gunicorn is primarily a Python WSGI HTTP Server, it’s not directly used for PHP applications like Magento 2. Magento 2 typically runs with PHP-FPM. If you are using Gunicorn for a separate Python API or microservice that interacts with Magento, the tuning principles would apply to that specific application. For Magento 2, we focus on PHP-FPM.

PHP-FPM Tuning for Magento 2

PHP-FPM (FastCGI Process Manager) is the de facto standard for running PHP applications. Tuning its process management and resource allocation is critical for Magento 2’s performance.

Process Manager Settings

PHP-FPM offers several process management strategies: static, dynamic, and ondemand. For Magento 2, especially under heavy load, dynamic or static are generally preferred.

Edit your PHP-FPM pool configuration file (e.g., /etc/php/8.1/fpm/pool.d/www.conf):

; Choose a process management strategy. 'dynamic' is often a good balance.
; 'static' can offer more predictable performance but might waste resources.
; 'ondemand' is good for low-traffic sites but can cause latency on first request.
pm = dynamic

; For 'dynamic' pm:
; Minimum number of child processes.
pm.min_spare_servers = 3
; Maximum number of child processes. This is a critical tuning parameter.
; A common starting point is (number of CPU cores * 3) to (number of CPU cores * 5).
; Magento can be memory-intensive, so monitor memory usage.
pm.max_children = 100
; Number of max idle processes.
pm.max_spare_servers = 5

; For 'static' pm:
; pm.max_children = 50 ; Set to a fixed number based on your server's capacity.

; Process idle timeout.
pm.process_idle_timeout = 10s

; Maximum number of requests each child process should execute before respawning.
; This helps prevent memory leaks. A value between 500 and 1000 is common.
pm.max_requests = 500

; The user and group that will run the processes.
user = www-data
group = www-data

; The address on which to accept FastCGI requests.
; Use a Unix socket for better performance if Nginx and PHP-FPM are on the same server.
; listen = /var/run/php/php8.1-fpm.sock
; Or use a TCP socket if Nginx and PHP-FPM are on different servers.
; listen = 127.0.0.1:9000

; Set the listen permissions if using a Unix socket.
; listen.owner = www-data
; listen.group = www-data
; listen.mode = 0660

; Set environment variables if needed.
; env[MY_ENV_VAR] = 'value'

After changes, restart PHP-FPM:

sudo systemctl restart php8.1-fpm # Adjust version as needed

PHP Configuration Tuning

Beyond PHP-FPM, core PHP settings in php.ini significantly impact Magento 2 performance.

; Adjust memory limit based on Magento's requirements and server capacity.
; Magento can require a significant amount of memory, especially for complex operations.
memory_limit = 512M

; Maximum execution time for scripts. Magento cron jobs or complex page loads might need more.
max_execution_time = 300

; Maximum input variables. Magento uses many. Increase this substantially.
max_input_vars = 3000

; Maximum upload size.
upload_max_filesize = 64M
post_max_size = 64M

; Enable OPcache for significant performance gains.
; Ensure opcache.enable is set to 1.
opcache.enable=1
opcache.memory_consumption=128 ; Adjust based on your code base size
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60 ; Check for file updates every 60 seconds
opcache.validate_timestamps=1 ; Set to 0 in production for maximum performance if you have a robust deployment process
opcache.save_comments=1
opcache.enable_file_override=0
opcache.fast_shutdown=1

Locate your php.ini file (e.g., /etc/php/8.1/fpm/php.ini) and restart PHP-FPM after modifications.

MongoDB Tuning for Magento 2

Magento 2 uses MongoDB for session storage, caching, and catalog data (if configured). Optimizing MongoDB involves memory management, indexing, and connection pooling.

WiredTiger Storage Engine Configuration

The WiredTiger storage engine is the default and recommended engine. Its performance is heavily influenced by the storage.wiredTiger.engineConfig.cacheSizeGB setting.

Edit your MongoDB configuration file (typically /etc/mongod.conf):

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
  wiredTiger:
    engineConfig:
      # Allocate a significant portion of RAM to WiredTiger's cache.
      # A common recommendation is 50% of available RAM for dedicated MongoDB servers,
      # or less if running other services on the same instance.
      # For a 16GB RAM instance, this might be 8GB.
      cacheSizeGB: 8
    collectionConfig:
      # Compression can save disk space and I/O, but adds CPU overhead.
      # zlib is a good balance. snappy is faster but less compression.
      compression: zlib
    indexConfig:
      prefixCompression: true

# Network and security settings
net:
  port: 27017
  bindIp: 0.0.0.0 # Or specific IPs for security

# Logging settings
systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true
  verbosity: 0

# Process management
processManagement:
  fork: true
  pidFilePath: /var/run/mongodb/mongod.pid
  # Ensure the user and group are correct for your system
  # user: mongodb
  # group: mongodb

# Sharding settings (if applicable)
# sharding:
#   clusterRole: configsvr
#   configsvrFilePermissions:
#     groupReadable: true

Restart MongoDB after applying changes:

sudo systemctl restart mongod

MongoDB Indexing and Query Optimization

Proper indexing is crucial for fast query performance. Magento 2 relies on specific indexes for its operations. Regularly review and optimize these.

Connect to your MongoDB instance and check existing indexes:

mongo
use  # e.g., use magento_prod
db.getCollectionNames().forEach(function(collectionName) {
    print("Indexes for " + collectionName + ":");
    db[collectionName].getIndexes().forEach(function(index) {
        printjson(index);
    });
});

Magento’s default indexes are usually sufficient, but custom modules or specific usage patterns might require additional indexes. For example, if you frequently query the catalog_product_entity collection by SKU:

db.catalog_product_entity.createIndex( { sku: 1 }, { unique: true } )

Use MongoDB’s profiling tools to identify slow queries. Enable the profiler:

db.setProfilingLevel(1) // 0=off, 1=slow, 2=all
db.system.profile.find().pretty()

Analyze the output for queries exceeding your defined slow query threshold (default is 100ms) and add appropriate indexes.

Connection Pooling and MongoDB URI

Ensure your Magento 2 application is configured to use connection pooling. This is typically managed in app/etc/env.php.

<?php
return [
    'backend' => [
        'frontName' => 'admin_your_admin_path'
    ],
    'crypt' => [
        'key' => 'your_crypt_key'
    ],
    'db' => [
        'table_prefix' => ''
    ],
    'install' => [
        'date' => '2023-10-27 10:00:00'
    ],
    'modules' => [
        'Magento_Backend' => 1,
        // ... other modules
    ],
    'cache' => [
        'frontend' => [
            'default' => [
                'backend' => 'Magento\\Framework\\Cache\\Backend\\Redis',
                'options' => [
                    'report_buffer_size' => '10485760',
                    'compress_data' => '1',
                    'compression_lib' => '',
                    'max_concurrency' => '6',
                    'connect_retries' => '1',
                    'read_timeout' => '10',
                    'automatic_cleaning_factor' => '0',
                    'use_stale_backend' => '0',
                    'cache_id_prefix' => 'mage_'
                ]
            ],
            'page_cache' => [
                'backend' => 'Magento\\Framework\\Cache\\Backend\\Redis',
                'options' => [
                    'report_buffer_size' => '10485760',
                    'compress_data' => '1',
                    'compression_lib' => '',
                    'max_concurrency' => '6',
                    'connect_retries' => '1',
                    'read_timeout' => '10',
                    'automatic_cleaning_factor' => '0',
                    'use_stale_backend' => '0',
                    'cache_id_prefix' => 'mage_'
                ]
            ]
        ]
    ],
    'session' => [
        'save' => 'redis',
        'redis' => [
            'host' => '10.0.0.5', // Your Redis host for sessions
            'port' => 6379,
            'password' => '',
            'timeout' => '2.5',
            'persistent_identifier' => '',
            'database' => '0',
            'compression_threshold' => '2048',
            'compression_library' => '',
            'log_level' => '1',
            'max_concurrency' => '6',
            'break_after_frontend' => '5',
            'break_after_frontend_exception' => '0'
        ]
    ],
    'resource' => [
        'default_setup' => [
            'connection' => [
                'host' => '10.0.0.6', // Your MySQL host
                'dbname' => 'magento_prod',
                'username' => 'magento_user',
                'password' => 'your_db_password',
                'model' => 'mysql4',
                'initStatements' => 'SET NAMES utf8',
                'engine' => 'innodb',
                'active' => '1'
            ]
        ],
        'default' => [
            'connection' => [
                'host' => '10.0.0.6', // Your MySQL host
                'dbname' => 'magento_prod',
                'username' => 'magento_user',
                'password' => 'your_db_password',
                'model' => 'mysql4',
                'initStatements' => 'SET NAMES utf8',
                'engine' => 'innodb',
                'active' => '1'
            ]
        ]
    ],
    'Mage_Core_Model_File_Storage_Storage' => [
        'storage_config' => [
            'media_storage' => [
                'type' => 'local', // or 'cloud' for cloud storage
                'path' => 'media'
            ]
        ]
    ],
    'system' => [
        'default' => [
            'dev' => [
                'css' => [
                    'merge_css_files' => '1'
                ],
                'js' => [
                    'merge_files' => '1',
                    'enable_js_bundling' => '1'
                ]
            ]
        ]
    ],
    'http_client' => [
        'timeout' => '30',
        'user_agent' => 'Magento'
    ],
    'mongo' => [
        'connection' => [
            'host' => '10.0.0.7', // Your MongoDB host
            'port' => '27017',
            'username' => 'magento_user',
            'password' => 'your_mongo_password',
            'dbname' => 'magento_prod',
            'options' => [
                'replicaSet' => 'rs0', // If using replica set
                'authSource' => 'admin', // If auth is not on the dbName
                'connectTimeoutMS' => '5000',
                'socketTimeoutMS' => '5000',
                'w' => 'majority', // For write concern
                'readPreference' => 'primaryPreferred' // Or other read preferences
            ]
        ]
    ]
];

The options array in the mongo configuration is critical. Ensure connectTimeoutMS and socketTimeoutMS are set appropriately to prevent connection issues without introducing excessive delays. For replica sets, configure replicaSet and readPreference according to your availability and consistency needs.

Google Cloud Specific Considerations

When deploying on Google Cloud, consider the following:

  • Instance Sizing: Choose Compute Engine instances with sufficient vCPUs and RAM for your expected load. Monitor resource utilization (CPU, memory, network I/O) using Cloud Monitoring.
  • Persistent Disks: Use SSD Persistent Disks for MongoDB and your Magento application files for better I/O performance.
  • Network Latency: If your MongoDB instance is separate from your web servers, ensure they are in the same GCP region and preferably the same zone to minimize latency. Consider using Private Google Access for internal communication.
  • Load Balancing: Utilize Google Cloud Load Balancing to distribute traffic across multiple Nginx instances. Configure health checks to ensure traffic is only sent to healthy servers.
  • Managed Services: For MongoDB, consider using Google Cloud’s Memorystore for Redis (for caching/sessions) or exploring managed MongoDB solutions if self-management becomes too burdensome.
  • Firewall Rules: Configure GCP firewall rules to restrict access to your MongoDB port (27017) only from your application servers.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • Step-by-Step: Diagnosing indexing lock conflicts and high CPU during bulk stock updates on DigitalOcean Servers
  • How to Debug and Fix memory leaks and socket exhaustion in daemon processes in Modern C++ Applications
  • Infrastructure as Code: Provisioning Secure PHP Clusters on DigitalOcean Using Terraform
  • Fixing Slow Largest Contentful Paint (LCP) caused by unoptimized database queries in Legacy Laravel Codebases Without Breaking API Contracts
  • An Auditor’s Checklist for Securing Laravel Backends on Google Cloud

Copyright © 2026 · Vinay Vengala