Nginx: setup SSL reverse proxy (load balanced SSL proxy)

776px-Nginx-battleship.svgA reverse proxy is a proxy server that is installed in a server network. Typically, reverse proxies are used in front of Web servers such as Apache, IIS, and Lighttpd. How do I setup nginx web server as SSL reverse proxy?

When you’ve multiple backend web servers, encryption / SSL acceleration can be done by a reverse proxy. Nginx can act as SSL acceleration software. It provided the following benefits:

  • Easy of use : Nginx is easy to setup and upgrade.
  • Security : Nginx provide an additional layer of defense as Apache is behind the proxy. It can protect against common web-based attacks too.
  • Load Distribution : nginx use very little memory and can distribute the load to several Apache servers. It can even rewrite urls on fly.
  • Caching : Nginx act as a reverse proxy which offload the Web servers by caching static content, such as images, css, js, static html pages and much more.
  • Compression : Nginx can optimize and compress the content to speed up the load time.

Our Sample Setup

Internet--
         |
    =============                          |---- apache1 (192.168.1.15)
    | ISP Router|                          |
    =============                          |---- apache2 (192.168.1.16)
         |                                 |
         |                                 |---- db1 (192.168.1.17)
         |      |eth0 -> 192.168.1.11 ----/
         |-lb0==|                        /
         |      |eth1 -> 202.54.1.1:443-/
         |
         |      |eth0 -> 192.168.1.10 -\
         |-lb1==|                       \
                |eth1 -> 202.54.1.1:443--\     
                                          |---- apache1 (192.168.1.15)
                                          |
                                          |---- apache2 (192.168.1.16)
                                          |
                                          |---- db1 (192.168.1.17)
  • lb0 — Linux box directly connected to the Internet via eth1. This is master SSL load balancer.
  • lb1 — Linux box directly connected to the Internet via eth1. This is backup SSL load balancer. This will become active if master networking failed.
  • 202.54.1.1 A virtual IP address that moves between lb0 and lb1. It is managed by keepalived.
  • nginx — It is installed on lb0 and lb1.
  • SSL Certificate — You need to install ssl certificates on lb0 and lb1.

For demonstration purpose I’m going to use Self-signed SSL certificate, but you can use real SSL certificate signed by CAs.

+------+        +-------------+        +-------------------+
|Client| <----> |SSL-Nginx:443| <----> |Apache-HTTP_mode:80|
+------+        +-------------+        +-------------------+
  • You’ve the SSL connection between client and Nginx.
  • Then Nginx act as proxy server and makes unencrypted connection to Apache at port 80.
  • Nginx can cache all static file and other files.

Generating Self-signed Certificate
First, create required directories:

# cd /usr/local/nginx/conf
# mkdir ssl
# cd ssl

To create a private key, enter:

# openssl genrsa -des3 -out nixcraft.in.key 1024

Sample outputs:

openssl-private-key

Fig.01: OpenSSL — Create a Private Key
To create a CSR (Certificate Signing Request):

# openssl req -new -key nixcraft.in.key -out nixcraft.in.csr

Sample outputs:
openssl-create-csr

Fig.02: OpenSSL — Create a CSR (Certificate Signing Request)
Please enter your domain name that you want to associate with the certificate. For example, for the Command Name I entered nixcraft.in as I’m going to use https://nixcraft.in/.

How Do I Remove The Passphrase? (Optional)

You can remove the passphrase so nginx can start on boot without entering the passphrase. Type the following commands

# cp nixcraft.in.key nixcraft.in.key.bak
# openssl rsa -in nixcraft.in.key.bak -out nixcraft.in.key

Finally, you should see three files as follows (note I’ve created all files as vivek user and than moved lb0 and lb1 server /usr/local/ngnix/conf/ssl/ directory):

# ls -l

Sample outputs:

remove-ssl-passphrase

Fig.03: All the files in ssl directory

# openssl x509 -req -days 365 -in nixcraft.in.csr -signkey nixcraft.in.key -out nixcraft.in.crt

Sample outputs:

openssl-create-crt-file

Fig.04: Generating The Actual Self-signed SSL Certificate

How Do I Copy SSL Certificates Files To lb1?

You need to copy those files to lb1, enter:

# ssh root@lb1 mkdir /usr/local/ngnix/conf/ssl
# rsync -av /usr/local/ngnix/conf/ssl/* root@lb1:/usr/local/ngnix/conf/ssl/

