Advanced NGINX Stack Configuration for VPS and Dedicated Servers

In this article, we will cover advanced configuration topics for the WordPress/NGINX Stack on VPS and Dedicated Servers. This includes setting up custom defaults, per-domain include files, and connecting NGINX to external applications, such as Node.js, Python, or Tomcat/Java apps.

Most of the steps in this article require root-level SSH access to your server, and assume basic familiarity with Linux system administration. Check out some of the following articles if you need a refresher:

  • This article covers the WordPress Stack, which is available pre-installed on certain VPS packages, but can be installed on any VPS or Dedicated server.
  • For an in-depth explanation of how NGINX and the rest of the stack work together, please check out our WordPress Hosting Stack article.

Adding custom NGINX directives

It may be desirable to add custom NGINX configuration directives — either to change a global configuration option, or only for a specific domain. Both options will be covered here. However, it should also be noted that in many cases, changing the NGINX configuration is not required (and may not be desirable). For example, you may come across a tutorial that provides a list of NGINX rewrites that can be added to your configuration for a certain WordPress plugin. In most cases, this should actually be done in the Apache configuration (such as in an .htaccess file). Many tutorials that pertain to NGINX assume that Apache is not running “behind” NGINX, so the directives do make sense in those cases. However, if the necessary functionality can only be provided by NGINX, then follow along with the steps below.

Using per-domain includes

It is possible to add custom NGINX directives in the server{} block of the NGINX configuration for a specific domain on your server. For example, this includes adding additional location{} blocks, or defining redirects or rewrites (rewrite).

First, open up /opt/ngxconf/config.yaml with a text editor, such as vim or Nano:

 nano /opt/ngxconf/config.yaml

/opt/ngxconf/config.yaml opened up inside of Nano Change the option allow_user_includes from false to true, then save and exit (in Nano, press Control+X, then Y to confirm saving).

Once this option has been enabled, include files can be created for each domain that requires custom directives. For example, if your user exampl5 owns the domain example.com, then the include file would be created at /home/exampl5/.imh/nginx/example_com.inc.conf. Use an editor such as vim or Nano to edit the file.

Once the include files are created, you’ll need to force-rebuild the NGINX configuration:

 ngxconf -Rrd --force

If you receive a validation error, then run nginx -t to re-validate the configuration, which should report the line that’s causing the error. Then either fix or remove the code from the include file to resolve the problem, and re-run ngxconf -Rrd --force to rebuild again.

This option is disabled by default because it can potentially be abused by untrusted users to bypass local security policies (for example, a user could create an include file to read data from another user’s home directory). For this reason, this option should only be enabled on servers that only you (or a trusted group of people) control. It should NOT be enabled on a server where untrusted users are granted SSH or FTP/SFTP access.

Changing global options

If a global NGINX configuration option needs to be changed or added, this can be accomplished by either editing the file at /etc/nginx/nginx.conf (not recommended), or by creating a new file in /etc/nginx/conf.d. For example:

 nano /etc/nginx/conf.d/custom.conf

This should open up Nano and allow you to add custom directives or configuration values. The configuration options should be intended for use inside of the http{} context — double-check the NGINX documentation for the directive you’re attempting to use to confirm this.

Once you have finished adding custom directives, be sure to test the configuration, then reload NGINX:

 nginx -t service nginx reload

If nginx -t reports an error, then re-open your file and fix any problems before continuing. After fixing, re-check again with nginx -t, then proceed with reloading if validation is successful.

Setting global defaults & overrides

It is possible to define default Cache Manager settings, which will be applied to all domains on the server. This can be handy for PCI compliance, as well as ensuring the cache settings are the same across all domains, without having to manually make these changes for each user. Please note that only one of the options below should be used — they should not be used together.

Setting global defaults

Open /opt/ngxconf/config.yaml with vim or Nano, then enable the following option flag. If the key does not exist, then create it:

 apply_user_default_config: true

Next, create a new file at /opt/ngxconf/defaults.yaml, then populate it with the values you would like to set as defaults for all users. Below is an example that shows how to disable TLSv1 and TLSv1.1, then set a default cache time of 60 minutes.

 --- cache_time_default: 3600 enable_tlsv1: false enable_tlsv1_1: false

