• 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 PostgreSQL on DigitalOcean for Python

The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and PostgreSQL on DigitalOcean for Python

Nginx as a High-Performance Frontend Proxy

For Python web applications, Nginx serves as an indispensable frontend proxy, efficiently handling static file serving, SSL termination, and request routing to your application server (Gunicorn or PHP-FPM). Optimizing Nginx is crucial for overall system throughput and responsiveness.

Core Nginx Configuration Tuning

The primary configuration file, typically located at /etc/nginx/nginx.conf, contains global settings. We’ll focus on key directives within the http block.

Worker Processes and Connections

The worker_processes directive determines how many worker processes Nginx will spawn. Setting this to auto is generally recommended, allowing Nginx to detect the number of CPU cores and utilize them effectively. The worker_connections directive sets the maximum number of simultaneous connections that each worker process can handle. A common starting point is 1024, but this can be increased based on your server’s RAM and expected load.

Keepalive Connections

Enabling keepalive_timeout reduces the overhead of establishing new TCP connections for subsequent requests from the same client. A value between 65 and 75 seconds is a good balance, preventing resource exhaustion while still allowing clients to reuse connections.

Gzip Compression

Enabling Gzip compression significantly reduces the bandwidth required to transfer text-based assets (HTML, CSS, JavaScript, JSON). Configure it within the http block or a specific server block.

Example Nginx Configuration Snippets

Here are essential directives to include in your /etc/nginx/nginx.conf or a site-specific configuration file (e.g., /etc/nginx/sites-available/your_app).

Global HTTP Settings

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    tcp_nopush      on;
    tcp_nodelay     on;

    keepalive_timeout  75;
    keepalive_requests 1000;

    # Gzip Compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;

    # Increase open file limit
    worker_rlimit_nofile 65535;

    # Auto-detect worker processes
    worker_processes auto;

    # Max connections per worker
    # Adjust based on server RAM and expected load
    # Example: 4096 for a server with 8GB+ RAM
    events {
        worker_connections 4096;
    }

    # Include server blocks
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Proxying to Gunicorn (Python WSGI)

When using Gunicorn, Nginx acts as a reverse proxy, forwarding requests to the Gunicorn worker processes, typically listening on a local Unix socket or a TCP port.

Example Server Block for Gunicorn
server {
    listen 80;
    server_name your_domain.com www.your_domain.com;

    # Serve static files directly
    location /static/ {
        alias /path/to/your/app/static/;
        expires 30d;
        access_log off;
        add_header Cache-Control "public";
    }

    location /media/ {
        alias /path/to/your/app/media/;
        expires 30d;
        access_log off;
        add_header Cache-Control "public";
    }

    # Proxy all other requests to Gunicorn
    location / {
        proxy_pass http://unix:/run/gunicorn.sock; # Or http://127.0.0.1:8000;
        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;
    }

    # Optional: SSL configuration
    # listen 443 ssl http2;
    # server_name your_domain.com www.your_domain.com;
    # ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
    # ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
    # include /etc/letsencrypt/options-ssl-nginx.conf;
    # ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

Proxying to PHP-FPM (for PHP applications)

For PHP applications, Nginx communicates with PHP-FPM via a FastCGI socket.

Example Server Block for PHP-FPM
server {
    listen 80;
    server_name your_domain.com www.your_domain.com;
    root /var/www/your_app/public;
    index index.php index.html index.htm;

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

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # Adjust socket path based on your PHP-FPM configuration
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_read_timeout 300; # Increase timeout for long-running scripts
    }

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

    # Serve static files with caching
    location ~* \.(css|js|jpg|jpeg|gif|png|svg|ico|webp)$ {
        expires 30d;
        add_header Cache-Control "public";
        access_log off;
    }
}

Gunicorn Performance Tuning for Python Applications

Gunicorn (Green Unicorn) is a popular WSGI HTTP Server for Python. Its performance is heavily influenced by the number of worker processes, worker type, and timeout settings.

Worker Processes and Type

The --workers flag determines the number of worker processes. A common recommendation is (2 * CPU_CORES) + 1. For I/O-bound applications, consider using the gevent or event worker types, which are asynchronous and can handle more concurrent connections per process than the default sync worker.

Worker Timeout

