Should I use Nginx vs Apache?
Choosing a web server, should I use Nginx vs Apache?
July 30, 2019 | XEO
"I didn't switch to Nginx until I understood how it handled virtual hosts" - Xeo
What are Nginx and Apache?
Both Nginx and Apache are web servers which host your website on the server. They can also serve API and mobile applications. Nginx
goes a little further and can be a proxy, in fact it is used in CloudFlare and provides some of the clever features. Fundamentally a
web server reads the web site code from the disk and returns it to the web browser, potentially caching along the way. Each subdomain.domain.com
becomes its own Virtual Host and has a separate configurations; basically which folder to use for which domain.
Behind the web server is a multi-threaded model. There are several to choose from. PHP-FPM is the one XeoDev uses because it relies
on pipes for optimal internal communications and it is configurable based on web server capacity. Matching the multi-threaded model with
the web server provides the optimal result.
So how much faster is Nginx?
Looking at Nginx vs Apache performance, At a high level we are seeing about 1 full second performance improvements on each page load with Nginx + PHP-FPM over Apache with the default model. In addition, this performance was maintained well as more clients were added. But this is not a performance measurement blog. What this told us was we should make the switch because it was the best web server for our workload. Honestly, over the last year Nginx has failed with some strange CloudFlare errors so i make it easy to switch back to Apache.
How well does Nginx Work with Webpack?
We upgraded to webpack, using Laravel Mix, at the same time as we changed from Apache to Nginx. We saw significant wins from each upgrade. Webpack requires a build step during the deployment process and we had to upgrade several places in the JS layer where we were not declaring all variables. There were also some load order conditions to overcome which caused us to split out vendor.js from core.js to give the loading some flexibility. But those were solid refactoring improvements and the drop from so many individual files to 3 JS and 3 CSS files which are cached 99% of the time and then a handful of area specific JS files at one or two per page is much cleaner in the browser.
Nginx and Apache on same server
To benchmark Nginx vs Apache 2019 and compare them against each other we simply install both of them on the front end webserver. you have to run one at a time but if you find a configuration error and need to flip back to safety it just takes a service stop and service start command and you're good to go.
Nginx and Apache Wordpress
The basic Wordpress hosts use stock Apache which when you compare Nginx vs Apache in PHP you see the default Apache launch model is not optional for PHP. By switching to both FPM and Nginx you will see a significant performance boost over the standard GoDaddy configuration.
XeoDev Standard Nginx Installation
Note: this installation continues to have user apache be the web server user so it changes Nginx to apache in a few places
### install Nginx
sudo yum install Nginx -y
sudo chkconfig Nginx on
sudo service Nginx start
### install php71-fpm
sudo yum install php71-fpm
sudo chkconfig php-fpm on
sudo service php-fpm start
### Nginx config
cd /etc/Nginx
sudo vi Nginx.conf
--
user apache;
--
### configure fpm
sudo vi /etc/php-fpm.d/www.conf
Note: to fix ACL issue, comment out listen.acl_users = apache,Nginx
--
[global]
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s
[www]
listen = /var/run/php-fpm/www.sock
listen.owner = apache
listen.group = apache
listen.mode = 0664
user = apache
group = apache
;listen.acl_users = apache
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 200
php_admin_value[memory_limit] = 128M
--
sudo service php-fpm restart
XeoDev Standard Nginx Configuration
I do love Stack Overflow. But it frequently requires reading a dozen decent articles and harvesting answers that are not the checked answers
to get a complete solution. Especially a complete solution for the current year, which is 2019. So we decided to publish the configuration
we are using. Feel free to give us feedback using the contact us page (don't have reply working in this static blog).
The configuration design is to use a standards.inc, a fastcgi.inc and a series of *vhost*.conf files to handle each vhost. This way the vhost
files are less than one page and include the other two files making global changes require changing only the .inc file. Some of the lines
are commented out as we are still experimenting with them.
Standards.inc
#
# Standard stuff for all virtual hosts
#
# SSL config
# enable session resumption to improve https performance
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# limit SSL ciphers
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256";
ssl_prefer_server_ciphers on;
ssl_ecdh_curve secp384r1;
# DNS resolver choice
# resolver 8.8.8.8;
# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
# ssl_stapling on;
# ssl_stapling_verify on;
# security headers
# http security headers
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
#add_header Pragma no-cache;
#add_header Cache-Control no-store;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy origin-when-cross-origin;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Strict-Transport-Security "max-age=100000" always;
# nonce!!, upgrade-insecure-requests!!
add_header Content-Security-Policy "upgrade-insecure-requests";
#add_header Content-Security-Policy "upgrade-insecure-requests; default-src 'self'; base-uri 'self'; require-sri-for script; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' 'nonce-JjECqn6A' http: https:; object-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https: http:; media-src 'none'; frame-src 'self'; font-src 'self'; connect-src 'self' wss:; report-uri https://yourdomain.report-uri.com/r/d/csp/enforce;";
# Add Security cookie flags
#proxy_cookie_path ~(.*) "$1; SameSite=strict; secure; httponly";
# gzip
gzip on;
gzip_vary on;
gzip_comp_level 5;
gzip_min_length 10240;
gzip_proxied any;
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
gzip_disable "MSIE [1-6]\.";
# configure expires on headers
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf)$ {
expires 7d;
}
# Deny all attempts to access hidden files
# such as .htaccess, .htpasswd, .DS_Store (Mac), .git, .etc...
location ~ /\. {
deny all;
}
# Security Settings
## Start: Size Limits & Buffer Overflows ##
#client_body_buffer_size 1K;
#client_header_buffer_size 1k;
#client_max_body_size 1k;
#large_client_header_buffers 2 1k;
## End: Size Limits & Buffer Overflows ##
## - OR - ##
## Start: Allow 25 mb uploads ##
#client_body_buffer_size 1K;
#client_header_buffer_size 1k;
client_max_body_size 25m;
#large_client_header_buffers 2 1k;
## End: Allow 25 mb uploads ##
## Start: Timeouts ##
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 5 5;
send_timeout 10;
## End: Timeouts ##
### Directive describes the zone, in which the session states are stored i.e. store in slimits. ###
### 1m can handle 32000 sessions with 32 bytes/session, set to 5m x 32000 session ###
#limit_zone slimits $binary_remote_addr 5m;
### Control maximum number of simultaneous connections for one session i.e. ###
### restricts the amount of connections from a single ip address ###
#limit_conn slimits 5;
# Block robots by user agent
## Block some robots ##
if ($http_user_agent ~* msnbot|scrapbot) {
return 403;
}
Fastcgi.inc
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE Nginx/$Nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_index index.php;
fastcgi_param REDIRECT_STATUS 200;
{vhost}.conf
#
# A virtual host using mix of IP-, name-, and port-based configuration
#
server {
listen 80;
listen [::]:80;
server_name sub.domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
access_log /var/log/httpd/access-sub-domain.log;
error_log /var/log/httpd/error-sub-domain.log error;
server_name next.collegefitfinder.com;
root /var/www/vhosts/next-collegefitfinder/public;
index index.php;
ssl on;
ssl_certificate /etc/pki/tls/certs/domain.crt;
ssl_certificate_key /etc/pki/tls/private/domain.key;
include conf.d/standards.inc;
# password protect this staging server
auth_basic "Secure Area";
auth_basic_user_file conf.d/htpasswd_domain.com;
location / {
root /var/www/vhosts/sub-domain/public;
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/www.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include conf.d/fastcgi.inc;
}
}
Other Config Changes
Made these permission changes because i'm running with the apache user since this way we can switch back and forth to apache.
sudo chown apache:root /var/lib/Nginx
sudo chown apache:root /var/lib/Nginx/tmp
About XeoDev
During the post mortem meeting on the release one of the client partners raise this high compliment for the XeoDev co-founders: 'David contributed as if he were a founder of our company, not as a vendor; and I really respect that.' That sums up our intended relationship model: we would like to be your technology partner and bring that founder mindset into your business to deliver complex redesign projects together. XeoDev provides SaaS and Mobile Android and iOS App platforms for companies ranging from solopreneurs to unicorns. When you need this type of technology for your business get started by requesting a quote.