Keep in mind that these settings will only be applied when a default configuration is generated. After the defaults have been generated, the user can still modify the values of these options later on. To reset all user configs to defaults, run the following command:

 # WARNING: Running this command will reset any user-chosen configuration options for ALL domains # to the defaults you have set in defaults.yaml (SSL-related options will still be automatically generated) ngxconf -Rrd --defaults --force

Setting global overrides

Open /opt/ngxconf/config.yaml with vim or Nano, then enable the following option flag. If the key does not exist, then create it:

 user_default_override_local: true

Next, create a new file at /opt/ngxconf/defaults.yaml, then populate it with the values you would like to override for all users. Below is an example that shows how to disable TLSv1 and TLSv1.1, then set a default cache time of 60 minutes.

 --- cache_time_default: 3600 enable_tlsv1: false enable_tlsv1_1: false

After making the necessary changes, rebuild the configuration for all users:

 ngxconf -Rrd --force

Available configuration options

Below is a list of all possible configuration values that can be used when creating a default or override configuration. These are the same values that are modified when a change is made in the Cache Manager Plugin in cPanel for a particular domain.

  • pass_all – Passes all requests and responses through to Apache, unchanged. This creates a simple stub server{} block that passes everything to Apache. No other options (with the exception of SSL/TLS) will be taken into consideration if enabled. (default: false)
  • error_page – Specify a custom user-created page to display if the server encounters a 503 (Service Unavailable) or 504 (Gateway Timeout) error (default: ‘/50x.html’ or server default)
  • proxy_proto – Protocol to use when requesting a page from the origin Apache server; this can be set to https to prevent redirect loops in certain applications (default: http; possible values: http, https)

Cache options

  • cache_time_default – Default cache TTL if the origin does not supply an X-Accel-Expires header. X-Accel info (default: 60)
  • cache_time_modsec – Cache TTL for ModSecurity hits that return a 406 status code (default: 0)
  • cache_time_404 – Cache TTL for hits that return a ‘404 Not Found’ status code (default: 10)
  • cache_lock_enable – Enable cache locking; this ensures that only one request is sent to the origin Apache server, even if multiple request that page at the exact same time (default: True)
  • cache_convert_head – Convert HEAD requests to GET requests for the purposes of caching (default: true)
  • cache_honor_cc – When enabled, Cache-Control headers are honored. This is disabled by default, since many CMSes set this value to zero (default: false)
  • cache_honor_expires – When enabled, Expires headers are honored. This is disabled by default, since many CMSes set this value to a time in the past (default: false)
  • cache_honor_cookies – When enabled, Set-Cookie headers from the server are honored. This should be left enabled in most cases. (default: true)
  • cache_bypass_paths[] – List of URIs which will always bypass the cache (default: see below)
  • bypass_cookies[] – List of strings to match in the Request cookies which will trigger a cache bypass. This is important to ensure that logged in users’ pages are not being cached and shown to other visitors. The default setting should work with most WordPress sites, but may need to be updated for certain plugins, or if using a CMS other than WordPress

Server options

  • fast_sending – Sets the postpone_output value to 0 for current server block; this is typically not a good idea if gzip is also enabled (default: false)
  • gzip – Compress response via gzip, using the specified level; 0 = disabled (default: 3)
  • accel_static_content – Bypass Apache to directly serve static content. The server block will use the try_files directive in a location block with a set of specific file extensions (default: true)
  • static_content_paths[] – List of URIs which should be served directly by NGINX (default: [‘/wp-content/uploads’])
  • force_passthru[] – List of URIs which should always be forwarded to Apache (default: [])
  • Rate-limiting ratelimit – Sets the number of requests per minute allowed to login or other rate-limited URIs; set to 0 to disable (default: 15)
  • ratelimit_paths[] – List of URIs which should be rate-limited