The --timeout setting specifies how long Gunicorn will wait for a worker to process a request before killing it. This is crucial for preventing hung requests from blocking workers indefinitely. A value between 30 and 120 seconds is typical, depending on the expected complexity of your application’s requests.

Gunicorn Command Line Arguments

Here’s an example of how you might start Gunicorn, often managed by a process supervisor like systemd.

# Example systemd service file (/etc/systemd/system/gunicorn.service)
[Unit]
Description=Gunicorn instance to serve myapp
After=network.target

[Service]
User=your_app_user
Group=www-data
WorkingDirectory=/path/to/your/app
Environment="PATH=/path/to/your/venv/bin"
ExecStart=/path/to/your/venv/bin/gunicorn \
    --workers 3 \
    --worker-class gevent \
    --bind unix:/run/gunicorn.sock \
    --timeout 120 \
    --log-level info \
    --access-logfile - \
    --error-logfile - \
    your_app.wsgi:application

[Install]
WantedBy=multi-user.target

Note: Replace your_app.wsgi:application with the actual path to your WSGI application object.

PostgreSQL Performance Tuning

PostgreSQL’s performance is highly dependent on its configuration, especially memory allocation and query optimization. Tuning postgresql.conf is essential.

Key Configuration Parameters

These parameters are typically found in /etc/postgresql/[version]/main/postgresql.conf.

shared_buffers

This is the most critical parameter. It defines the amount of memory PostgreSQL dedicates to caching data. A common recommendation is 25% of your server’s total RAM. For a 16GB server, this would be 4GB.

work_mem

This parameter controls the amount of memory that can be used for internal sort operations and hash tables before spilling to disk. It’s allocated per operation, so setting it too high can lead to memory exhaustion if many complex queries run concurrently. Start with 16MB or 32MB and monitor. It can be set per session for specific queries.

maintenance_work_mem

This parameter is used for maintenance operations like VACUUM, CREATE INDEX, and ALTER TABLE ADD FOREIGN KEY. A larger value (e.g., 256MB to 1GB) can significantly speed up these operations. It’s less critical than work_mem as these operations are not as frequent.

effective_cache_size

This parameter informs the query planner about how much memory is available for disk caching by the operating system and PostgreSQL’s shared buffers. A good starting point is 50% to 75% of total RAM. It doesn’t allocate memory but influences query plan choices.

max_connections

The maximum number of concurrent connections. Ensure this is high enough for your application but not so high that it exhausts server memory. Each connection consumes memory. A typical value might be 100-200 for moderate applications.

shared_preload_libraries

Used to load shared libraries into PostgreSQL at startup. Essential for extensions like pg_stat_statements for query analysis.

Example `postgresql.conf` Snippets

# Example for a server with 16GB RAM
# Adjust based on your specific server resources and workload

# Memory Allocation
shared_buffers = 4GB
work_mem = 32MB
maintenance_work_mem = 512MB
effective_cache_size = 12GB # 75% of 16GB

# Connections
max_connections = 150
# Consider using a connection pooler like PgBouncer for high-traffic apps

# Logging
log_destination = 'stderr'
logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_min_duration_statement = 1000 # Log statements longer than 1 second
log_checkpoints = on
log_connections = on
log_disconnections = on
log_lock_waits = on
log_temp_files = 0 # Log all temporary files
log_autovacuum_min_duration = 0 # Log all autovacuum actions

# Background Writer & WAL
bgwriter_delay = 100ms
bgwriter_lru_maxpages = 1000
bgwriter_lru_multiplier = 1.0
bgwriter_flush_after = 1MB

wal_level = replica
wal_buffers = 16MB
wal_writer_delay = 200ms
checkpoint_timeout = 5min
max_wal_size = 4GB
min_wal_size = 1GB
checkpoint_completion_target = 0.9

# Autovacuum
autovacuum = on
autovacuum_max_workers = 3
autovacuum_naptime = 1min
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50
autovacuum_vacuum_scale_factor = 0.1 # 10% of table size
autovacuum_analyze_scale_factor = 0.05 # 5% of table size

# Extensions
shared_preload_libraries = 'pg_stat_statements'

Enabling `pg_stat_statements`

To effectively analyze query performance, enable the pg_stat_statements extension. After modifying postgresql.conf and restarting PostgreSQL, run the following SQL command in your database:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

You can then query this extension to find slow or frequently executed queries:

SELECT
    query,
    calls,
    total_exec_time,
    rows,
    mean_exec_time,
    stddev_exec_time
