a proxy server is a mediator server that will forward every request from clients to different destinations. destination server does not see clients directly, so they don't know anything about those clients.

after accepting a request from a client, the proxy server will assign a port to that request and forwards the request to its destination. after receiving the reply on that port, the response will be forwarded to the client through the previous connection.

proxy server

unlike proxy servers, a reverse proxy server resides beside web servers. clients see web servers behind a reverse proxy as one server and can not distinguish them.

reverse proxy server

Reverse proxies forward requests to one or more ordinary servers which handle them. The response from the proxy server is returned as if it came directly from the original server, leaving the client with no knowledge of the origin servers.

    Common Uses For A Reverse Proxy Server:

  • Load Balancing

    A reverse proxy server can act as a load-balancer in front of backend servers and distributing client requests across a group of servers in a manner that maximizes speed and capacity utilization while ensuring none of them is overloaded. If one goes down, the load balancer redirects traffic to the remaining active ones.

  • Web Acceleration

    Reverse proxies can compress requests, as well as cache commonly requested content, which speeds up the flow of traffic between clients and servers.

  • Encryption / SSL Acceleration

    the SSL encryption is often not done by web servers, and instead reverse proxy will handle it. by this, all services across web servers are encrypted and secured just by one configuration.

Installing NGINX

as we write this article current version of NGINX is 1.14.2.

    CentOS/RHEL:

  1. Install the EPEL repository:

    $ sudo yum install epel-release
  2. Update the repository:

    $ sudo yum update
  3. Install NGINX Open Source:

    $ sudo yum install nginx
  4. Verify the installation:

    $ sudo nginx -v

    Debian/Ubuntu:

  1. Update the Debian repository information:

    $ sudo apt-get update
  2. Install the NGINX Open Source package:

    $ sudo apt-get install nginx
  3. Verify the installation:

    $ sudo nginx -v

other installation methods and operating systems are available on this link: Installing NGINX Open Source

Configure NGINX

assume that we have two main services on the server. one is hosted by apache on port 8080 and another one is a nodejs service on port 8090.

URLs for the first service are as follow:

http://localhost:8080/login
http://localhost:8080/home
http://localhost:8080/assets/css/home.css
http://localhost:8080/assets/js/home.js

and here are URLs for the second service:

http://localhost:8090/api
http://localhost:8090/api/getAll
http://localhost:8090/api/set

ok, now let's look at our configuration. the main location of this file is /etc/nginx/nginx.conf. if you can not find that just create it:

1
2
3
4
5
6
server {
    listen 80;
    listen [::]:80;

    server_name example.com; 
}

you should replace example.com with your own domain name.

we have defined a new server on port 80 on line 2. server_name is our domain name. now we want to define our rules for URLs in reverse proxy. just add these lines after server_name.

1
2
3
4
5
6
location /app {
    proxy_pass http://localhost:8080/;
}
location /api {
    proxy_pass http://localhost:8090/api/;
}

as you can see if URL starts with /app, the request will be forwarded to first service.

http://localhost/app/login => http://localhost:8080/login
http://localhost/app/home => http://localhost:8080/home
http://localhost/api/getAll => http://localhost:8090/api/getAll
http://localhost/app/xxxx => http://localhost:8080/xxxx
http://localhost/api/xxxx => http://localhost:8090/api/xxxx

Advanced Configuration

real-time web applications often do not buffer data, so we may also want to disable it on the reverse proxy server.

1
2
3
4
location /api {
    proxy_pass http://localhost:8090/api/;
    proxy_buffering off;
}

you may also need to set or add headers to the requests:

1
2
3
4
5
location /app {
    proxy_pass http://localhost:8080/;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
}

This configuration uses the built-in $remote_addr variable to send the IP address of the original client to the proxy host.

By default, the Host header from the request is not forwarded but is set based on the proxy_pass statement.

you can use regular expressions for defining custom locations:

1
2
3
location  ~ ^/app/css/(.*)$ {
    proxy_pass   http://localhost:8080/assets/css/$1;
}
http://localhost/app/css/home.css => http://localhost:8080/assets/css/home.css

We also can use rewrite:

1
2
3
4
location  /app/ {
    rewrite    ^/app/dashboard/(.*)$ /app/home?path=$1 break;
    proxy_pass   http://localhost:8080/;
}

If the rewrite rule is hit, the URI specified in the directive is ignored and the full changed request URI is passed to the server:

http://localhost/app/dashboard/addUser => http://localhost:8080/home?path=addUser
http://localhost/app/assets/css/home.css => http://localhost:8080/assets/css/home.css

Using NGINX Load Balancer

Define servers that you want to balance request loads on them:

1
2
3
4
5
upstream backend {
    server 10.1.0.101; 
    server 10.1.0.102;
    server 10.1.0.103;
}

now we can use load balancer in location parameter of reverse proxy:

1
2
3
4
5
6
7
server {
    listen 80; 
 
    location / {
       proxy_pass http://backend;
    }
}

SSL Encryption With NGINX

First of all define certifications like this:

1
2
3
4
5
http {
    ssl_certificate     /root/certs/example.com/example.com.crt;
    ssl_certificate_key /root/certs/example.com/example.com.key;
    ssl_ciphers         EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
    ssl_protocols       TLSv1.1 TLSv1.2;

now you can enable https for your servers by this:

1
2
3
4
5
6
7
8
9
10
11
12
server {
    listen              203.0.113.30:443 ssl;
    listen              [2001:DB8::5]:443 ssl;
    server_name         example1.com www.example1.com;
    root                /var/www/example1.com;
}
server {
    listen              203.0.113.40:443 ssl;
    listen              [2001:DB8::6]:443 ssl;
    server_name         example2.com www.example2.com;
    root                /var/www/example2.com;
}