We know that Nginx is more faster than Apache and most of us prefer to replace Apache with Nginx as their web server. Nginx is known to serve faster static content and run with less RAM. As of this writing, Virtualmin supports Apache as its web server. To take advantage of Nginx, we will install it as reverse proxy for Apache and continue using Virtualmin to manage your domains. This guide also applies to Nginx+PHP FPM setup just skip the “Configure Apache” section and skip the “Configure Virtualmin” section if you are not using Virtualmin. Nginx configurations for virtual host are tailored for Drupal site and the following are the features:
- Support for Virtualmin to manage domains.
- Microcache support for anonymous and authenticated users.
- Seamless upstream switch between reverse proxy to Apache and PHP FPM backends.
- Script that aids to generate Nginx configuration from template for your web site domain (for those who don’t use Virtualmin).
- Protections from: MIME type deviation, DoS attacks, bad bot/referrer user agents, clickjacking attacks, unauthorized access to private file directory and hotlinking.
- Disabled access to any code files and known Drupal files and directories.
- Better handling of static resources: css, cur, json, js, jpg/jpeg, gif, htc, ico, png, htm, html, xml, txt, otf, ttf, eot, woff, svg, webp, webm, zip, gz, tar, rar, pdf, pptx, mp3, ogg, flv, mp4, mpa.
- Nginx PageSpeed support.
- Boost module support.
- Advanced CSS/JS Aggregation module support.
- RobotsTxt module support.
- XML Sitemap module support.
- Advanced Help module support.
- imagecache module support.
- File Force Download module support.
- Provision to support Filefield Nginx Progress module.
- RSS feed support.
- Supports Drupal 8, Drupal 7 and Durpal 6.
- The configurations observes Nginx’s inheritance rules for add_header directives.
- Protection against illegal HTTP methods (HEAD, GET and POST are only allowed).
- The error_log is set to “error” level and access_log is disabled in this Nginx configurations to avoid spending disk IO time.
- Implements Nginx PageSpeed module’s Shard domains technique for non-SSL sites.
- Uses the Let’s Encrypt free SSL/TLS certificates.
The following procedures are tested on Linode server running Centos 7 64-bit Linux distribution.
Install Nginx
If you need to install Nginx with PageSpeed module please follow the steps here instead then jump to configure Nginx section.
- In able to install the latest Nginx server we will need to register Nginx repository:
1vi /etc/yum.repos.d/nginx.repo
12345name=nginx repobaseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/gpgcheck=0priority=1enabled=0 - Install Nginx using yum:
1yum --enablerepo=nginx -y install nginx - Make Nginx auto-start upon reboot:
1chkconfig nginx on
Configure Nginx
- We will not need the native Nginx configurations provided because we will create new configurations. Lets backup the original Nginx configurations first:
1mv /etc/nginx /etc/nginx.bak - Create the folders following the directory structure shown below:
In the next steps, we will populate these folders with Nginx configurations. We will start populating each folder from bottom folder (utils) to top folder (apps).
- Create the main Nginx file
/etc/nginx/nginx.conf
and copy the following scripts to this file:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208user apache;## This number should be, at maximum, the number of CPU cores on your system.## (since nginx doesn't benefit from more than one worker per CPU.)worker_processes auto;## Only log errorserror_log /var/log/nginx/error.log error;pid /var/run/nginx.pid;## Number of file descriptors used for Nginx.## This is set in the OS with 'ulimit -n 200000'## or using /etc/security/limits.confworker_rlimit_nofile 200000;events {## Determines how many clients will be served by each worker process.## (worker_connections = 256 * worker_processes)## worker_processes can be identified by `cat /proc/cpuinfo | grep processor`## (Max clients = worker_connections * worker_processes)## "Max clients" is also limited by the number of socket connections## available on the system (~64k)worker_connections 1024;## Accept as many connections as possible,## after nginx gets notification about a new connection.## May flood worker_connections, if that option is set too low.multi_accept on;}http {## MIME types.include lib/mime.types;default_type application/octet-stream;## Logslog_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';## Default log and error files.log_not_found off;error_log /var/log/nginx/error.log error;## Buffer log writes to speed up IO, or disable them altogether#access_log /var/log/nginx/access.log main buffer=16k;#access_log /var/log/nginx/access.log;access_log off;## Use sendfile() syscall to speed up I/O operations and speed up## static file serving.## Sendfile copies data between one FD and other from within the kernel.## More efficient than read() + write(), since the requires transferring## data to and from the user space.sendfile on;## Handling of IPs in proxied and load balancing situations.set_real_ip_from 0.0.0.0/32; # all addresses get a real IP.real_ip_header X-Forwarded-For; # the ip is forwarded from the load balancer/proxy## Limit Request/Connection## Limit number of requests to mitigate DDoS attacklimit_req_zone $binary_remote_addr zone=reqlimit:10m rate=60r/s;## Define a zone for limiting the number of simultaneous## connections nginx accepts. 1m means 32000 simultaneous## sessions. We need to define for each server the limit_conn## value referring to this or other zones.limit_conn_zone $binary_remote_addr zone=connlimit:5m;## Timeouts.client_body_timeout 60s;client_header_timeout 60s;## Timeout for keep-alive connections.## Server will close connections after this time.keepalive_timeout 75 75;send_timeout 60s;## Reset lingering timed out connections. Deflect DDoS.reset_timedout_connection on;## TCP options.## don't buffer data-sends (disable Nagle algorithm).## Good for sending frequent small bursts of data in real time.tcp_nodelay on;## Optimization of socket handling when using sendfile.## Tcp_nopush causes nginx to attempt to send its HTTP response head in one packet,## instead of using partial frames. This is useful for prepending headers## before calling sendfile, or for throughput optimization.tcp_nopush on;## Compression.## Reduces the amount of data that needs to be transferred over the networkgzip on;gzip_buffers 16 8k;gzip_comp_level 1;gzip_http_version 1.1;gzip_min_length 10;gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/x-icon application/vnd.ms-fontobject font/opentype application/x-javascript application/x-font-ttf text/x-js;gzip_vary on;gzip_proxied any; # Compression for all requests.## No need for regexps. See## http://wiki.nginx.org/NginxHttpGzipModule#gzip_disablegzip_disable "msie6";## SSL## Use a SSL/TLS cache for SSL session resume. This needs to be## here (in this context, for session resumption to work. See this## thread on the Nginx mailing list:## http://nginx.org/pipermail/nginx/2010-November/023736.html.## 1MB store about 4000 sessions:## In this case, it store about 80000 sessions in 1 dayssl_session_cache shared:SSL:20m;ssl_session_timeout 1d;## The server dictates the choice of cipher suites.ssl_prefer_server_ciphers on;## Use only Perfect Forward Secrecy Ciphers. Fallback on non ECDH## for crufty clients.## Modern Mozilla SSL Configuration#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:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';#ssl_protocols TLSv1.2;## Intermediate Mozilla SSL Configuration## https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.10.2&openssl=1.0.1e&hsts=no&profile=intermediate#ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';## No SSLv3 support (SSLv3 POODLE Vulnerability)ssl_protocols TLSv1 TLSv1.1 TLSv1.2;## Old Mozilla SSL Configuration## https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.10.2&openssl=1.0.1e&hsts=no&profile=oldssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP';#ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;## Pregenerated Diffie-Hellman parameters 2048.ssl_dhparam key/dh_param.pem;## Curve to use for ECDH.ssl_ecdh_curve prime256v1;## Enable OCSP stapling. A better way to revocate server certificates.ssl_stapling on;## Enable verification of OCSP stapling responses by the server.ssl_stapling_verify on;## Server certificate and key (using Let's Encrypt free SSL certificate).ssl_certificate /etc/letsencrypt/live/yourwebsite.com/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/yourwebsite.com/privkey.pem;## Verify chain of trust of OCSP response using Root CA and Intermediate certsssl_trusted_certificate /etc/letsencrypt/live/yourwebsite.com/chain.pem;## Use Google's DNSresolver 8.8.8.8 8.8.4.4;## Body size.client_max_body_size 50m;## To build optimal server_names_hashserver_names_hash_bucket_size 72;## If start getting [emerg]: could not build the map_hash,## you should increase map_hash_bucket_size: 64 in your## logs. Cf. http://wiki.nginx.org/NginxOptimizations.#map_hash_bucket_size 192;## Uncomment one of the lines below if you start getting this message:## "[emerg] could not build the variables_hash, you should increase## either variables_hash_max_size: 512 or variables_hash_bucket_size: 64"## You only need to increase one. Increasing variables_hash_max_size to 1024## was recommended in nginx forum by developers.## See this forum topic and responses## http://forum.nginx.org/read.php?2,192277,192286#msg-192286## See http://wiki.nginx.org/HttpCoreModule#variables_hash_bucket_size## The line variables_hash_bucket_size was added for completeness but not## changed from default.#variables_hash_max_size 1024; # default 512#variables_hash_bucket_size 64; # default is 64## For the filefield_nginx_progress module to work. From the## README. Reserve 1MB under the name 'uploads' to track uploads.#upload_progress uploads 1m;## Modify HTTP headerinclude utils/mod_header.conf;## Hide the Nginx version number.server_tokens off;## Map## Include the map to block HTTP methods.include map/block_http_methods.conf;## Support the X-Forwarded-Proto header for fastcgi.include map/x_forwarded_proto.conf;## Include blacklist for bad bot and referer blocking.include map/blacklist.conf;## Include the Nginx stub status allowed hosts configuration block.include map/nginx_status_allowed_hosts.conf;## Include list of allowed hosts to run croninclude map/cron_allowed_hosts.conf;## Include the php-fpm status allowed hosts configuration block.include map/php_fpm_status_allowed_hosts.conf;## Include the caching setup.## Needed for using Drupal with an external cache.include map/drupal_external_cache.conf;## Include the upstream servers.include utils/service/upstream.conf;## Microcache zone definition.include utils/service/microcache_zone.conf;## Handle all undefined server_nameinclude utils/undefined_server_name_handler.conf;## Google PageSpeed module## Uncomment the line below if Google PageSpeed module is present#include apps/pagespeed/core.conf;## Include all vhosts.include sites-enabled/*.conf;}Note: To generate the following SSL certificate files:
123ssl_certificate /etc/letsencrypt/live/yourwebsite.com/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/yourwebsite.com/privkey.pem;ssl_trusted_certificate /etc/letsencrypt/live/yourwebsite.com/chain.pem;… follow steps in this article: Using Let’s Encrypt free SSL/TLS certificates with Nginx.
- Lets populate
/etc/nginx/utils
:Create the file/etc/nginx/utils/undefined_server_name_handler.conf
and copy the following scripts to this file:12345678910111213141516171819202122232425262728293031## Prevent processing requests with undefined server names (HTTPS)server {listen XXX.XXX.XXX.XXX:443 ssl; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:443 ssl; ## IPv6server_name _;return 444;}## Prevent processing requests with undefined server names (HTTP)server {listen XXX.XXX.XXX.XXX:80; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:80; ## IPv6server_name _;return 444;}## Prevent processing requests with undefined server names (HTTPS)server {listen XXX.XXX.XXX.XXX:443 ssl; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:443 ssl; ## IPv6server_name "";return 444;}## Prevent processing requests with undefined server names (HTTP)server {listen XXX.XXX.XXX.XXX:80; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:80; ## IPv6server_name "";return 444;}Note: Replace all the occurrence of
XXX.XXX.XXX.XXX
with your server’s IPv4 address andXXXX:XXXX::XXXX:XXXX:XXXX:XXXX
with your server’s IPv6 address.Create the file
/etc/nginx/utils/mod_header.conf
and copy the following scripts to this file:1234567891011121314151617181920212223242526272829303132## Modify HTTP header## Enable the builtin cross-site scripting (XSS) filter available## in modern browsers. Usually enabled by default we just## reinstate in case it has been somehow disabled for this## particular server instance.## https://www.owasp.org/index.php/List_of_useful_HTTP_headers.add_header X-XSS-Protection '1; mode=block';## Enable clickjacking protection in modern browsers. Available in## IE8 also. See## https://developer.mozilla.org/en/The_X-FRAME-OPTIONS_response_header## This may conflicts with pseudo streaming (at least with Nginx version 1.0.12).## Uncomment the line below if you're not using media streaming.## For sites being framing on the same domain uncomment the line below.add_header X-Frame-Options SAMEORIGIN;## For sites accepting to be framed in any context comment the## line below.#add_header X-Frame-Options DENY;## When serving user-supplied content, include a X-Content-Type-Options: nosniff header along with the Content-Type: header,## to disable content-type sniffing on some browsers.## https://www.owasp.org/index.php/List_of_useful_HTTP_headers## currently suppoorted in IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx## http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx## 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020## Block MIME type sniffing on IE.add_header X-Content-Options nosniff;## Add a cache miss/hit status header. This can be disabled if not including## any of the apps/drupal/microcache* files.add_header X-Micro-Cache $upstream_cache_status;Create the file
/etc/nginx/utils/nginx_status_vhost.conf
and copy the following scripts to this file:1234567891011121314## The configuration for Nginx status page. As described in## http://wiki.nginx.org/HttpStubStatusModule.## php-fpm provides a status and a heartbeat page that is served through the web server.## Here's an example configuration for them.## Get the nginx status.location /nginx_status {if ($dont_show_nginx_status) {return 404;}stub_status on;access_log off;}Create the file
/etc/nginx/utils/apache/microcache.conf
and copy the following scripts to this file:12345678910111213141516171819202122232425262728293031## The cache zone referenced.proxy_cache microcache;## The cache key.proxy_cache_key $scheme$host$request_uri;## For 200 and 301 make the cache valid for 10 seconds.proxy_cache_valid 200 301 10s;## For 302 make it valid for 1 minute.proxy_cache_valid 302 1m;## For 404 make it valid 1 second.proxy_cache_valid 404 1s;## If there are any upstream errors or the item has expired use## whatever it is available.proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504 off;## The Cache-Control and Expires headers should be delivered untouched## from the upstream to the client.proxy_ignore_headers Cache-Control Expires;## Bypass the cache.proxy_cache_bypass $no_cache;proxy_no_cache $no_cache;## To avoid any interaction with the cache control headers we expire## everything on this location immediately.expires epoch;## Cache locking mechanism for protecting the backendof too many## simultaneous requests.proxy_cache_lock on;## The default timeout, i.e., the time to way before forwarding the## second request upstream if no reply as arrived in the meantime is 5s.proxy_cache_lock_timeout 5000; # in miliseconds.Create the file
/etc/nginx/utils/apache/microcache_auth.conf
and copy the following scripts to this file:123456789101112131415161718192021222324252627282930313233## The cache zone referenced.proxy_cache microcache;## The cache key.proxy_cache_key $cache_uid@$scheme$host$request_uri;## For 200 and 301 make the cache valid for 10 seconds.proxy_cache_valid 200 301 10s;## For 302 make it valid for 1 minute.proxy_cache_valid 302 1m;## For 404 make it valid 1 second.proxy_cache_valid 404 1s;## If there are any upstream errors or the item has expired use## whatever it is available.proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504 off;## The Cache-Control and Expires headers should be delivered untouched## from the upstream to the client.proxy_ignore_headers Cache-Control Expires;proxy_pass_header Set-Cookie;proxy_pass_header Cookie;## Bypass the cache.proxy_cache_bypass $no_auth_cache;proxy_no_cache $no_auth_cache;## To avoid any interaction with the cache control headers we expire## everything on this location immediately.expires epoch;## Cache locking mechanism for protecting the backendof too many## simultaneous requests.proxy_cache_lock on;## The default timeout, i.e., the time to way before forwarding the## second request upstream if no reply as arrived in the meantime is 5s.proxy_cache_lock_timeout 5000; # in miliseconds.Create the file
/etc/nginx/utils/apache/microcache_zone.conf
and copy the following scripts to this file:12345678## Defining the proxy cache zone for the microcache as presented at:## http://fennb.com/microcaching-speed-your-app-up-250x-with-no-n.## If youre using a Nginx version greater than 1.1.1 then you can## tweak the Tweaking of the cache loader parameters.## Cf. http://forum.nginx.org/read.php?21,213197,213209#msg-213209 for## rationale.proxy_cache_path /var/cache/nginx/microcache levels=1:2 keys_zone=microcache:5M max_size=1G loader_threshold=2592000000 loader_sleep=1 loader_files=100000;Create the file
/etc/nginx/utils/apache/php_fpm_status_vhost.conf
and copy the following scripts to this file:1## This should be empty. Serves as dummy to prevent nginx non-existing file error.Create the file
/etc/nginx/utils/apache/php_pass.conf
and copy the following scripts to this file:123456789101112131415161718192021## Apache configuration## Configuration for reverse proxy. Passing the necessary headers to## the backend. Nginx doesn't tunnel the connection, it opens a new## one. Hence we need to send these headers to the backend so that## the client(s) IP is available to them. The host is also sent.proxy_pass http://phpapache;proxy_http_version 1.1; # keep alive to the Apache upstreamproxy_set_header Connection '';## Referrerproxy_set_header Visitor-referrer $http_referer;## Rewrite the 'Host' header to the value in the client request,## or primary server nameproxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;## Hide the X-Drupal-Cache header provided by Pressflow.proxy_hide_header 'X-Drupal-Cache';## Hide the Drupal 7 header X-Generator.proxy_hide_header 'X-Generator';Create the file
/etc/nginx/utils/apache/upstream.conf
and copy the following scripts to this file:1234567891011121314151617181920## Upstream configuration for Apache functioning has a PHP handler.## Add as many servers as needed.## Cf. http://wiki.nginx.org/HttpUpstreamModule.## Note that this configuration assumes by default that keepalive## upstream connections are supported and that you have a Nginx## version with the fair load balancer.upstream phpapache {## Use the least connection algorithm for load balancing. This## algorithm was introduced in versions 1.3.1 and 1.2.2.least_conn;server 127.0.0.1:8080;#server 127.0.0.1:8081;## Create a backend connection cache. Note that this requires## Nginx version greater or equal to 1.1.4.## Cf. http://nginx.org/en/CHANGES.keepalive 5;}Populate the
/etc/nginx/utils/fastcgi
folder under this guide: Setup PHP FPM for Nginx. - The
/etc/nginx/sites-enabled
folder is used as container for enabled websites which are soft link to physical file Nginx configuration of each of your website virtual host stored at/etc/nginx/sites-available/prod
. - Lets populate
/etc/nginx/sites-available
:Create the file/etc/nginx/sites-available/template.conf
and copy the following scripts to this file:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126## Nginx configuration for {DOM}.## Redirect HTTPS to HTTP (Domains used for static resource).server {listen XXX.XXX.XXX.XXX:443 ssl; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:443 ssl; ## IPv6server_name s1.{DOM} s2.{DOM} s3.{DOM} s4.{DOM};return 301 http://$server_name$request_uri;}## Domains used for static resource.server {listen XXX.XXX.XXX.XXX:80; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:80; ## IPv6server_name s1.{DOM} s2.{DOM} s3.{DOM} s4.{DOM};## Access and error logs.#access_log /var/log/virtualmin/{DOM}_nginx_access_log;access_log off;log_not_found off;error_log /var/log/virtualmin/{DOM}_nginx_error_log error;## Allow Let's Encrypt to access the temporary filelocation /.well-known/acme-challenge {root /var/www/letsencrypt;}## Filesystem root of the site.root {HOME};## Set no HTTP Strict Transport Securityset $hsts "";## Common Nginx configuration for server contextinclude apps/drupal/common_server_context.conf;## Named locationinclude apps/drupal/named_location.conf;## The 'default' location.location / {## Redirect web content to main domain.location ~* .(html?|xml)$ {return 301 $scheme://www.{DOM}$request_uri;}## Accept static files only.## Drupal generated static files.include apps/drupal/static_files_handler.conf;}}## Redirect HTTPS to HTTP (Main server).server {listen XXX.XXX.XXX.XXX:443 ssl; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:443 ssl; ## IPv6server_name {DOM} www.{DOM};return 301 http://$server_name$request_uri;}## Redirect domain with prefixed www sub-domain.server {## This is to avoid the spurious if for sub-domain name## "rewriting".listen XXX.XXX.XXX.XXX:80; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:80; ## IPv6server_name {DOM};return 301 $scheme://www.{DOM}$request_uri;}## Main server.server {listen XXX.XXX.XXX.XXX:80; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:80; ## IPv6server_name www.{DOM};## PageSpeed## Uncomment the line below if Google PageSpeed module is present#pagespeed ShardDomain $scheme://$server_name $scheme://s1.{DOM},$scheme://s2.{DOM};## Access and error logs.#access_log /var/log/virtualmin/{DOM}_nginx_access_log;access_log off;log_not_found off;error_log /var/log/virtualmin/{DOM}_nginx_error_log error;## Allow Let's Encrypt to access the temporary filelocation /.well-known/acme-challenge {root /var/www/letsencrypt;}## Filesystem root of the site and index.root {HOME};index index.php;## Set no HTTP Strict Transport Securityset $hsts "";## Configuration for Drupal.include apps/drupal/core.conf;## Installation handling. If an already installed site there's## no need to touch it. Uncomment the line below if you want to## enable Drupal install PHP script and comment out after## installation. Note that there's a basic auth in front as## secondary line of defense.#include apps/drupal/drupal_install.conf;## Configuration for updating the site via update.php and running## cron externally. Uncomment the line below if you want to## enable Drupal xmlrpc, update and cron PHP script#include apps/drupal/drupal_cron_update.conf;## Support for upload progress bar. Configurations differ for## Drupal 6 and Drupal 7.#include apps/drupal/drupal_upload_progress.conf;## Including the php-fpm status and ping pages config.#include utils/service/php_fpm_status_vhost.conf;## Including the Nginx stub status page for having stats about## Nginx activity: http://wiki.nginx.org/HttpStubStatusModule.#include utils/nginx_status_vhost.conf;{TARGETED_SERVER_CONFIG}}Note: Replace all the occurrence of
XXX.XXX.XXX.XXX
with your server’s IPv4 address andXXXX:XXXX::XXXX:XXXX:XXXX:XXXX
with your server’s IPv6 address.Create the file
/etc/nginx/sites-available/template_ssl.conf
and copy the following scripts to this file:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106## Nginx configuration for {DOM}.## Redirect HTTP to HTTPS.server {listen XXX.XXX.XXX.XXX:80; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:80; ## IPv6server_name {DOM} www.{DOM};set $nossl 0;if ($request_uri ~* /.well-known/acme-challenge/.+) {## Override redirection to HTTPSset $nossl 1;}if ($nossl = 0){## Redirect to HTTPS.return 301 https://$server_name$request_uri;}## Allow Let's Encrypt to access the temporary filelocation /.well-known/acme-challenge {root /var/www/letsencrypt;}}## HTTPS (Redirect domain with prefixed www sub-domain).server {listen XXX.XXX.XXX.XXX:443 ssl; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:443 ssl; ## IPv6server_name {DOM};## Access and error logs.#access_log /var/log/virtualmin/{DOM}_nginx_access_log;access_log off;log_not_found off;error_log /var/log/virtualmin/{DOM}_nginx_error_log error;## Config to enable HSTS (HTTP Strict Transport Security)## https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security## to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping## Strict Transport Security header for enhanced security. See## http://www.chromium.org/sts. Enables HTTP to HTTPS redirects via browser level.set $hsts "max-age=31536000";add_header Strict-Transport-Security $hsts;## Inheritance Rules for add_header Directives## Because this 'server' block contains another 'add_header' directive,## we must redeclare the 'add_header' from 'http' contextinclude utils/mod_header.conf;return 301 $scheme://www.{DOM}$request_uri;}## HTTPS (Main server).server {listen XXX.XXX.XXX.XXX:443 ssl http2; ## IPv4listen [XXXX:XXXX::XXXX:XXXX:XXXX:XXXX]:443 ssl http2; ## IPv6server_name www.{DOM};## Access and error logs.#access_log /var/log/virtualmin/{DOM}_nginx_access_log;access_log off;log_not_found off;error_log /var/log/virtualmin/{DOM}_nginx_error_log error;## Config to enable HSTS (HTTP Strict Transport Security)## https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security## to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping## Strict Transport Security header for enhanced security. See## http://www.chromium.org/sts. Enables HTTP to HTTPS redirects via browser level.set $hsts "max-age=31536000";add_header Strict-Transport-Security $hsts;## Inheritance Rules for add_header Directives## Because this 'server' block contains another 'add_header' directive,## we must redeclare the 'add_header' from 'http' contextinclude utils/mod_header.conf;## Filesystem root of the site and index.root {HOME};index index.php;## Configuration for Drupal.include apps/drupal/core.conf;## Installation handling. If an already installed site there's## no need to touch it. Uncomment the line below if you want to## enable Drupal install PHP script and comment out after## installation. Note that there's a basic auth in front as## secondary line of defense.#include apps/drupal/drupal_install.conf;## Configuration for updating the site via update.php and running## cron externally. Uncomment the line below if you want to## enable Drupal xmlrpc, update and cron PHP script#include apps/drupal/drupal_cron_update.conf;## Support for upload progress bar. Configurations differ for## Drupal 6 and Drupal 7.#include apps/drupal/drupal_upload_progress.conf;## Including the php-fpm status and ping pages config.#include utils/service/php_fpm_status_vhost.conf;## Including the Nginx stub status page for having stats about## Nginx activity: http://wiki.nginx.org/HttpStubStatusModule.#include utils/nginx_status_vhost.conf;{TARGETED_SERVER_CONFIG}}Note: Replace all the occurrence of
XXX.XXX.XXX.XXX
with your server’s IPv4 address andXXXX:XXXX::XXXX:XXXX:XXXX:XXXX
with your server’s IPv6 address.The two scripts above
/etc/nginx/sites-available/template.conf
and/etc/nginx/sites-available/template_ssl.conf
will be used by the Virtualmin to generate Nginx configuration for your website virtual host when created using Virtualmin. By default, these configurations utilizes the use of Drush for site maintenance. If you wanted the original Drupal behavior in installing new site, uncomment the line:1include apps/drupal/drupal_install.conf;For original Drupal cron and update behavior, uncomment the line:
1include apps/drupal/drupal_cron_update.conf;Note: This uses Basic Authentication so it will challenge you for password.
If you are not using Virtualmin, you can use the following bash script to create Nginx configuration for your website virtual host. Create the file
/etc/nginx/sites-available/buildsitesconf.sh
and add the following to it:1234567891011121314151617181920212223242526#!/bin/bashSITES=('yourwebsite.com' 'yourotherwebsite.com')SITEHOME='/home/drupal/public_html'for SITEDOM in "${SITES[@]}"dosed "s/{DOM}/$SITEDOM/g" template.conf > buffer.confsed "s/{HOME}/$SITEHOME/g" buffer.conf > "prod/${SITEDOM}.conf"sed "s/{DOM}/$SITEDOM/g" template_ssl.conf > buffer.confsed "s/{HOME}/$SITEHOME/g" buffer.conf > "prod/${SITEDOM}_ssl.conf"if [ -f "targeted_server_config/${SITEDOM}.conf" ]thensed "s/{TARGETED_SERVER_CONFIG}/include sites-available/targeted_server_config/${SITEDOM}.conf;/g" "prod/${SITEDOM}.conf" > buffer.confcat buffer.conf > "prod/${SITEDOM}.conf"sed "s/{TARGETED_SERVER_CONFIG}/include sites-available/targeted_server_config/${SITEDOM}.conf;/g" "prod/${SITEDOM}_ssl.conf" > buffer.confcat buffer.conf > "prod/${SITEDOM}_ssl.conf"elsesed "s/{TARGETED_SERVER_CONFIG}//g" "prod/${SITEDOM}.conf" > buffer.confcat buffer.conf > "prod/${SITEDOM}.conf"sed "s/{TARGETED_SERVER_CONFIG}//g" "prod/${SITEDOM}_ssl.conf" > buffer.confcat buffer.conf > "prod/${SITEDOM}_ssl.conf"fidonerm -f buffer.confNote: Replace the
'yourwebsite.com' 'yourotherwebsite.com'
with your own website domains and'/home/drupal/public_html'
with your websites’ root path (eg. if your websites’ root path is/var/www
then change it to'/var/www'
).Make it executable:
1chmod +x /etc/nginx/sites-available/buildsitesconf.shWhen you executed this script, it will generate non-SSL and SSL versions of Nginx configuration for your website virtual hosts that you defined at
/etc/nginx/sites-available/buildsitesconf.sh
. The generated Nginx configuration will be saved at/etc/nginx/sites-available/prod
.To enable a non-SSL version virtual host Nginx configuration, just create a soft link of this configuration file from /etc/nginx/sites-available/prod to /etc/nginx/sites-enabled example:
1ln -s /etc/nginx/sites-available/prod/yourwebsite.com.conf /etc/nginx/sites-enabled/yourwebsite.com.conf… or if SSL version is desired:
1ln -s /etc/nginx/sites-available/prod/yourwebsite_ssl.com.conf /etc/nginx/sites-enabled/yourwebsite_ssl.com.confThis is easy and good approach to disable and enable a virtual host.
The
/etc/nginx/sites-available/prod
folder will be used by the/etc/nginx/sites-available/template.conf
and/etc/nginx/sites-available/template_ssl.conf
scripts as container for the generated Nginx configuration of your website virtual host.The
/etc/nginx/sites-available/admin
folder will be used for Admin UI Nginx configurations like:The
/etc/nginx/sites-available/targeted_server_config
folder will be used by the/etc/nginx/sites-available/template.conf
and/etc/nginx/sites-available/template_ssl.conf
scripts to look for the filename that will match the domain under process. e.g. if the template script processing the domain “webfoobar.com”, it will look for a filename “webfoobar.com.conf” and this should only contain your custom Nginx configuration for “webfoobar.com” domain inserver
context. Domains that don’t have custom Nginx configuration need not to create file under this folder. - Lets populate
/etc/nginx/map
:Create the file/etc/nginx/map/php_fpm_status_allowed_hosts.conf
and add the following to it:12345678## Configuration of php-fpm status and ping pages. Here we define the## allowed hosts using the Geo Module. http://wiki.nginx.org/HttpGeoModulegeo $dont_show_fpm_status {default 1;127.0.0.1 0; # allow on the loopback192.168.1.0/24 0; # allow on an internal network}Create the file
/etc/nginx/map/nginx_status_allowed_hosts.conf
and add the following to it:12345678## Configuration of nginx stub status page. Here we define the## allowed hosts using the Geo Module. http://wiki.nginx.org/HttpGeoModulegeo $dont_show_nginx_status {default 1;127.0.0.1 0; # allow on the loopback192.168.1.0/24 0; # allow on an internal network}Create the file
/etc/nginx/map/hotlinking_protection_allowed_hosts.conf
and add the following to it:12345678910111213## Hotlinking protection for images. Include it in any context you## want. Adjust the list of allowed referrers to your liking.valid_referers none blockedwww.yahoo.comwww.google.comwebfoobar.comwww.webfoobar.com## Add your domains here;if ($invalid_referer) {return 200 "No image hotlinking allowed!n";}Create the file
/etc/nginx/map/drupal_external_cache.conf
and add the following to it:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354## Testing if we should be serving content from cache or not. This is## needed for any Drupal setup that uses an external cache.## Let Ajax calls go through.map $uri $no_cache_ajax {default 0;/system/ajax 1;}## Test Boost session cookie being present. If there is, then no## caching is to be done.map $http_cookie $no_boost_cache_cookie {default 0;~DRUPAL_UID 1;#~nocache=1 1; # Custom logged in/out indicator}## Boost URI watch listmap $request_uri $no_boost_cache_uri {default 0;~*^/(admin|cache|misc|modules|sites|system|openid|themes|node/add|comment/reply)|(/(edit|user|user/(login|password|register)))$ 1;}## Combine both results to get the cache bypassing mapping.map $no_boost_cache_cookie$no_boost_cache_uri $no_boost_cache {default 1;00 0;}## Testing for the session cookie being present. If there is, then no## caching is to be done. Note that this is for someone using either## Drupal 7 pressflow or stock Drupal 6 core with no_anon## (https://drupal.org/project/no_anon).map $http_cookie $no_cache_cookie {default 0;~SESS 1; # PHP session cookie#~nocache=1 1; # Custom logged in/out indicator}## Combine both results to get the cache bypassing mapping.map $no_cache_ajax$no_cache_cookie $no_auth_cache {default 1;00 0;}## Cache bypassing mapping (auth).map $no_cache_ajax $no_cache {default 0;1 1;}## Set a cache_uid variable for authenticated users.map $http_cookie $cache_uid {default nil;~SESS[[:alnum:]]+=(?[[:graph:]]+) $session_id;}Note: You can also use the Method 1 mentioned here: Methods to disable Nginx cache when user is authenticated in Drupal as I find it more reliable indicator for user status: anonymous or authenticated.
Create the file
/etc/nginx/map/cron_allowed_hosts.conf
and add the following to it:123456789## Configuration file for specifying which hosts can invoke Drupal's## cron. This only applies if you're not using drush to run cron.geo $not_allowed_cron {default 1;## Add your set of hosts.127.0.0.1 0; # allow the localhost192.168.1.0/24 0; # allow on an internal network}Create the file
/etc/nginx/map/block_http_methods.conf
and add the following to it:123456789## This file contains a map directive that is used to block the## invocation of HTTP methods. Out of the box it allows for HEAD, GET and POST.map $request_method $not_allowed_method {default 1;GET 0;HEAD 0;POST 0;}Create the file
/etc/nginx/map/x_forwarded_proto.conf
and add the following to it:123456## Support the X-Forwarded-Proto header for fastcgi.map $http_x_forwarded_proto $fastcgi_https {default $https;http '';https on;}Create the file
/etc/nginx/map/blacklist.conf
and add the following to it:123456789101112131415161718192021222324## This file implements a blacklist for certain user agents and## referrers. It's a first line of defence. It must be included## inside a http block.## Add here all user agents that are to be blocked.map $http_user_agent $bad_bot {default 0;~*^Lynx 0; # Let Lynx go throughlibwww-perl 1;~*(?i)(360Spider|80legs|Abonti|Aboundex|^AIBOT|^Alexibot|almaden|^Anarchie|^ASPSeek|^asterias|^attach|^autoemailspider|^BackWeb|Baiduspider|^Bandit|^BatchFTP|BBBike|^BackDoorBot|^Bigfoot|^Black.Hole|^BlackWidow|^BlowFish|^Bot mailto:craftbot@yahoo.com|^BotALot|^Buddy|^BuiltBotTough|^Bullseye|^bumblebee|^BunnySlippers|^Cegbfeieh|^CheeseBot|^CherryPicker|^ChinaClaw|^CICC|Cogentbot|^Collector|^Copier|^CopyRightCheck|^cosmos|CPython|^Crescent|^Custo|^DA|^DIIbot|^DISCo|^DISCo Pump|^Download Demon|^Download Wonder|^Downloader|^Drip|^DSurf15a|^eCatch|^EasyDL/2.99|^EirGrabber|email|^EmailCollector|^EmailSiphon|^EmailWolf|^Express WebPictures|^ExtractorPro|^EyeNetIE|facebookexternalhit|^FileHound|^FlashGet|FlipboardProxy|FrontPage|^GetRight|^GetSmart|^GetWeb!|^gigabaz|^Go!Zilla|^Go!Zilla|^Go-Ahead-Got-It|^gotit|^Grabber|^GrabNet|^Grafula|^grub-client|^HMView|htmlparser|^HTTrack|^httpdown|.*httrack.*|^ia_archiver|^Image Stripper|^Image Sucker|^Indy*Library|Indy Library|^InterGET|^InternetLinkagent|^Internet Ninja|^InternetSeer.com|^Iria|^Java|^JBH*agent|^JetCar|^JOC Web Spider|JikeSpider|^JustView|^larbin|^LeechFTP|^LexiBot|^lftp|libwww|^Link*Sleuth|^likse|^Link|^LinkWalker|^Mag-Net|^Magnet|^Mass Downloader|mediawords|MegaIndex|^Memo|MetaURI|^Microsoft.URL|^MIDown tool|^Mirror|^Mister PiX|MJ12bot|Mozilla/4.0|^Mozilla.*Indy|^Mozilla.*NEWT|^Mozilla*MSIECrawler|^MS FrontPage*|^MSFrontPage|^MSIECrawler|msnbot|^MSProxy|^Navroad|^NearSite|^NetAnts|^NetMechanic|^NetSpider|^Net Vampire|^NetZIP|^NICErsPRO|^Ninja|^Octopus|^Offline Explorer|^Offline Navigator|^Openfind|OpenLinkProfiler|^PageGrabber|^Papa Foto|^pavuk|^pcBrowser|^Ping|^PingALink|Pixray|^Pockey|proximic|^psbot|^Pump|^QRVA|^RealDownload|^Reaper|^Recorder|^ReGet|^Scooter|^Seeker|^Siphon|^sitecheck.internetseer.com|Siteimprove|^SiteSnagger|^SlySearch|^SmartDownload|^Snake|Sosospider|^SpaceBison|spbot|Spinn3r|^sproose|^Stripper|^Sucker|^SuperBot|^SuperHTTP|^Surfbot|^Szukacz|^tAkeOut|^Teleport Pro|Twitterbot|^URLSpiderPro|^Vacuum|^VoidEYE|^Web Image Collector|^Web Sucker|^WebAuto|^[Ww]eb[Bb]andit|^webcollage|^WebCopier|^Web Downloader|^WebEMailExtrac.*|^WebFetch|^WebGo IS|^WebHook|^WebLeacher|^WebMiner|^WebMirror|^WebReaper|^WebSauger|^Website|^Website eXtractor|^Website Quester|^Webster|^WebStripper|WebWhacker|^WebZIP|^Wget|^Whacker|^Widow|^WWWOFFLE|^x-Tractor|^Xaldon WebSpider|^Xenu|^Zeus.*Webster|^Zeus|ZmEu) 1;}## Add here all referrers that are to blocked.map $http_referer $bad_referer {default 0;~(?i)(adult|babes|click|diamond|forsale|girl|jewelry|love|nudit|organic|poker|porn|poweroversoftware|sex|teen|webcam|zippo|casino|replica|en.savefrom.net|7makemoneyonline.com|acunetix-referrer.com|adcash.com|bithack.ru|buttons-for-website.com|cenokos.ru|cenoval.ru|cityadspix.com|darodar.com|econom.co|edakgfvwql.ru|gobongo.info|iedit.ilovevitaly.com|ilovevitaly.com|ilovevitaly.co|ilovevitaly.info|ilovevitaly.org|ilovevitaly.ru|iskalko.ru|luxup.ru|make-money-online.7makemoneyonline.com|maps.ilovevitaly.com|myftpupload.com|savefrom.net|savetubevideo.com|screentoolkit.com|semalt.com|seoexperimenty.ru|shopping.ilovevitaly.ru|slftsdybbg.ru|socialseet.ru|srecorder.com|st3.cwl.yahoo.com|superiends.org|vodkoved.ru|websocial.me|ykecwqlixx.ru|yougetsignal.com|priceg.com|responsinator.com|o-o-6-o-o.ru|o-o-8-o-o.ru) 1;}## Add here all hosts that should be spared any referrer checking.geo $bad_referer {## Add your set of hosts.127.0.0.1 0;192.168.1.0/24 0;} - Lets populate
/etc/nginx/lib
:Create the file/etc/nginx/lib/win-utf
and add the following to it:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124## This map is not a full windows-1251 utf8 map: it does not## contain Serbian and Macedonian letters. If you need a full map,## use contrib/unicode2nginx/win-utf map instead.charset_map windows-1251 utf-8 {82 E2809A ; ## single low-9 quotation mark84 E2809E ; ## double low-9 quotation mark85 E280A6 ; ## ellipsis86 E280A0 ; ## dagger87 E280A1 ; ## double dagger88 E282AC ; ## euro89 E280B0 ; ## per mille91 E28098 ; ## left single quotation mark92 E28099 ; ## right single quotation mark93 E2809C ; ## left double quotation mark94 E2809D ; ## right double quotation mark95 E280A2 ; ## bullet96 E28093 ; ## en dash97 E28094 ; ## em dash99 E284A2 ; ## trade mark signA0 C2A0 ; ##A1 D18E ; ## capital Byelorussian short UA2 D19E ; ## small Byelorussian short uA4 C2A4 ; ## currency signA5 D290 ; ## capital Ukrainian soft GA6 C2A6 ; ## borken barA7 C2A7 ; ## section signA8 D081 ; ## capital YOA9 C2A9 ; ## (C)AA D084 ; ## capital Ukrainian YEAB C2AB ; ## left-pointing double angle quotation markAC C2AC ; ## not signAD C2AD ; ## soft hypenAE C2AE ; ## (R)AF D087 ; ## capital Ukrainian YIB0 C2B0 ; ## °B1 C2B1 ; ## plus-minus signB2 D086 ; ## capital Ukrainian IB3 D196 ; ## small Ukrainian iB4 D291 ; ## small Ukrainian soft gB5 C2B5 ; ## micro signB6 C2B6 ; ## pilcrow signB7 C2B7 ; ## ·B8 D191 ; ## small yoB9 E28496 ; ## numero signBA D194 ; ## small Ukrainian yeBB C2BB ; ## right-pointing double angle quotation markBF D197 ; ## small Ukrainian yiC0 D090 ; ## capital AC1 D091 ; ## capital BC2 D092 ; ## capital VC3 D093 ; ## capital GC4 D094 ; ## capital DC5 D095 ; ## capital YEC6 D096 ; ## capital ZHC7 D097 ; ## capital ZC8 D098 ; ## capital IC9 D099 ; ## capital JCA D09A ; ## capital KCB D09B ; ## capital LCC D09C ; ## capital MCD D09D ; ## capital NCE D09E ; ## capital OCF D09F ; ## capital PD0 D0A0 ; ## capital RD1 D0A1 ; ## capital SD2 D0A2 ; ## capital TD3 D0A3 ; ## capital UD4 D0A4 ; ## capital FD5 D0A5 ; ## capital KHD6 D0A6 ; ## capital TSD7 D0A7 ; ## capital CHD8 D0A8 ; ## capital SHD9 D0A9 ; ## capital SHCHDA D0AA ; ## capital hard signDB D0AB ; ## capital YDC D0AC ; ## capital soft signDD D0AD ; ## capital EDE D0AE ; ## capital YUDF D0AF ; ## capital YAE0 D0B0 ; ## small aE1 D0B1 ; ## small bE2 D0B2 ; ## small vE3 D0B3 ; ## small gE4 D0B4 ; ## small dE5 D0B5 ; ## small yeE6 D0B6 ; ## small zhE7 D0B7 ; ## small zE8 D0B8 ; ## small iE9 D0B9 ; ## small jEA D0BA ; ## small kEB D0BB ; ## small lEC D0BC ; ## small mED D0BD ; ## small nEE D0BE ; ## small oEF D0BF ; ## small pF0 D180 ; ## small rF1 D181 ; ## small sF2 D182 ; ## small tF3 D183 ; ## small uF4 D184 ; ## small fF5 D185 ; ## small khF6 D186 ; ## small tsF7 D187 ; ## small chF8 D188 ; ## small shF9 D189 ; ## small shchFA D18A ; ## small hard signFB D18B ; ## small yFC D18C ; ## small soft signFD D18D ; ## small eFE D18E ; ## small yuFF D18F ; ## small ya}Create the file
/etc/nginx/lib/mime.types
and add the following to it:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129types {text/html html htm shtml;text/css css;text/xml xml;image/gif gif;image/jpeg jpeg jpg;application/javascript js;application/atom+xml atom;application/rss+xml rss;text/mathml mml;text/plain txt;text/vnd.sun.j2me.app-descriptor jad;text/vnd.wap.wml wml;text/x-component htc;image/png png;image/tiff tif tiff;image/vnd.wap.wbmp wbmp;image/x-icon ico;image/x-jng jng;image/x-ms-bmp bmp;image/svg+xml svg svgz;image/webp webp;application/java-archive jar war ear;application/json json;application/mac-binhex40 hqx;application/msword doc;application/pdf pdf;application/postscript ps eps ai;application/rtf rtf;application/vnd.apple.mpegurl m3u8;application/vnd.ms-excel xls;application/vnd.ms-powerpoint ppt;application/vnd.wap.wmlc wmlc;application/vnd.wap.xhtml+xml xhtml;application/vnd.google-earth.kml+xml kml;application/vnd.google-earth.kmz kmz;application/x-7z-compressed 7z;application/x-cocoa cco;application/x-java-archive-diff jardiff;application/x-java-jnlp-file jnlp;application/x-makeself run;application/x-perl pl pm;application/x-pilot prc pdb;application/x-rar-compressed rar;application/x-redhat-package-manager rpm;application/x-sea sea;application/x-shockwave-flash swf;application/x-stuffit sit;application/x-tcl tcl tk;application/x-x509-ca-cert der pem crt;application/x-xpinstall xpi;application/xspf+xml xspf;application/zip zip;application/vnd.oasis.opendocument.chart odc;application/vnd.oasis.opendocument.chart-template otc;application/vnd.oasis.opendocument.database odb;application/vnd.oasis.opendocument.formula odf;application/vnd.oasis.opendocument.formula-template odft;application/vnd.oasis.opendocument.graphics odg;application/vnd.oasis.opendocument.graphics-template otg;application/vnd.oasis.opendocument.image odi;application/vnd.oasis.opendocument.image-template oti;application/vnd.oasis.opendocument.presentation odp;application/vnd.oasis.opendocument.presentation-template otp;application/vnd.oasis.opendocument.spreadsheet ods;application/vnd.oasis.opendocument.spreadsheet-template ots;application/vnd.oasis.opendocument.text-master otm;application/vnd.oasis.opendocument.text odt;application/vnd.oasis.opendocument.text-template ott;application/vnd.oasis.opendocument.text-web oth;application/vnd.openofficeorg.extension oxt;application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx;application/vnd.openxmlformats-officedocument.presentationml.slide sldx;application/vnd.openxmlformats-officedocument.presentationml.template potx;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx;application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx;application/vnd.sun.xml.calc sxc;application/vnd.sun.xml.calc.template stc;application/vnd.sun.xml.draw sxd;application/vnd.sun.xml.draw.template std;application/vnd.sun.xml.impress sxi;application/vnd.sun.xml.impress.template sti;application/vnd.sun.xml.math sxm;application/vnd.sun.xml.writer.global sxg;application/vnd.sun.xml.writer sxw;application/vnd.sun.xml.writer.template stw;## Mime types for web fonts. Stolen from here:## http://seconddrawer.com.au/blog/ in part.application/x-font-ttf ttf;font/opentype otf;application/vnd.ms-fontobject eot;application/font-woff woff;application/octet-stream bin exe dll;application/octet-stream deb;application/octet-stream dmg;application/octet-stream iso img;application/octet-stream msi msp msm;application/octet-stream vcf;audio/midi mid midi kar;audio/mpeg mpga mpega mp2 mp3;audio/ogg ogg;audio/x-m4a m4a;audio/x-realaudio ra;audio/webm weba;video/3gpp 3gpp 3gp;video/mp2t ts;video/mp4 mp4;video/mpeg mpeg mpg mpe;video/ogg ogv;video/quicktime mov;video/webm webm;video/x-flv flv;video/x-m4v m4v;video/x-mng mng;video/x-ms-asf asx asf;video/x-ms-wmv wmv;video/x-msvideo avi;}Create the file
/etc/nginx/lib/koi-win
and add the following to it:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101charset_map koi8-r windows-1251 {80 88 ; ## euro95 95 ; ## bullet9A A0 ; ##9E B7 ; ## ·A3 B8 ; ## small yoA4 BA ; ## small Ukrainian yeA6 B3 ; ## small Ukrainian iA7 BF ; ## small Ukrainian yiAD B4 ; ## small Ukrainian soft gAE A2 ; ## small Byelorussian short uB0 B0 ; ## °B3 A8 ; ## capital YOB4 AA ; ## capital Ukrainian YEB6 B2 ; ## capital Ukrainian IB7 AF ; ## capital Ukrainian YIB9 B9 ; ## numero signBD A5 ; ## capital Ukrainian soft GBE A1 ; ## capital Byelorussian short UBF A9 ; ## (C)C0 FE ; ## small yuC1 E0 ; ## small aC2 E1 ; ## small bC3 F6 ; ## small tsC4 E4 ; ## small dC5 E5 ; ## small yeC6 F4 ; ## small fC7 E3 ; ## small gC8 F5 ; ## small khC9 E8 ; ## small iCA E9 ; ## small jCB EA ; ## small kCC EB ; ## small lCD EC ; ## small mCE ED ; ## small nCF EE ; ## small oD0 EF ; ## small pD1 FF ; ## small yaD2 F0 ; ## small rD3 F1 ; ## small sD4 F2 ; ## small tD5 F3 ; ## small uD6 E6 ; ## small zhD7 E2 ; ## small vD8 FC ; ## small soft signD9 FB ; ## small yDA E7 ; ## small zDB F8 ; ## small shDC FD ; ## small eDD F9 ; ## small shchDE F7 ; ## small chDF FA ; ## small hard signE0 DE ; ## capital YUE1 C0 ; ## capital AE2 C1 ; ## capital BE3 D6 ; ## capital TSE4 C4 ; ## capital DE5 C5 ; ## capital YEE6 D4 ; ## capital FE7 C3 ; ## capital GE8 D5 ; ## capital KHE9 C8 ; ## capital IEA C9 ; ## capital JEB CA ; ## capital KEC CB ; ## capital LED CC ; ## capital MEE CD ; ## capital NEF CE ; ## capital OF0 CF ; ## capital PF1 DF ; ## capital YAF2 D0 ; ## capital RF3 D1 ; ## capital SF4 D2 ; ## capital TF5 D3 ; ## capital UF6 C6 ; ## capital ZHF7 C2 ; ## capital VF8 DC ; ## capital soft signF9 DB ; ## capital YFA C7 ; ## capital ZFB D8 ; ## capital SHFC DD ; ## capital EFD D9 ; ## capital SHCHFE D7 ; ## capital CHFF DA ; ## capital hard sign}Create the file
/etc/nginx/lib/koi-utf
and add the following to it:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107## This map is not a full koi8-r utf8 map: it does not contain## box-drawing and some other characters. Besides this map contains## several koi8-u and Byelorussian letters which are not in koi8-r.## If you need a full and standard map, use contrib/unicode2nginx/koi-utf## map instead.charset_map koi8-r utf-8 {80 E282AC ; ## euro95 E280A2 ; ## bullet9A C2A0 ; ##9E C2B7 ; ## ·A3 D191 ; ## small yoA4 D194 ; ## small Ukrainian yeA6 D196 ; ## small Ukrainian iA7 D197 ; ## small Ukrainian yiAD D291 ; ## small Ukrainian soft gAE D19E ; ## small Byelorussian short uB0 C2B0 ; ## °B3 D081 ; ## capital YOB4 D084 ; ## capital Ukrainian YEB6 D086 ; ## capital Ukrainian IB7 D087 ; ## capital Ukrainian YIB9 E28496 ; ## numero signBD D290 ; ## capital Ukrainian soft GBE D18E ; ## capital Byelorussian short UBF C2A9 ; ## (C)C0 D18E ; ## small yuC1 D0B0 ; ## small aC2 D0B1 ; ## small bC3 D186 ; ## small tsC4 D0B4 ; ## small dC5 D0B5 ; ## small yeC6 D184 ; ## small fC7 D0B3 ; ## small gC8 D185 ; ## small khC9 D0B8 ; ## small iCA D0B9 ; ## small jCB D0BA ; ## small kCC D0BB ; ## small lCD D0BC ; ## small mCE D0BD ; ## small nCF D0BE ; ## small oD0 D0BF ; ## small pD1 D18F ; ## small yaD2 D180 ; ## small rD3 D181 ; ## small sD4 D182 ; ## small tD5 D183 ; ## small uD6 D0B6 ; ## small zhD7 D0B2 ; ## small vD8 D18C ; ## small soft signD9 D18B ; ## small yDA D0B7 ; ## small zDB D188 ; ## small shDC D18D ; ## small eDD D189 ; ## small shchDE D187 ; ## small chDF D18A ; ## small hard signE0 D0AE ; ## capital YUE1 D090 ; ## capital AE2 D091 ; ## capital BE3 D0A6 ; ## capital TSE4 D094 ; ## capital DE5 D095 ; ## capital YEE6 D0A4 ; ## capital FE7 D093 ; ## capital GE8 D0A5 ; ## capital KHE9 D098 ; ## capital IEA D099 ; ## capital JEB D09A ; ## capital KEC D09B ; ## capital LED D09C ; ## capital MEE D09D ; ## capital NEF D09E ; ## capital OF0 D09F ; ## capital PF1 D0AF ; ## capital YAF2 D0A0 ; ## capital RF3 D0A1 ; ## capital SF4 D0A2 ; ## capital TF5 D0A3 ; ## capital UF6 D096 ; ## capital ZHF7 D092 ; ## capital VF8 D0AC ; ## capital soft signF9 D0AB ; ## capital YFA D097 ; ## capital ZFB D0A8 ; ## capital SHFC D0AD ; ## capital EFD D0A9 ; ## capital SHCHFE D0A7 ; ## capital CHFF D0AA ; ## capital hard sign} - Lets populate
/etc/nginx/key
:Generate DH parameters file with 2048 bit long safe prime:1openssl dhparam 2048 -out /etc/nginx/key/dh_param.pemGenerate HTTP Authentication:
12htpasswd /etc/nginx/key/.htpasswd-users adminchown apache. /etc/nginx/key/.htpasswd-usersThis command will prompt password for the new user with the name
admin
. - Lets populate
/etc/nginx/apps
:Create the file/etc/nginx/drupal/static_files_handler.conf
and add the following to it:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260## Pagespeed optimized resources that returns 404, redirect to original resourcelocation ~* (.+)/x(.+),(.+).pagespeed.[.-_[:alnum:]]+$ {## Handle resources with query string and Pagespeed optimized resources with## file name prefixed with x (eg. xMyImage.png,qitok=qwer.pagespeed.asdf.webp)error_page 404 = @orig-resource;set $orig_resource_uri $1/$2?$3;try_files $uri $uri/ $orig_resource_uri;}location ~* (.+),(.+).pagespeed.[.-_[:alnum:]]+$ {## Handle resources with query stringerror_page 404 = @orig-resource;set $orig_resource_uri $1?$2;try_files $uri $uri/ $orig_resource_uri;}location ~* (.+)/x(.+).pagespeed.[.-_[:alnum:]]+$ {## Handle Pagespeed optimized resources with file name prefixed with x## (eg. xMyImage.png.pagespeed.asdf.webp)error_page 404 = @orig-resource;set $orig_resource_uri $1/$2;try_files $uri $uri/ $orig_resource_uri;}location ~* (.+).pagespeed.[.-_[:alnum:]]+$ {## Default handlererror_page 404 = @orig-resource;set $orig_resource_uri $1;try_files $uri $uri/ $orig_resource_uri;}## Regular private file serving.location ^~ /system/files/ {include utils/service/php_pass.conf;## For not signalling a 404 in the error log whenever the## system/files directory is accessed add the line below.## Note that the 404 is the intended behaviour.log_not_found off;}## Trying to access private files directly returns a 404.location ^~ /sites/[.-[:alnum:]]+/files/private/ {internal;}location ^~ /sites/[.-[:alnum:]]+/private/ {internal;}## Support for the file_force module## https://drupal.org/project/file_force.location ^~ /system/files_force/ {include utils/service/php_pass.conf;## For not signalling a 404 in the error log whenever the## system/files directory is accessed add the line below.## Note that the 404 is the intended behaviour.log_not_found off;}## If accessing an image generated by Drupal 6 imagecache, serve it## directly if available, if not relay the request to Drupal to (re)generate## the image.location ~* /imagecache/ {## Image hotlinking protection. If you want hotlinking## protection for your images uncomment the following line.include map/hotlinking_protection_allowed_hosts.conf;access_log off;expires 30d;try_files $uri $uri/ @drupal;}## Drupal 7 generated image handling, i.e., imagecache in core. See:## https://drupal.org/node/371374.location ~* /files/styles/ {## Image hotlinking protection. If you want hotlinking## protection for your images uncomment the following line.include map/hotlinking_protection_allowed_hosts.conf;access_log off;expires 30d;try_files $uri $uri/ @drupal;}## Advanced Aggregation module CSS/JS## support. https://drupal.org/project/advagg.location ~ ^/sites/[.-[:alnum:]]+/files/advagg_(?:css|js)/ {location ~* (?:css|js)[_-[:alnum:]]+.(?:css|js)(.gz)?$ {access_log off;expires max;gzip_static on;add_header ETag '';add_header Accept-Ranges '';## Set a far future Cache-Control header to 52 weeks and add no-transform## to make Pagespeed bypass these CSS/JS optimized by advagg moduleadd_header Cache-Control 'max-age=31449600, no-transform, public';## Inheritance Rules for add_header Directives## Because this 'server' block contains another 'add_header' directive,## we must redeclare the 'add_header' from 'http' contextinclude utils/mod_header.conf;add_header Strict-Transport-Security $hsts;try_files $uri $uri/ @drupal;}}## All static files will be served directly.location ~* ^.+.(?:css|cur|json|js|jpe?g|gif|htc|ico|png|txt|otf|ttf|eot|woff|svg|webp|webm|zip|gz|tar|rar)$ {access_log off;expires 30d;## No need to bleed constant updates. Send the all shebang in one## fell swoop.tcp_nodelay off;## Set the OS file cache.open_file_cache max=3000 inactive=120s;open_file_cache_valid 45s;open_file_cache_min_uses 2;open_file_cache_errors off;try_files $uri $uri/ @cache;}## PDFs and powerpoint files handling.location ~* ^.+.(?:pdf|pptx?)$ {access_log off;expires 30d;## No need to bleed constant updates. Send the all shebang in one## fell swoop.tcp_nodelay off;try_files $uri $uri/ @drupal;}## MP3 and Ogg/Vorbis files are served using AIO when supported. Your OS must support it.location ~ ^/sites/[.-[:alnum:]]+/files/audio/mp3 {location ~* .*.mp3$ {access_log off;directio 4k; ## for XFS## If you're using ext3 or similar uncomment the line below and comment the above.#directio 512; ## for ext3 or similar (block alignments)tcp_nopush off;aio on;output_buffers 1 2M;try_files $uri $uri/ @drupal;}}location ~ ^/sites/[.-[:alnum:]]+/files/audio/ogg {location ~* .*.ogg$ {access_log off;directio 4k; # for XFS## If you're using ext3 or similar uncomment the line below and comment the above.#directio 512; ## for ext3 or similar (block alignments)tcp_nopush off;aio on;output_buffers 1 2M;try_files $uri $uri/ @drupal;}}## Pseudo streaming of FLV files:## http://wiki.nginx.org/HttpFlvStreamModule.## If pseudo streaming isn't working, try to comment## out in nginx.conf line with:## add_header X-Frame-Options SAMEORIGIN;location ~ ^/sites/[.-[:alnum:]]+/files/video/flv {location ~* .*.flv$ {access_log off;flv;try_files $uri $uri/ @drupal;}}## Pseudo streaming of H264/AAC files. This requires an Nginx## version greater or equal to 1.0.7 for the stable branch and## greater or equal to 1.1.3 for the development branch.## Cf. http://nginx.org/en/docs/http/ngx_http_mp4_module.html.location ~ ^/sites/[.-[:alnum:]]+/files/video/mp4 { # videoslocation ~* .*.(?:mp4|mov)$ {access_log off;mp4;mp4_buffer_size 1M;mp4_max_buffer_size 5M;try_files $uri $uri/ @drupal;}}location ~ ^/sites/[.-[:alnum:]]+/files/audio/m4a { # audioslocation ~* .*.m4a$ {access_log off;mp4;mp4_buffer_size 1M;mp4_max_buffer_size 5M;try_files $uri $uri/ @drupal;}}## Advanced Help module makes each module provided README available.location ^~ /help/ {location ~* ^/help/[^/]*/README.txt$ {access_log off;include utils/service/php_pass.conf;}}## Replicate the Apache directive of Drupal standard## .htaccess. Disable access to any code files. Return a 404 to curtail## information disclosure. Hide also the text files.location ~* ^(?:.+.(?:htaccess|gitignore|txt|engine|inc|info|install|make|module|profile|test|po|sh|.*sql|test|theme|twig|tpl(?:.php)?|xtmpl|yml)(~|.sw[op]|.bak|.orig|.save)?$|^(/.(?!well-known).*|/code-style.pl|/Entries.*|/Repository|/Root|/Tag|/Template|/composer.(json|lock))$|^#.*#$|/.*.php(.sw[op]|.bak|.orig|.save)+)$ {return 404;}## Disallow access to .bzr, .git, .hg, .svn, .cvs directories:## return 404 as not to disclose information.location ^~ /.bzr {return 404;}location ^~ /.git {return 404;}location ^~ /.hg {return 404;}location ^~ /.svn {return 404;}location ^~ /.cvs {return 404;}## Disallow access to patches directory.location ^~ /patches {return 404;}## Disallow access to drush backup directory.location ^~ /backup {return 404;}## Disable access logs for robots.txt.location = /robots.txt {access_log off;## Add support for the robotstxt module## https://drupal.org/project/robotstxt.try_files $uri $uri/ @drupal;}## RSS feed support.location = /rss.xml {try_files $uri $uri/ @drupal;}## XML Sitemap support.location = /sitemap.xml {try_files $uri $uri/ @drupal;}## Support for favicon. Return an 1x1 transparent GIF if it## doesn't exist.location = /favicon.ico {expires 30d;try_files /favicon.png @empty;}Create the file
/etc/nginx/drupal/php_handler.conf
and add the following to it:12345## PHP handlerinclude utils/service/php_pass.conf;include utils/service/microcache_auth.conf;#include utils/service/microcache.conf;We have two options here:
microcache_auth.conf
which uses the Nginx cache for anonymous users only andmicrocache.conf
which uses the Nginx cache for both anonymous and authenticated users. Themicrocache_auth.conf
is enabled by default. Select between the two according to your requirements.Create the file
/etc/nginx/drupal/named_location.conf
and add the following to it:123456789101112131415161718192021222324252627282930## Restrict access to the strictly necessary PHP files. Reducing the## scope for exploits. Handling of PHP code and the Drupal event loop.location @drupal {include apps/drupal/php_handler.conf;## Filefield Upload progress## https://drupal.org/project/filefield_nginx_progress support## through the NginxUploadProgress modules.#track_uploads uploads 60s;}## We define a named location for the Boost cache.location @cache {include apps/drupal/boost.conf;## We try each boost URI in succession, if every one of them## fails then hand it to Drupal.try_files /cache/normal/$host${uri}_${args}.html /cache/normal/$host${uri}_${args}.xml /cache/normal/$host${uri}_${args}.json /cache/normal/$host${uri}_${args}.html.gz /cache/normal/$host${uri}_${args}.xml.gz /cache/normal/$host${uri}_${args}.json.gz /cache/perm/$host${uri}_.css /cache/perm/$host${uri}_.js /cache/$host/0$uri.html /cache/$host/0${uri}/index.html @drupal;}## Return an in memory 1x1 transparent GIF.location @empty {expires 30d;empty_gif;}## Redirect Pagespeed optimized resources that returns 404 to## original resource.location @orig-resource {return 302 $scheme://$server_name$orig_resource_uri;}Create the file
/etc/nginx/drupal/drupal_upload_progress.conf
and add the following to it:123456789101112131415161718192021## Drupal 7 configuration for the Nginx Upload Progress module:## https://github.com/masterzen/nginx-upload-progress-module## This requires the Filefield Nginx Progress module:## https://drupal.org/project/filefield_nginx_progress.## The Nginx module wants ?X-Progress-ID query parameter so## that it report the progress of the upload through a GET## request. But the drupal form element makes use of clean## URLs in the POST.location ~ (?.*)/x-progress-id:(?d*) {rewrite ^ $upload_form_uri?X-Progress-ID=$upload_id;}## Now the above rewrite must be matched by a location that## activates it and references the above defined upload## tracking zone.location ^~ /progress {upload_progress_json_output;report_uploads uploads;}Create the file
/etc/nginx/drupal/drupal_install.conf
and add the following to it:12345678910111213## Directives for installing drupal. This is for drupal 6 and 7.location = /install.php {auth_basic "Restricted Access"; # auth realmauth_basic_user_file key/.htpasswd-users; # htpasswd fileinclude apps/drupal/php_handler.conf;}## This is for drupal 8.location = /core/install.php {auth_basic "Restricted Access"; # auth realmauth_basic_user_file key/.htpasswd-users; # htpasswd fileinclude apps/drupal/php_handler.conf;}Create the file
/etc/nginx/drupal/drupal_cron_update.conf
and add the following to it:12345678910111213141516171819202122232425262728## Configuration file for Drupal if you're not using drush to update your site## or run cron.## XMLRPC. Comment out if not enabled.location = /xmlrpc.php {include apps/drupal/php_handler.conf;}## Restrict cron access to a specific host.location = /cron.php {## If not allowed to run cron then issue a 404 and redirect to the## site root.if ($not_allowed_cron) {return 404 /;}include apps/drupal/php_handler.conf;}## Run the update from the web interface with Drupal 7.location = /authorize.php {include apps/drupal/php_handler.conf;}location = /update.php {auth_basic "Restricted Access"; # auth realmauth_basic_user_file key/.htpasswd-users; # htpasswd fileinclude apps/drupal/php_handler.conf;}Create the file
/etc/nginx/drupal/core.conf
and add the following to it:1234567891011121314151617181920212223242526272829303132333435363738394041424344## Nginx configuration for Drupal## Common Nginx configuration for server contextinclude apps/drupal/common_server_context.conf;## Named locationinclude apps/drupal/named_location.conf;## The 'default' location.location / {## Drupal generated static filesinclude apps/drupal/static_files_handler.conf;try_files $uri $uri/ @cache;}## Drupal index.location = /index.php {include apps/drupal/boost.conf;## We try each boost URI in succession, if every one of them## fails then hand it to Drupal.try_files /cache/normal/$host/_${args}.html /cache/normal/$host/_${args}.html.gz /cache/$host/0.html /cache/$host/0/index.html @drupal;}## Boost stats.location = /boost_stats.php {include apps/drupal/php_handler.conf;}## PHP scipt to log all catch pathslocation = /sites/all/logcatchall.php {include apps/drupal/php_handler.conf;}## Uncomment the line below if you want to enable basic auth for## access to all /admin URIs. Note that this provides much better## protection if use HTTPS. Since it can easily be eavesdropped if you## use HTTP.#include apps/drupal/admin_basic_auth.conf;## Any other attempt to access PHP files returns a 404.location ~* ^.+.php$ {return 404;}Create the file
/etc/nginx/drupal/common_server_context.conf
and add the following to it:12345678910111213141516171819202122232425262728293031323334353637## Common to all hosts Nginx configurations for server context## See the blacklist.conf file at the parent dir: /etc/nginx.## Deny access based on the User-Agent header.if ($bad_bot) {return 444;}## Deny access based on the Referer header.if ($bad_referer) {return 444;}## Protection against illegal HTTP methods. Out of the box only HEAD,## GET and POST are allowed.if ($not_allowed_method) {return 405;}## Limits## limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=60r/s + limit_req zone=req_limit_per_ip burst=5 nodelay## - Set shared memory as 10MB## - Limit requests per IP as following## - Set maximum requests as rate * burst in burst seconds## For example, maximum value is 300(=60*5) requests in 5 seconds in this case## - With nodelay option : Nginx would return 503 response and not handle excessive requests## - Without nodelay option : Nginx would wait (no 503 response) and handle excessive requests with some delay## limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m + limit_conn conn_limit_per_ip 30## - Set shared memory as 10MB## - Limit connections per IP as 30 in this case## - Note that normal browser makes 2~8 connections and SPDY protocol split each connections## - Nginx would return 503 response if connection exceeds this valuelimit_conn connlimit 32;limit_req zone=reqlimit burst=5 nodelay;## PageSpeed filters## Uncomment the line below if Google PageSpeed module is present#include apps/pagespeed/optimize.conf;Create the file
/etc/nginx/drupal/boost.conf
and add the following to it:1234567891011121314151617181920212223242526272829303132## Boost configurationgzip_static on;## Error page handler for the case where $no_boost_cache is 1, POST## request or authenticated.error_page 418 = @drupal;## If $no_boost_cache is 1 then it means that Boost session cookie## is present or uri has wrong dir. So serve the dynamic page.if ($no_boost_cache) {return 418;}## No caching for POST requests.if ($request_method = POST) {return 418;}## Now for some header tweaking. We use a date that differs## from stock Drupal.add_header Expires "Tue, 25 Dec 1977 03:45:00 GMT";## We bypass all delays in the post-check and pre-check## parameters of Cache-Control. Both set to 0.add_header Cache-Control "must-revalidate, post-check=0, pre-check=0";add_header X-DCache "Boost";## Inheritance Rules for add_header Directives## Because this 'server' block contains another 'add_header' directive,## we must redeclare the 'add_header' from 'http' contextinclude utils/mod_header.conf;add_header Strict-Transport-Security $hsts;## Boost doesn't set a charset.charset utf-8;Populate the
/etc/nginx/apps/pagespeed
folder under this guide.To enable Google PageSpeed in your Nginx configuration (make sure first that your Nginx is compiled with PageSpeed module), uncomment the line seen below at
/etc/nginx/nginx.conf
:
1include apps/pagespeed/core.conf;/etc/nginx/apps/drupal/common_server_context.conf
:
1include apps/pagespeed/optimize.conf;/etc/nginx/site-available/template.conf
:
1pagespeed ShardDomain $scheme://$server_name $scheme://s1.{DOM},$scheme://s2.{DOM}; - To enable this Nginx reverse proxy for Apache setup, execute the following:
1ln -s /etc/nginx/utils/apache /etc/nginx/utils/service
1ln -s /etc/nginx/utils/fastcgi /etc/nginx/utils/service - Set permission:
12chmod -R -x /etc/nginxchmod +x /etc/nginx/lib/ /etc/nginx/apps/ /etc/nginx/apps/drupal/ /etc/nginx/apps/pagespeed/ /etc/nginx/key/ /etc/nginx/sites-available/ /etc/nginx/sites-available/admin/ /etc/nginx/sites-available/dev/ /etc/nginx/sites-available/targeted_server_config/ /etc/nginx/sites-enabled/ /etc/nginx/utils/ /etc/nginx/utils/apache/ /etc/nginx/utils/fastcgi/ /etc/nginx/map/ /etc/nginx/ - Restart Nginx:
1systemctl restart nginx
Setup Nginx requirements
- In this tutorial the Apache will use port 8080 and lets open this port to become accessible:
1234iptables -I INPUT -p tcp -m tcp --dport 8080 -j ACCEPTiptables --line -vnLservice iptables saveservice iptables restart - Create the Nginx cache path folder:
123mkdir /var/cache/nginx/microcachechown apache:root /var/cache/nginx/microcachechmod 700 /var/cache/nginx/microcache - Create Nginx logrotate script:
1vi /etc/logrotate.d/websites_nginx_logs.conf
12345678910/var/log/virtualmin/*nginx_access_log /var/log/virtualmin/*nginx_error_log {rotate 10missingokdailycompresspostrotateservice httpd graceful ; sleep 5endscriptsharedscripts}
Configure Apache
- Since Nginx is reverse proxy to Apache, the IP address that Apache will get is the IP of the server and we need to correct that. Apache 2.4 and above do have mod_remoteip and we will use that module. Open mod_remoteip’s configuration file:
1vi /etc/httpd/conf.d/remoteip.conf
1234# mod_remoteip settingsRemoteIPHeader X-Real-IPRemoteIPInternalProxy 127.0.0.1RemoteIPInternalProxy 188.8.8.8 - Change the port of Apache:
1vi /etc/httpd/conf/httpd.conf
1Listen 80
1Listen 8080 - Restart Apache:
1systemctl restart httpd
Configure Virtualmin
- Set the virtual server template to listen to 8080. Login to Virtualmin, go to “System Settings” -> “Server Templates” -> “Default Settings” and select from the dropdown “Apache Website”. Change the “Port number for virtual hosts” from 80 to 8080. Restart webmin:
1systemctl restart webmin - Lets build the script that will automate the creation of website virtual host Nginx configuration file each time Virtualmin created a new server.Create the file
/usr/local/bin/virtualmin.sh
and add the following to it:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283#!/bin/shfunction update_nginx_conf {cat /etc/nginx/sites-available/${TEMPLATE_FILENAME} > $NGINX_CONF_FILEperl -pi -e "s#{DOM}#${VIRTUALSERVER_DOM}#g" $NGINX_CONF_FILEperl -pi -e "s#{HOME}#${VIRTUALSERVER_HOME}#g" $NGINX_CONF_FILEcat /etc/nginx/sites-available/${TEMPLATE_FILENAME_SSL} > $NGINX_CONF_FILE_SSLperl -pi -e "s#{DOM}#${VIRTUALSERVER_DOM}#g" $NGINX_CONF_FILE_SSLperl -pi -e "s#{HOME}#${VIRTUALSERVER_HOME}#g" $NGINX_CONF_FILE_SSLif [ -f "/etc/nginx/sites-available/targeted_server_config/${VIRTUALSERVER_DOM}.conf" ]thenperl -pi -e "s#{TARGETED_SERVER_CONFIG}#include sites-available/targeted_server_config/${VIRTUALSERVER_DOM}.conf;#g" $NGINX_CONF_FILEperl -pi -e "s#{TARGETED_SERVER_CONFIG}#include sites-available/targeted_server_config/${VIRTUALSERVER_DOM}.conf;#g" $NGINX_CONF_FILE_SSLelseperl -pi -e "s#{TARGETED_SERVER_CONFIG}##g" $NGINX_CONF_FILEperl -pi -e "s#{TARGETED_SERVER_CONFIG}##g" $NGINX_CONF_FILE_SSLfi}NGINX_CONF_FILENAME="${VIRTUALSERVER_DOM}.conf"NGINX_CONF_FILE="/etc/nginx/sites-available/prod/${NGINX_CONF_FILENAME}"NGINX_CONF_FILENAME_SSL="${VIRTUALSERVER_DOM}_ssl.conf"NGINX_CONF_FILE_SSL="/etc/nginx/sites-available/prod/${NGINX_CONF_FILENAME_SSL}"TEMPLATE_FILENAME=template.confTEMPLATE_FILENAME_SSL=template_ssl.confif [ "$VIRTUALSERVER_ACTION" = "CREATE_DOMAIN" ]thenif [ "${VIRTUALSERVER_WEB}" = "1" ]thenupdate_nginx_confif [ "${VIRTUALSERVER_SSL}" = "1" ]thenln -s $NGINX_CONF_FILE_SSL /etc/nginx/sites-enabled/${NGINX_CONF_FILENAME_SSL}elseln -s $NGINX_CONF_FILE /etc/nginx/sites-enabled/${NGINX_CONF_FILENAME}fiif [ -f "/home/${VIRTUALSERVER_USER}/etc/dav.digest.passwd" ]thencat /home/$VIRTUALSERVER_USER/etc/dav.digest.passwd >> /etc/nginx/key/.htpasswd-usersfi/usr/sbin/nginx -s reloadfielif [ "$VIRTUALSERVER_ACTION" = "DELETE_DOMAIN" ]thenif [ "${VIRTUALSERVER_WEB}" = "1" ]thenrm -f /etc/nginx/sites-enabled/${VIRTUALSERVER_DOM}.conf /etc/nginx/sites-enabled/${VIRTUALSERVER_DOM}_ssl.confrm -f /etc/nginx/sites-available/prod/${VIRTUALSERVER_DOM}.conf /etc/nginx/sites-available/prod/${VIRTUALSERVER_DOM}_ssl.confrm -f /var/log/virtualmin/${VIRTUALSERVER_DOM}_nginx_*/usr/sbin/nginx -s reloadfielif [ "$VIRTUALSERVER_ACTION" = "MODIFY_DOMAIN" ]thenif [ "${VIRTUALSERVER_WEB}" = "1" ]thenif [ ! -f $NGINX_CONF_FILE ]thenupdate_nginx_conffifiif [ "$VIRTUALSERVER_DOM" != "$VIRTUALSERVER_OLDSERVER_DOM" ]thenif [ "${VIRTUALSERVER_WEB}" = "1" ]thenrm -f /etc/nginx/sites-available/prod/${VIRTUALSERVER_OLDSERVER_DOM}.conf /etc/nginx/sites-available/prod/${VIRTUALSERVER_OLDSERVER_DOM}_ssl.confrm -f /etc/nginx/sites-enabled/${VIRTUALSERVER_OLDSERVER_DOM}.conf /etc/nginx/sites-enabled/${VIRTUALSERVER_OLDSERVER_DOM}_ssl.confupdate_nginx_confif [ "${VIRTUALSERVER_SSL}" = "1" ]thenln -s $NGINX_CONF_FILE_SSL /etc/nginx/sites-enabled/${NGINX_CONF_FILENAME_SSL}elseln -s $NGINX_CONF_FILE /etc/nginx/sites-enabled/${NGINX_CONF_FILENAME}fififiif [ "${VIRTUALSERVER_WEB}" = "1" ]then/usr/sbin/nginx -s reloadfifi
1chmod u+x /usr/local/bin/virtualmin.sh - Let Virtualmin know about the virtualmin.sh. Login to Virtualmin, go to “System Settings” -> “Virtualmin Configuration” and select from dropdown “Actions upon server and user creation”. Populate the “Command to run after making changes to a server” field with:
1/usr/local/bin/virtualmin.sh