Server Optimization

PHP configuration

For file uploads to work, PHP must be configured properly. The following PHP configuration variables may need to be set or configured, in your PHP php.ini file, .htaccess file, or settings.php files.

  • file_uploads = On must be set to "On"
  • upload_max_filesize = 24M can't be larger than post_max_size
  • max_input_time = 300 small values may cause timeouts for large file uploads
  • memory_limit = 64M small values may cause out of memory errors for large file uploads
  • max_execution_time = 180 small values may cause timeouts for large file uploads
  • post_max_size = 24M limits the size of input submitted to the website (including attached files)

 

change the error reporting (so that notices aren't shown any longer):

[...]
;error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
error_reporting = E_ALL & ~E_NOTICE
[...]

 

 

https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfa...

; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is.  For more information on PATH_INFO, see the cgi specs.  Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec.  A setting
; of zero causes PHP to behave as before.  Default is 1.  You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://www.php.net/manual/en/ini.core.php#ini.cgi.fix-pathinfo
cgi.fix_pathinfo=0

 

Passing Uncontrolled Requests to PHP

Many example NGINX configurations for PHP on the web advocate passing every URI ending in .php to the PHP interpreter. Note that this presents a serious security issue on most PHP setups as it may allow arbitrary code execution by third parties.

The problem section usually looks like this:

location ~* \.php$ {
    fastcgi_pass backend;
    # [...]
}

Here, every request ending in .php will be passed to the FastCGI backend. The issue with this is that the default PHP configuration tries to guess which file you want to execute if the full path does not lead to an actual file on the filesystem.

For instance, if a request is made for /forum/avatar/1232.jpg/file.php which does not exist but if /forum/avatar/1232.jpg does, the PHP interpreter will process /forum/avatar/1232.jpg instead. If this contains embedded PHP code, this code will be executed accordingly.

Options for avoiding this are:

  • Set cgi.fix_pathinfo=0 in php.ini. This causes the PHP interpreter to only try the literal path given and to stop processing if the file is not found.

 

 

Very useful command to check running processes

 

PHP-FPM Configuration

 

php-fpm -tt

 

/etc/php-fpm.d/www.conf

/etc/php-fpm.conf

https://devcoops.com/how-to-determine-the-correct-number-of-max-child-pr...

https://tideways.com/profiler/blog/an-introduction-to-php-fpm-tuning

 

Modify and rotate

pm.max_children = 100 # The hard-limit total number of processes allowed
pm.start_servers = 20 # When php-fpm starts, have this many processes waiting for requests
pm.min_spare_servers = 10 # Number spare processes php-fpm will create
pm.max_spare_servers = 20 # Max number of spare (waiting for connections) processes allowed to be created
pm.process_idle_timeout = 10s;

 

 

 

 

Test for handling processes:

ab -n 1000 -c 10 http://localhost/index.php
ab -n 5000 -c 20 http://localhost/index.php

 

 

ab -n 10000 -c 200 http://localhost/index.php

 

 

RAM consumption

determine Memory_per_User-->

ps aux | awk 'NR != 1 {x[$1] += $4} END{ for(z in x) {print z, x[z]"%"}}'

  • ps -ylC httpd --sort:rss | awk '{sum+=$8; ++n} END {print "Tot="sum"("n")";print "Avg="sum"/"n"="sum/n/1024"MB"}'
  • ps -ylC httpd | awk '{x += $8;y += 1} END {print "Average Process Size (MB): "x/((y-1)*1024)}'f
  • ps -ylC httpd | awk '{x += $8;y += 1} END {print "Apache Memory Usage (MB): "x/1024; print "Average Proccess Size (MB): "x/((y-1)*1024)}'

sed -i 's|memory_limit = 128M|memory_limit = 256M|' /etc/php.ini

grep 'memory_limit' /etc/php.ini

multiple run:

sed -i 's|memory_limit = 512M|memory_limit = 256M|' /opt/php-5.6.40/lib/php.ini /opt/php-7.2.16/lib/php.ini /opt/php-7.3.3/php.ini /opt/php-7.3.3/lib/php.ini

 grep 'memory_limit' /opt/php-5.6.40/lib/php.ini /opt/php-7.2.16/lib/php.ini /opt/php-7.3.3/php.ini /opt/php-7.3.3/lib/php.ini


Decrease CPU load

  • yum install cpulimit
  • top
  •  then run your resource-intensive process (like opening many pages of your website at once)
  • and you'll see, which command devours all your resources (PID:__)
  • cpulimit --pid 31 --limit 86
  • cpulimit -e clamd -l 50

Tuning MySQL Performance


MySQLTuner is a Perl script that analyzes your MySQL performance and, based on the statistics it gathers, gives recommendations which variables you should adjust in order to increase performance. That way, you can tune your my.cnf file to tease out the last bit of performance from your MySQL server and make it work more efficiently.e with MySQLTuner

You can download the MySQLTuner script as follows:

wget http://drupal.mamatuik.com/PALS/public/CENTOS7/mysqltuner.pl

In order to run it, we must make it executable:

chmod +x mysqltuner.pl

Afterwards, we can run it. You need your MySQL root password for it:

./mysqltuner.pl

/etc/my.cnf[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd

max_allowed_packet=32M

#Configure tmp_table_size and max_heap_table_size
#Both directives should have the same size and will help you prevent disk writes. The tmp_table_size is the maximum amount of size of internal in-memory tables. In case the limit in question is exceeded the table will be converted to on-disk MyISAM table.
max_heap_table_size = 32M
tmp_table_size = 32M

max_connections = 50
thread_cache_size = 50

#query_cache_size=SIZE
#The amount of memory (SIZE) allocated for caching query results.
#The default value is 0, which disables the query cache.

#query_cache_type=OPTION
#Set the query cache type. Possible options are as follows:
#0 : Don't cache results in or retrieve results from the query cache.
#1 : Cache all query results except for those that begin with SELECT S_NO_CACHE.
#2 : Cache results only for queries that begin with SELECT SQL_CACHE
query_cache_size = 16M
query_cache_type = 1
query_cache_limit = 256K
query_cache_min_res_unit = 2k

interactive_timeout = 60
wait_timeout = 60
connect_timeout = 60

[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid

#
# include all files from the config directory
#
!includedir /etc/my.cnf.d

[mysqldump]
quick
max_allowed_packet = 32M

[mysql]
no-auto-rehash
default-character-set = utf8mb4
 
/etc/php.ini

;;;;;;;;;;;;;;;;;;;
; Resource Limits ;
;;;;;;;;;;;;;;;;;;;

;This sets the maximum time in seconds a script is allowed to run before it is terminated by the parser. This helps prevent poorly written scripts from tying up the server.
max_execution_time = 240

;This sets the maximum time in seconds a script is allowed to parse input data, like POST and GET. Timing begins at the moment PHP is invoked at the server and ends when execution begins.
max_input_time = 240

;This sets the maximum amount of memory in bytes that a script is allowed to allocate. This helps prevent poorly written scripts for eating up all available memory on a server.
memory_limit = 512M

;;;;;;;;;;;;;;;;;
; Data Handling ;
;;;;;;;;;;;;;;;;;

; Maximum size of POST data that PHP will accept.
; Its value may be 0 to disable the limit. It is ignored if POST data reading
; is disabled through enable_post_data_reading.

;This setting also affects file upload. To upload large files, this value must be larger than upload_max_filesize. Generally speaking, memory_limit should be larger than post_max_size.
post_max_size = 256M

;;;;;;;;;;;;;;;;
; File Uploads ;
;;;;;;;;;;;;;;;;

; Maximum allowed size for uploaded files.
; http://php.net/upload-max-filesize

upload_max_filesize = 128M

; Maximum number of files that can be uploaded via a single request
max_file_uploads = 50

;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;

;IonCube Loader
zend_extension=/usr/lib64/php/modules/ioncube/ioncube_loader_lin_5.4.so

extension=uploadprogress.so
extension=imagick.so

;;;;;;;;;;;;;;;;;;;
;The Alternative PHP Cache (APC) is a free and open opcode cache for PHP.
; Its goal is to provide a free, open, and robust framework for caching and optimizing PHP intermediate code.
;Alternatives to this extension are OPcache, APCu, Windows Cache for PHP
;and the Session Upload Progress API.  
;;;;;;;;;;;;;;;;;;;
extension=apc.so
apc.enabled=1
apc.shm_size=128M
apc.ttl=0
apc.user_ttl=600
apc.gc_ttl=600
;apc.enable_cli=1
apc.enable_cli=off
apc.mmap_file_mask=/tmp/apc.XXXXXX
;apc.mmap_file_mask=/dev/zero
;apc.shm_segments = 5
 

/etc/php.d/solr.iniextension=solr.so

 

  •  Virtual Host Files

A method of adding virtual host containers to the Apache configuration is by using virtual host files. This is described in more detail in ApacheVhostDir.

If inserting as first host, name the file something that shows first in a directory listing, like 0Default.conf.

If adding a catch all virtual host, name the file something that will always be listed last, like zDefault.conf.

  •  First Virtual Host (0Default.conf)

As a first virtual host, the ServerName should be something specific that is not actually used. It can be as simple as:

<VirtualHost *:80>
  ServerName fail
</VirtualHost>

  •  Last Virtual Host (zDefault.conf)

As a catch all virtual host, it should match everything. This can done with:

<VirtualHost *:80>
  ServerAlias *
</VirtualHost>

  •  Restart Apache

To make your changes take effect, restart Apache.

service httpd graceful

 

Rest of the Server Performance


 

Solr/etc/default/solr.in.sh
SOLR_JAVA_MEM="-Xms256m -Xmx512m"

 

Multi-Processing Module

nano /etc/httpd/conf.modules.d/00-mpm.conf
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
LoadModule mpm_event_module modules/mod_mpm_event.s
o

nano /etc/httpd/conf.d/php.conf {php-fpm}
<Directory /usr/share>
<FilesMatch \.php$>
#    SetHandler application/x-httpd-php
  SetHandler "proxy:fcgi://127.0.0.1:9000"
#  SetHandler proxy:fcgi://php-fpm
</FilesMatch>
</Directory>

nano /etc/phpMyAdmin/config.inc.php
$cfg['Servers'][$i]['auth_type']     = 'cookie';
 

Mailman
/etc/httpd/conf.d/mailman.conf:

#ScriptAlias /cgi-bin/mailman/ /usr/lib/mailman/cgi-bin/
PHP-configuration/etc/httpd/conf.d/php.conf:
#php_value session.save_handler "files"
#php_value session.save_path    "/var/lib/php/session"
httpd -V
 
AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/httpd/conf/httpd.conf:367
AH00513: WARNING: MaxRequestWorkers of 30 is not an integer multiple of
 ThreadsPerChild of 25, decreasing to nearest multiple 25,
 for a maximum of 1 servers.
Server version: Apache/2.4.6 (CentOS)
Server built:   Nov  5 2018 01:47:09
Server's Module Magic Number: 20120211:24
Server loaded:  APR 1.4.8, APR-UTIL 1.5.2
Compiled using: APR 1.4.8, APR-UTIL 1.5.2
Architecture:   64-bit
Server MPM:     event
  threaded:     yes (fixed thread count)
    forked:     yes (variable process count)
Server compiled with....

systemctl restart httpd php-fpm && systemctl enable httpd php-fpm

service php-5.6.40-fpm restart
service php-7.3.3-fpm restart
service php-7.2.16-fpm restart
service httpd restart
 

Allocate RAM wisely for Apache


/etc/httpd/conf/httpd.conf
<IfModule mpm_event_module>
    StartServers 3
    MinSpareThreads          25
    MaxSpareThreads          75
    ThreadLimit                      64
    ThreadsPerChild          25
    MaxRequestWorkers    30
    MaxConnectionsPerChild    1000
</IfModule>
ps -ylC httpd | awk '{x += $8;y += 1} END {print "Average Process Size (MB): "x/((y-1)*1024)}'fget average process' SIZE = 18.6659
ServerLimit=RAM/2 or better (RAM - reserved memory)
let's assume, reserved memory: 512MB
MaxClients = 512/18.7=27
dmidecode -t 17
dmidecode --type memory
RAM information
/etc/httpd/conf/httpd.conf

<IfModule prefork.c>
# <IfModule mpm_prefork_module>
# LoadModule cgi_module modules/mod_cgi.so
StartServers 5
# MinSpareServers    6
# VPS  5
MinSpareServers    8
MaxSpareServers   13
ServerLimit 512
MaxClients       27
MaxRequestWorkers 512
# defualt - MaxConnectionsPerChild 0
MaxConnectionsPerChild 1000
# apache 2.2 value of  MaxConnectionsPerChild - MaxRequestsPerChild 100
</IfModule>

list the currently
loaded modules with:
httpd -M

Test for server speed

ab -n 1000 -c 20 http://localhost/index.php

Vultr

iptables -A INPUT -s 127.0.0.1 -i eth1 -p tcp -m state --state NEW -m tcp --dport 11211 -j ACCEPT

iptables -I INPUT 1 -m tcp -p tcp --dport 111 -j DROP

iptables -I INPUT 1 -m udp -p udp --dport 111 -j DROP

Networking Tuning Tips

echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter

cat /etc/sysctl.conf

# Red Hat recommends not using multiple interfaces in the same network segment.
# However, if this is unavoidable, you can use arp_filter to prevent ARP Flux
# https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html
/virtualization_tuni$
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0

marked "red" - is an additional setting

== Portmapper servers ==


Portmapper is a service usually used with NFS.  When this is not properly firewalled, it can be abused to conduct DDOS attacks.  We recommend that all portmapper services be behind a firewall, and restricted to only IPs that need to contact them.

For Linux machines, please add firewall rules to block port 111 on both UDP and TCP:

iptables -I INPUT 1 -m tcp -p tcp --dport 111 -j DROP
iptables -I INPUT 1 -m udp -p udp --dport 111 -j DROP

Please see https://blog.cloudflare.com/reflections-on-reflections/ for more information on reflection attacks.