Configure Nginx As SSL Reverse Proxy (lb0 and lb1)

Edit nginx.conf, enter (you need to edit files on both lb0 and lb1):

# vi /usr/local/ngnix/conf/nginx.conf

Edit / append as follows:

server {
	### server port and name ###
        listen          202.54.1.1:443;
	ssl 		on;
        server_name     nixcraft.in;

	### SSL log files ###
        access_log      logs/ssl-access.log;
        error_log       logs/ssl-error.log;

	### SSL cert files ###
        ssl_certificate      ssl/nixcraft.in.crt;
        ssl_certificate_key  ssl/nixcraft.in.key;

	### Add SSL specific settings here ###

	ssl_protocols        SSLv3 TLSv1 TLSv1.1 TLSv1.2;
	ssl_ciphers RC4:HIGH:!aNULL:!MD5;
     	ssl_prefer_server_ciphers on;
     	keepalive_timeout    60;
	ssl_session_cache    shared:SSL:10m;
     	ssl_session_timeout  10m;

	### We want full access to SSL via backend ###
     	location / {
	        proxy_pass  http://nixcraft;

		### force timeouts if one of backend is died ##
        	proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;

		### Set headers ####
                proxy_set_header        Accept-Encoding   "";
	        proxy_set_header        Host            $host;
	        proxy_set_header        X-Real-IP       $remote_addr;
	        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

		### Most PHP, Python, Rails, Java App can use this header ###
		#proxy_set_header X-Forwarded-Proto https;##
		#This is better##
	        proxy_set_header        X-Forwarded-Proto $scheme;
		add_header              Front-End-Https   on;

		### By default we don't want to redirect it ####
	        proxy_redirect     off;
      }

Save and close the file. Reload nginx:

# /usr/local/nginx/sbin/nginx -t
# /usr/local/nginx/sbin/nginx -s reload

Verify port is opened:

# netstat -tulpn | grep :443

How Do I Test And Debug SSL Certificates From The Shell Prompt?
Use the openssl command as follows:

$ openssl s_client -connect nixcraft.in:443

Or better use the following command:

$ openssl s_client -connect nixcraft.in:443 -CApath /usr/share/ssl-cert/ -servername nixcraft.in

How Do I Cache Common Files?
Edit nginx.conf and add as follows to cache common files:

location ~* \.(jpg|png|gif|jpeg|css|js|mp3|wav|swf|mov|doc|pdf|xls|ppt|docx|pptx|xlsx)$ {
        proxy_buffering           on;
        proxy_cache_valid 200 120m;
        expires 864000;
}

Save and close the file. Reload nginx:

# nginx -s reload

Proxy-сервер ffproxy

Для того, чтобы быстро установить простой прокси-сервер в Debian можно установить сервер ffproxy.

Для начала установим:

# apt-get install ffproxy

Открываем файл с настройками прокси-сервера

# mcedit /etc/ffproxy/ffproxy.conf

Тут нас интересует несколько строк:

port 8080

— В этой строке можно заменить номер порта нашего прокси-сервера. Например, у меня для прокси-сервера используется порт 3128.

Если компьютер сам подключен к прокси-серверу, то можно указать его параметры, заменив строки

forward_proxy 192.168.10.5
forward_proxy_port 8082

Для того, чтобы раскомментировать их, надо убрать # в начале строки.

Далее заполним список ip-адресов, с которых можно выходить в сеть через наш прокси-сервер:

# mcedit /etc/ffproxy/db/access.ip

там весьма оригинальный формат записи, крайне напоминающий регулярные выражения. Вполне возможно, что это они и есть и можно при помощи них задавать диапазоны айпишников — сам лично не проверял. Например, в моём случае это выглядит так: ^192\.168\.0\.101$ (там есть пример, глядя на который можно не запутаться).

Для того, чтобы разрешить подключения с любого ip-адреса, оставляем в файле только два символа

 .*

для разрешения всех подключений через IPv6 оставим только символ

:

для разрешения всех подключений через IPv4 напишем

 \.

Для запуска/остановки/перезапуска нашего прокси-сервера используем следующие команды:

/etc/init.d/ffproxy start
/etc/init.d/ffproxy stop 
/etc/init.d/ffproxy restart