Tag Archives: nginx

Configuring NGINX Load Balancer Reverse Proxy

Below is example of NGINX reverse proxy with 2 backend load balanced:

upstream backend {
  ip_hash;
  server localhost:8080 fail_timeout=3;
  server localhost:8081 fail_timeout=3;
}

server {
  listen 80;
  server_name mydomain.com;

  location / {
    proxy_pass http://backend/;
    proxy_redirect default;
    proxy_cookie_domain localhost mydomain.com;
  }
}
  • The upstream directive defines a cluster named backend of 2 backend servers (localhost:8080 and localhost:8081). fail_timeout parameter specifies request to the node will be deemed fail if no response is obtained after 3 seconds.
  • The ip_hash directive causes request coming from same ip to be associated with the same backend. This is often called sticky session. Other popular strategy is using cookie.
  • The cluster name backend is referenced by proxy_pass directive inside location

Add down parameter to avoid request being passed to specific backend:

upstream backend {
  ip_hash;
  server localhost:8080 fail_timeout=3;
  server localhost:8081 fail_timeout=3 down;
}

This is handy when performing no-outage release.

Don’t forget to reload the configuration using nginx -s reload

Read Related NGINX Docos

AWS EC2 Nginx Reverse Proxy And localhost Slowness

This is something really odd I yet to fully understand, but for time being I’ve decided using localhost on AWS ec2 is bad. (at least on Windows Server 2008 R2)

I think it might have something to do with internal DNS or address routing, but my nginx-reverse-proxied tomcat is 4-5x slower when I bind it into localhost as opposed of the local IP. We’re talking 1 minute to load a 300kb css file!

Open a command prompt and run ipconfig /all and your local ip should be under IPv4 Address under Ethernet adapter Local Area Connection 2:

ec2-local-ip

On tomcat, edit your server.xml, find your element and add address attribute:


And finally update nginx.conf to point the reverse proxy backend to above IP.

After doing this now my reverse proxy is much faster, only few seconds to load 300kb css file.

IP Whitelisting wp-admin In Nginx

Similar like Apache, Nginx also has allow & deny directives allowing you to block certain ip. Here’s a config I use to whitelist /wp-admin to certain IP only.

location / {
  try_files $uri $uri/ /index.php?$args;
}

location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
  access_log off; log_not_found off; expires max;
}

location ~ \.php$ {
  try_files                $uri =404;
  fastcgi_pass             localhost:9000;
  fastcgi_index            index.php;
  fastcgi_param            SCRIPT_FILENAME  $document_root$fastcgi_script_name;
  fastcgi_intercept_errors on;
  include                  fastcgi_params;
}

location ~ ^/wp-(admin|login) {
  allow /32;
  deny  all;
  location ~ \.php$ {
    try_files                $uri =404;
    fastcgi_pass             localhost:9000;
    fastcgi_index            index.php;
    fastcgi_param            SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_intercept_errors on;
    include                  fastcgi_params;
  }
}

Apart from any path starting with /wp-admin, this will also restrict /wp-login.php to specified IP only.

Hopefully this come handy when you’re configuring wordpress using nginx php-fpm.

WordPress Config For Nginx PHP-FPM

Here’s how you can setup nginx and php-fpm for use with wordpress. It is assumed you have nginx and and php-fpm installed.

Goals / Environment

  • Domain mycooldomain1.com pointing to (http only)
  • wordpress installed on /usr/share/mycooldomain1.com_wordpress
  • php-fpm listening on localhost port 9000

On your nginx.conf (typically located at /etc/nginx/nginx.conf), add following server element somewhere down the inner-bottom of http:

http {
  ...
  server {
    listen      80;
    server_name mycooldomain1.com;
    access_log  /var/log/nginx/mycooldomain1.com.access.log main;
    error_log   /var/log/nginx/mycooldomain1.com.error.log;
    root        /usr/share/mycooldomain1.com_wordpress;
    index       index.php index.html index.htm;

    # This location block matches everything, but subsequently the first matching
    # regex location block (the ones starting with ~) will be used instead if any.
    # The try_files statement below will check if the request matches any file or
    # directory and serve it directly, otherwise it will redirect into /index.php
    # for nice permalink URLs processing
    location / {
      try_files $uri $uri/ /index.php?$args;
    }

    # Avoid logging these extensions and set maximum cache expiry. This is as
    # recommended by http://codex.wordpress.org/Nginx
    location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
      access_log off; log_not_found off; expires max;
    }

    # Any requests ending with .php will be processed using this block instead of above,
    # including request to root (http://mycooldomain1.com/). This is true because we've set 
    # index.php to be one of the index file searched above
    location ~ \.php$ {
      try_files      $uri =404;
      fastcgi_pass   localhost:9000;
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
      include        fastcgi_params;
    }
  }
}

The directive include fastcgi_params imported directives from external file. fastcgi_params is a default file which comes with nginx / php-fpm installation, in case you don’t have it here’s the default fastcgi_params I have on my box.

Restart both nginx and php-fpm once you’ve updated the config:

sudo service nginx restart
sudo service php-fpm restart

And yes nginx config is pretty mundane to learn and debug. I’ve spent few hours reading the official doc as well as various posts to make it work. One most important paragraph of the official doc is probably this (from http_core_module location directive)

A location can either be defined by a prefix string, or by a regular expression. Regular expressions are specified with the preceding “~*” modifier (for case-insensitive matching), or the “~” modifier (for case-sensitive matching). To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

Enjoy!

Nginx Virtual Host and Reverse Proxy

Firstly, there’s no such thing as Virtual Host in nginx. , Virtual Host is an apache terminology.

Scenario:

  • Domain mycooldomain1.com pointing to VPS server
  • Nginx running on port 80
  • Tomcat running on port 8080
  • Only inbound TCP traffic to port 80 is allowed through firewall

In your nginx.conf (mine’s on /etc/nginx/nginx.conf), add following inside the http element:

http {
  ...
  server {

    server_name mycooldomain1.com;
    access_log /var/log/nginx/mycooldomain1.com.access.log main;
    error_log /var/log/nginx/mycooldomain1.com.error.log;

      location / {
        proxy_pass http://localhost:8080;
        proxy_redirect default;
        proxy_cookie_domain localhost mycooldomain1.com;
      }
  }
  ...
}

The server_name and location / expression matches request to http://mycooldomain.com while proxy_pass sets the backend where the response will be fetched from.

proxy_redirect ensures any 3xx redirects and Location: header on response is rewritten into mycooldomain1.com.

If your backend has different context root (eg: http://mycooldomain.com to http://localhost:8080/someapp) you will also need to adjust the cookie path

proxy_cookie_path /someapp/ /;