Nginx + PHP-FPM


Optimized for Wordpress on 1CPU + 1GB Mem

/etc/php-fpm.d/www.conf
[www]
user = nobody
group = mobody
listen = 127.0.0.1:9000
listen.owner = nobody
listen.group = nobody
listen.mode = 0664
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 20
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 5
pm.process_idle_timeout = 3s;
pm.max_requests = 500

pm.status_path=/fpm-status
ping.path=/fpm-ping

;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
slowlog = /var/log/php-fpm/www-slow.log
;request_slowlog_timeout = 0
request_terminate_timeout = 0
;rlimit_files = 1024
;rlimit_core = 0

php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 256M

php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[soap.wsdl_cache_dir]  = /var/lib/php/wsdlcache
php_value[opcache.file_cache]  = /var/lib/php/opcache
/etc/nginx/nginx.conf
user nginx;
worker_processes  auto;
worker_rlimit_nofile 65535;
pid /var/run/nginx.pid;

events {
    use epoll;
    worker_connections  4096;
    multi_accept        on;
}


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

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log                  off;
    error_log                   off;

    sendfile       on;
    sendfile_max_chunk  128k;

    tcp_nopush     on;
    tcp_nodelay    on;
    reset_timedout_connection       on;
    client_header_timeout           3;
    client_body_timeout             5;
    send_timeout                    3;
    client_header_buffer_size       2k;
    client_body_buffer_size         256k;

    gzip                on;
    gzip_comp_level     1;
    gzip_min_length     512;
    gzip_buffers        8 64k;
    gzip_types text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
    gzip_proxied        any;

    server_tokens off;

    include /etc/nginx/conf.d/*.conf;
}
cat /etc/nginx/conf.d/10-yoursite-com.conf
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
limit_req_status 444;

server {
    listen 80;
    listen 443 ssl http2;

	limit_req zone=one burst=5;
	
    ssl_trusted_certificate /etc/nginx/ssl/letencrypt-root.crt;
    ssl_certificate         /var/lib/acme/live/fserver.ru/fullchain;
    ssl_certificate_key     /var/lib/acme/live/fserver.ru/privkey;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl_prefer_server_ciphers on;
    ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA512:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:ECDH+AESGCM:ECDH+AES256:DH+AESGCM:DH+AES256:RSA+AESGCM:!aNULL:!eNULL:!LOW:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
    ssl_session_cache shared:TLS:2m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload' always;

    server_name fserver.ru www.fserver.ru;

    access_log /var/log/nginx/access-fserver.log main;
    error_log /var/log/nginx/error-fserver.log info;

    set $basedir "/data/sites/fserver.ru";
    root $basedir/htdocs;

    client_max_body_size 200m;
    index index.php index.html index.htm;

    location /.well-known/acme-challenge/ { alias /data/.acme/; }
	
    if ($scheme = http) {
        return 301 https://$server_name$request_uri;
    }

    sub_filter 'http://' '//';
    sub_filter_types text/css text/javascript;
    sub_filter_once off;
	
    location ~ /\. { deny all; }	
    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }

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

    location = /wp-login.php {
        limit_req zone=one burst=1 nodelay;
		fastcgi_pass    127.0.0.1:9000;
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PHP_VALUE         "open_basedir=$basedir;";
    }
    rewrite /wp-admin$ $scheme://$host$uri/ permanent;

    location ~ \.php$ {
        try_files $uri =404;
		fastcgi_pass    127.0.0.1:9000;		
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PHP_VALUE         "open_basedir=$basedir;";		
    }

    location ~* \.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
        expires max;
    }
    location = /robots.txt {
        access_log off;
        log_not_found off;
    }
    location = /favicon.ico {
        access_log off;
        log_not_found off;
    }
    error_page 404 /index.php;
}


/etc/my.cnf
[mysqld]
port            = 3306
socket          = /var/lib/mysql/mysql.sock
skip_name_resolve
skip-external-locking
open_files_limit       = 65535
lower_case_table_names = 1
symbolic-links=0

server-id       = 1
default_storage_engine=InnoDB

max_connections         = 10000
connect_timeout         = 5
wait_timeout            = 600
max_allowed_packet      = 16M
thread_cache_size       = 128
sort_buffer_size        = 4M
bulk_insert_buffer_size = 16M
tmp_table_size          = 32M
max_heap_table_size     = 32M

key_buffer_size = 64M
sort_buffer_size = 8M

innodb_buffer_pool_size = 128M
innodb_log_buffer_size  = 4M
innodb_file_per_table   = 1
innodb_open_files       = 4000
innodb_io_capacity      = 4000
innodb_flush_method     = O_DIRECT

Zabbix monitoring

- template.nginx.xml
- template.php-fpm.xml

vi /etc/zabbix/zabbix_agentd.d/nginx-php-fpm.conf
# nginx
UserParameter=nginx.status.active,  /usr/bin/curl -s "http://localhost:80/status" 2>/dev/null| grep Active | awk '{print $3}'
UserParameter=nginx.status.accepts, /usr/bin/curl -s "http://localhost:80/status" 2>/dev/null| awk NR==3 | awk '{print $1}'
UserParameter=nginx.status.handled, /usr/bin/curl -s "http://localhost:80/status" 2>/dev/null| awk NR==3 | awk '{print $2}'
UserParameter=nginx.status.requests,/usr/bin/curl -s "http://localhost:80/status" 2>/dev/null| awk NR==3 | awk '{print $3}'
UserParameter=nginx.status.reading, /usr/bin/curl -s "http://localhost:80/status" 2>/dev/null| grep 'Reading' | awk '{print $2}'
UserParameter=nginx.status.writing, /usr/bin/curl -s "http://localhost:80/status" 2>/dev/null| grep 'Writing' | awk '{print $4}'
UserParameter=nginx.status.waiting, /usr/bin/curl -s "http://localhost:80/status" 2>/dev/null| grep 'Waiting' | awk '{print $6}'

# php-fpm
UserParameter=php-fpm.status[*],/usr/bin/curl -s http://localhost:80/fpm-status | grep "$(echo '$1' | sed 's/-/ /g')" | cut -d : -f 2 | awk '{print $$1}'