Server Configuration and Tuning for Optimal Server Performance

Here is a summary of server configuration for optimal server performance, site speed, and security for a single ecommerce site dedicated server with 16GB RAM.

File locations are based on

  • cPanel EA4
  • Apache 2.4 Event MPM
  • PHP 7.3 PHP-FPM
  • MariaDB 10.3

All configuration values are defined and tuned based on our actual website usages. E.g. opcache usage, number of PHP files, realpath cache usage, etc.

Apache (/usr/local/apache/conf/httpd.conf)

# Via EasyApache 4

# Apache MPM
mod_mpm_event

# Apache Modules
mod_brotli
mod_bwlimited
mod_cgid
mod_deflate
mod_env
mod_expires
mod_headers
mod_http2
mod_mpm_event
mod_proxy
mod_proxy_fcgi
mod_proxy_http
mod_proxy_wstunnel
mod_security2
mod_ssl
mod_unique_id
# Via Apache Configuration > Global Configuration

# https://wiki.mozilla.org/Security/Server_Side_TLS
SSL Cipher Suite: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384

SSL/TLS Protocols: -all +TLSv1.2 +TLSv1.3
SSL Use Stapling: On
Extended Status: Off
LogLevel: Warn
Trace Enable: Off
Server Signature: Off
Server Tokens: Product Only
File ETag: None
Directory “/” Options: FollowSymLinks
Keep-Alive: On
Keep-Alive Timeout: 15
Max Keep-Alive Requests: 200

# Via Include Editor > Pre VirtualHost Include > All Versions

<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
</IfModule>

<ifModule mod_headers.c>
Header unset ETag
FileETag None
Header append Vary "Accept-Encoding"

<filesMatch ".(ico|jpg|png|gif|webmanifest)$">
Header set Cache-Control "max-age=2592000, public"
</filesMatch>
<filesMatch ".(js|css)$">
Header set Cache-Control "max-age=604800, public"
Header set X-Content-Type-Options "nosniff"
</filesMatch>
<filesMatch ".(html|php|txt|xml)$">
Header set Cache-Control "private, must-revalidate"
Header always set Strict-Transport-Security "max-age=31536000; includeSubdomains; preload" env=HTTPS
Header always set X-Xss-Protection "1"
Header always set Feature-Policy "microphone 'none'; autoplay 'none'"
Header always set Content-Security-Policy "upgrade-insecure-requests"
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options sameorigin
Header set Referrer-Policy "no-referrer-when-downgrade"
Header append Vary User-Agent
</filesMatch>
</ifModule>

<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType text/html "access plus 1 seconds"
ExpiresByType text/xml "access plus 1 seconds"
ExpiresByType text/plain "access plus 1 seconds"
ExpiresByType application/xml "access plus 1 seconds"
ExpiresByType application/json "access plus 1 seconds"
ExpiresByType text/css "access plus 1 week"
ExpiresByType text/javascript "access plus 1 week"
ExpiresByType application/javascript "access plus 1 week"
ExpiresByType application/x-javascript "access plus 1 week"
ExpiresByType image/x-ico "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
</IfModule>

PHP

# Via EasyApache 4

# PHP Extensions
php73-pear
php73-php-cli
php73-php-common
php73-php-curl
php73-php-devel
php73-php-fpm
php73-php-ftp
php73-php-gd
php73-php-iconv
php73-php-litespeed
php73-php-mbstring
php73-php-mysqlnd
php73-php-opcache
php73-php-pdo
php73-php-posix
php73-php-pspell
php73-php-xml
php73-runtime
# Via MultiPHP INI Editor

[PHP]
output_buffering = 4096
zlib.output_compression = Off
expose_php = Off
memory_limit = 256M
track_errors = Off
variables_order = "GPCS"
register_argc_argv = Off
enable_dl = Off
realpath_cache_size = 512K
realpath_cache_ttl = 86400
allow_url_include = Off
max_input_vars = 3000

session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
session.use_cookies = 1
session.use_only_cookies = 1
session.use_strict_mode = 1