FROM
    pg_stat_statements
ORDER BY
    total_exec_time DESC
LIMIT 20;

Monitoring and Iterative Tuning

Performance tuning is an ongoing process. Implement robust monitoring to observe the impact of your changes and identify bottlenecks.

Key Metrics to Monitor

  • Nginx: Active connections, requests per second, error rates (5xx, 4xx), worker process CPU/memory usage.
  • Gunicorn: Worker process CPU/memory usage, request latency, number of active workers.
  • PostgreSQL: CPU utilization, memory usage (especially buffer cache hit ratio), disk I/O, active connections, query execution times (via pg_stat_statements), replication lag (if applicable).
  • System: Overall CPU, RAM, Disk I/O, Network traffic.

Tools for Monitoring

  • System Monitoring: htop, atop, Prometheus Node Exporter, Datadog Agent, New Relic Infrastructure.
  • Nginx Monitoring: Nginx Amplify, Prometheus Nginx Exporter, stub_status module.
  • Gunicorn Monitoring: Built-in logging, integration with APM tools (Datadog APM, New Relic APM).
  • PostgreSQL Monitoring: pg_stat_statements, pg_stat_activity, Prometheus PostgreSQL Exporter, pgAdmin, Datadog PostgreSQL integration.
  • APM (Application Performance Monitoring): Sentry, Datadog APM, New Relic APM for deep application-level insights.

After making configuration changes, always restart the relevant services (Nginx, Gunicorn, PostgreSQL) and observe the metrics. Make incremental adjustments and re-evaluate. For PostgreSQL, consider using tools like pgtune as a starting point, but always validate its recommendations against your specific hardware and workload.

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

  • Top 100 Developer Tooling and Productivity SaaS Ideas to Launch in 2026 to Boost Organic Search Growth by 200%
  • Top 100 Developer-Centric Code Snippet Managers and Customization Plugins to Double User Engagement and Session Duration
  • Top 5 API Monetization Frameworks and Gateway Strategies for Developers to Minimize Server Costs and Load Overhead
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Minimize Server Costs and Load Overhead
  • Top 50 Premium Newsletter and Subscription Business Models for Devs for High-Traffic Technical Portals

Categories

  • apache (1)
  • Business & Monetization (386)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (497)
  • DevOps (7)
  • DevOps & Cloud Scaling (922)
  • Django (1)
  • Migration & Architecture (86)
  • MySQL (1)
  • Performance & Optimization (643)
  • PHP (5)
  • Plugins & Themes (115)
  • Security & Compliance (525)
  • SEO & Growth (444)
  • Server (23)
  • Ubuntu (9)
  • WordPress (22)
  • WordPress Plugin Development (7)
  • WordPress Theme Development (62)

Recent Posts

  • Top 100 Developer Tooling and Productivity SaaS Ideas to Launch in 2026 to Boost Organic Search Growth by 200%
  • Top 100 Developer-Centric Code Snippet Managers and Customization Plugins to Double User Engagement and Session Duration
  • Top 5 API Monetization Frameworks and Gateway Strategies for Developers to Minimize Server Costs and Load Overhead
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Minimize Server Costs and Load Overhead
  • Top 50 Premium Newsletter and Subscription Business Models for Devs for High-Traffic Technical Portals
  • Top 100 SEO and Schema Markup Plugins for Headless Decoupled Sites for Independent Web Developers and Indie Hackers

Top Categories

  • DevOps & Cloud Scaling (922)
  • Performance & Optimization (643)
  • Security & Compliance (525)
  • Debugging & Troubleshooting (497)
  • SEO & Growth (444)
  • Business & Monetization (386)

Our Products

  • School Management & Student Administration System
  • Integrated Hospital & Clinic Management System
  • Real Estate Directory & Agent Portal
  • Restaurant POS & Table Booking System
  • Retail Inventory POS & Billing System
  • Pharmacy Inventory & Clinic Billing System

Our Services

  • Vibe Engineering & AI Code Auditing Services
  • Prompt Engineering & "Vibe Coding" Workflow Consulting
  • AI-Augmented "Vibe Coding" & Rapid MVP Development
  • Figma to Shopify Liquid Theme Customization
  • Figma to WooCommerce Frontend Development
  • Figma to Magento 2 Theme Development

Copyright © 2026 · Vinay Vengala