SSL/TLS options

  • enable_hsts – If enabled, send a Strict-Transport-Security header (default: false)
  • enable_http2 – Enable http/2 (default: true, if an SSL is installed)
  • force_https – If enabled, all traffic is redirected to https:// (default: false)
  • allow_compat_ciphers – If enabled, export and deprecated ciphers and protocols will be enabled. By default, these will be disabled. (default: false)
  • enable_tlsv1 – Enable TLSv1 support (default: true)
  • enable_tlsv1_1 – Enable TLSv1.1 support (default: true)
  • set_default – Set the current domain as the default. This option adds the default_server option to the NGINX listen directive for this server{} block. This means that this block will be served if the client directly visits an IP address, or their browser does not support SNI (default: false)

Using Node.js, Python, or Tomcat/Java applications with NGINX

One of the major benefits of using a VPS or Dedicated Server is the ability to run your own custom software or services. The steps below will provide a general overview on how to configure NGINX to work with your Node.js, Python, or Java application.

Overriding the default Apache/PHP setup

First, we need to prevent the NGINX configuration tool (ngxconf) from building a configuration for the domain in question. To do this, use vim or Nano to modify the Cache Manager configuration, located at /home/$USER/.imh/nginx/$DOMAIN.yml. For example, if your user exampl5 owns the domain example.com, then the configuration file would be created at /home/exampl5/.imh/nginx/example_com.yml.

 nano /home/exampl5/.imh/nginx/example_com.yml

With the file open, add a new line at the top, with the following content:

 _exclude: true

Creating the new config file

Next, we need to create a new configuration file for your domain. Use a text editor again to create a file in /etc/nginx/conf.d. Example:

 nano /etc/nginx/conf.d/example_com.conf

In this example, we have Node.js listening on port 7000, so we will add a proxy_pass http://127.0.0.1:7000; directive to pass the traffic to our application. Below is a very basic configuration that should be modified to suit your needs:

 server {      listen 80;     server_name example.com www.example.com;      location / {         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;         proxy_set_header X-Real-IP $remote_addr;         proxy_set_header Host $http_host;         proxy_set_header X-Forwarded-Proto $scheme;         proxy_pass http://127.0.0.1:7000;     } }

To add HTTPS support, add the following block to your configuration file (in addition to the one above):

 server {      listen 443 ssl http2;     server_name example.com www.example.com;      ssl on;     ssl_certificate /var/nginx/certs/example-com.pem;     ssl_certificate_key /var/nginx/certs/example-com.key;      ssl_prefer_server_ciphers on;      ssl_session_cache shared:SSL:10m;     ssl_session_timeout 10m;     ssl_buffer_size 8k;       ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;     ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256';     ssl_dhparam /var/nginx/dhparams.pem;      location / {         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;         proxy_set_header X-Real-IP $remote_addr;         proxy_set_header Host $http_host;         proxy_set_header X-Forwarded-Proto $scheme;         proxy_pass http://127.0.0.1:7000;     } }

Remember to update the port number for proxy_pass to match your application, as well as the path to the SSL certificate and key. If you’re unsure of the path to your domain’s SSL certificate and key, you can check with the following command:

 grep ^ssl_certificate /home/USER/.imh/nginx/*.yml

Finally, rebuild the configuration:

 ngxconf -Rrd --force

If all went well, you should now be able to visit your domain and see the results of your configuration. Some applications may require additional configuration to pass through static files. In those cases, please follow the application recommendations, which are typically provided in their documentation.

Troubleshooting

If you receive a validation error when running ngxconf, then double-check your configuration file for errors. Use nginx -t to validation the configuration — it should report any problems, and display exactly which line in the configuration is the source of the error. After resolving the problem, reload NGINX by running:

 service nginx reload

If you receive a 502 Bad Gateway error, then double-check that your application is running, and that the port number is correct. The NGINX error log should have further details — check the last few lines by running:

 tail -10 /var/log/nginx/error.log

If you run into a problem that you can’t seem to resolve, please don’t hesitate to reach out to our Support Team for assistance. Our Managed Hosting team is also experienced in performing custom server setups, and can assist you in integrating external applications with your NGINX configuration.

Leave a Reply