[mysqlnd]
mysqlnd.collect_statistics = Off
mysqlnd.collect_memory_statistics = Off

PHP Opcache

# /opt/cpanel/ea-php73/root/etc/php.d/10-opcache.ini

zend_extension=opcache.so
opcache.enable=1
;opcache.enable_cli=0
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
;opcache.max_wasted_percentage=5
;opcache.use_cwd=1
opcache.validate_timestamps=0
;opcache.revalidate_freq=2
;opcache.revalidate_path=0
opcache.save_comments=0
;opcache.fast_shutdown=0
opcache.enable_file_override=1
;opcache.optimization_level=0xffffffff
;opcache.inherited_hack=1
;opcache.dups_fix=0
opcache.blacklist_filename=/opt/cpanel/ea-php73/root/etc/php.d/opcache*.blacklist
;opcache.max_file_size=0
;opcache.consistency_checks=0
;opcache.force_restart_timeout=180
;opcache.error_log=
;opcache.log_verbosity_level=1
;opcache.preferred_memory_model=
;opcache.protect_memory=0
;opcache.restrict_api=
;opcache.file_cache=
;opcache.file_cache_only=0
;opcache.file_cache_consistency_checks=1
opcache.huge_code_pages=0
opcache.validate_permission=0
# /opt/cpanel/ea-php73/root/etc/php.d/opcache-default.blacklist

/home/moddiy/public_html/temp/*
/home/moddiy/public_html/cache/*

PHP-FPM

# /var/cpanel/ApachePHPFPM/system_pool_defaults.yaml

pm: static
pm_max_children: 80
pm_max_requests: 1000
pm_process_idle_timeout: 10
pm_start_servers: 30

# /var/cpanel/ApachePHPFPM/system.yaml

emergency_restart_threshold: 10
emergency_restart_interval: 1m
process_control_timeout: 10s

MySQL/MariaDB (/etc/my.cnf)

[mysqld]
performance-schema=0
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
local-infile=0
bind-address=127.0.0.1
sql_mode=NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
tmpdir = /dev/shm
skip_external_locking = 1
skip_name_resolve = 1
max_connections = 180

query_cache_type=1
query_cache_size=128M
query_cache_limit=1M

join_buffer_size = 2M
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 2M

thread_cache_size=16K
tmp_table_size=16M
max_heap_table_size=16M
low_priority_updates=1
concurrent_insert=ALWAYS

key_buffer_size = 16M

max_allowed_packet=268435456
table_open_cache=1K
table_open_cache = 39390
table_definition_cache = 1024

## InnoDB
innodb_buffer_pool_size = 4096M
innodb_buffer_pool_instances = 4
innodb_file_per_table = 1
innodb_log_file_size = 512M
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 0
innodb-flush-method = O_DIRECT

default-storage-engine=MyISAM
open_files_limit=78780

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash

[isamchk]
key_buffer = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M

[myisamchk]
key_buffer = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout

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

DNS

Zone Time To Live (TTL) = 86400

CSF

USE_CONNTRACK = On
DENY_IP_LIMIT = 1000
DENY_TEMP_IP_LIMIT = 1000
LF_IPSET = On
LF_PERMBLOCK = On
LF_NETBLOCK = On
# /etc/csf/csf.blocklists

# AbuseIPDB blacklist
# Details: https://docs.abuseipdb.com/#blacklist-endpoint
ABUSEIPDB|86400|10000|https://api.abuseipdb.com/api/v2/blacklist?&key=<your-api-key>&plaintext

# Spamhaus Don't Route Or Peer List (DROP)
# Details: http://www.spamhaus.org/drop/
SPAMDROP|86400|0|http://www.spamhaus.org/drop/drop.lasso

# Spamhaus Extended DROP List (EDROP)
# Details: http://www.spamhaus.org/drop/
SPAMEDROP|86400|0|http://www.spamhaus.org/drop/edrop.lasso

# DShield.org Recommended Block List
# Details: http://dshield.org
DSHIELD|86400|0|http://www.dshield.org/block.txt

Leave a Reply

Your email address will not be published. Required fields are marked *