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

Test Internet Connection Speed From Console Over SSH Command Line

aptestI have recently rented a dedicated server for my hobby projects and learning CentOS Linux server. I was informed that I am connected to the 100M/s port. How do I test my Internet connection download speed from the console over the ssh session without using HTML5 or Adobe flash/Java applets based websites? How do I test my upload speed from the console?

I recommend that you use lftp command to test Internet upload and download speed from console. You can run lftp using the ssh client:

[a] wget — Retrieves files from the web (download speed test).

[b] wput — A tiny wget-like ftp-client for uploading files (upload speed test).

[c] axel — Another light download accelerator.

[d] iperf — Perform network throughput tests.

Installation

You can use the following yum command to install lftp and iperf under RHEL / CentOS / Fedora Linux:

# yum install lftp iperf

OR use the following apt-get command under Debian or Ubuntu Linux:

$ sudo apt-get install lftp iperf

Step #1: Find out download url

You need a large size file to test download speed. For example, you can visit the home page of«Argonne National Laboratory Public Software Mirror» to grab Centos Linux ISO file.

Step #2: Use lftp command to test download speed

The syntax is:

lftp -e 'pget http://example.com/file.iso; exit; '
lftp -e 'pget http://speedtest.example.com/500M.bin; exit; '
lftp -e 'pget http://mirror.anl.gov/pub/centos/6.3/isos/x86_64/CentOS-6.3-x86_64-LiveCD.iso; exit; '

Sample outputs:

Fig.01: lftp testing internet speed
You will also get the report as follows:

725617504 bytes transferred in 65 seconds (10.63M/s)

A note about wget command

You can use the wget command as follows for testing download speed:

$ wget -O /dev/null http://mirror.anl.gov/pub/centos/6.3/isos/x86_64/CentOS-6.3-x86_64-LiveCD.iso

Sample outputs:

Fig.02: wget command in action

Step #3: Use lftp command to test upload speed
The sytnax is as follows:

lftp -u userName ftp.example.com -e 'put largecd1.avi; bye'
lftp -u userName,passWord ftp.example.com -e 'put largecd1.avi; bye'
lftp -u userName,passWord ftp.example.com -e 'put /path/to/large.iso; bye'

In this example, I am uploading a file to my private ftp server:

lftp -u admin homeserver -e 'cd video; put /home/vivek/Downloads/debian-testing-amd64-CD-1.iso; bye'

OR

lftp -u admin homeserver.public.ip.here -e 'cd video; put /home/vivek/Downloads/debian-testing-amd64-CD-1.iso; bye'

Sample outputs:

Fig.03: lftp upload speed test in action

How do I test network throughput rate between two Linux or Unix servers?
Consider the following setup:

+------------------+                            +----------------+
| Linux server A    +------- ISP Internet-------+ Linux server B +
+------------------+                            +----------------+
IP:202.54.1.1                                     IP:203.54.1.1
iperf server                                      iperf client

Iperf is a tool to measure maximum TCP bandwidth, allowing the tuning of various parameters and UDP characteristics. Iperf reports bandwidth, delay jitter, datagram loss. On server A start iperf as follows:

# iperf -s -B 202.54.1.1

On server B type the same command as follows:

# iperf -c 202.54.1.1 -d -t 60 -i 10

Sample outputs:

Fig.04: iperf client in action
Where,

  1. -s : Run in server mode.
  2. -B IP : Bind to IP, an interface or multicast address.
  3. -c IP : Run in client mode, connecting to IP.
  4. -d : Do a bidirectional test simultaneously.
  5. -t 60 : Time in seconds to transmit for (default 10).
  6. -i 10 : Pause n seconds between periodic bandwidth reports.

RECOMMENDED READINGS
See the following man pages for information:

man lftp
man wget
man iperf

SSH — беспарольная аутентификация с помощью ssh-agent

Генерируем приватный и публичный ключи для сервера с паролем:

root@priovtb-sftp:~# ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/root/.ssh/id_dsa):
/root/.ssh/id_dsa already exists.
Overwrite (y/n)? y
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_dsa.
Your public key has been saved in /root/.ssh/id_dsa.pub.
The key fingerprint is:
fe:61:e8:3e:0e:56:b5:13:c1:c7:f0:fe:fd:78:21:fa root@priovtb-sftp
The key's randomart image is:
+--[ DSA 1024]----+
|         .oo     |
|          .oo    |
|          o..    |
|         . +     |
|        S o .    |
|       o . . o o |
|      o o o . o o|
|     . o.o o   .o|
|       o+.. .E...|
+-----------------+

Запустим ssh-agent:

root@priovtb-sftp:~# exec ssh-agent /bin/bash

Проверим, какие ключи хранит в себе ssh-agent:

root@priovtb-sftp:~# ssh-add  -l
The agent has no identities.

Ключей пока нет.

Добавляем приватный ключ:

root@priovtb-sftp:~# ssh-add ~/.ssh/id_dsa
Enter passphrase for /root/.ssh/id_dsa:
Identity added: /root/.ssh/id_dsa (/root/.ssh/id_dsa)

Пробуем соединиться с хостом. Хост запрашивает пароль, потому что ключа пока нет.

root@priovtb-sftp:~# ssh 10.50.10.75
root@10.50.10.75's password:
^C

Заливаем на хост наш ключ. В процессе заливки ключа, хост запросит пользовательский пароль хоста:

root@priovtb-sftp:~# scp /root/.ssh/id_dsa.pub 10.50.10.75:~/.ssh/authorized_keys
root@10.50.10.75's password:
id_dsa.pub                       100%  607     0.6KB/s   00:00

Ключ на хосте. Пробуем соединиться по SSH:

root@priovtb-sftp:~# ssh 10.50.10.75
Linux lina 2.6.32-5-686 #1 SMP Mon Mar 26 05:20:33 UTC 2012 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Mar 29 15:25:00 2012 from 10.50.10.39
root@malina:~# exit
logout
Connection to 10.50.10.75 closed.
root@priovtb-sftp:~#

Отлично. Аутентификация прошла без запроса пароля, но при этом сам ключ запаролен. 🙂

Cisco ASA — Enable SSH

asa1# conf term
asa1(config)# crypto key generate rsa
INFO: The name for the keys will be:
Keypair generation process begin. Please wait...

asa1(config)# show crypto key mypubkey rsa
Key pair was generated at: 16:24:10 UTC Jan 6 2009
Key name:
Usage: General Purpose Key
Modulus Size (bits): 1024
Key Data:

xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxx

ssh 192.168.1.25 255.255.255.255 inside
ssh timeout 30
ssh version 2
username cisco password xxxxxxx
aaa authentication ssh console LOCAL

Включение SSH на Cisco ASA 5510

Once you are done with the basic configuration of Cisco ASA 5510, the next step is to enable SSH access from remote computers internally or externally, Steps involved in configuring SSH is as follows

[cc lang=»text»]
Firewall_5510# config t
Firewall_5510(config)# enable password xxxxx(your password)
[/cc]

Enable password is necessary to enable ssh access

[cc lang=»text»]
Firewall_5510(config)# username test password test123
[/cc]

User name and password for connecting using ssh

[cc lang=»text»]
Firewall_5510(config)# aaa authentication ssh console LOCAL
[/cc]

Different authentication can be  configured, like RADIUS, TACACS+, etc.., here we specified Local authentication with user name and password mentioned above

[cc lang=»text»]
Firewall_5510(config)# ssh 192.168.x.x 255.255.255.o inside
[/cc]

Permit ssh access to firewall from specified ip or subnet, inside

[cc lang=»text»]
Firewall_5510(config)# domain-name TEST.ORG
[/cc]

Domain name of your company. RSA key is generated using domain name + firewall name combination

[cc lang=»text»]
Firewall_5510(config)# crypto key generate rsa modulus 1024
[/cc]

Generate RSA key

You are done !!!!!!!!!!!!!!!!!!!!!!

now the firewall can be accessed from inside network……………………

Переподключение к сеансу SSH

В настройках SSH поставил «не завершать сеанс при разрыве». После переподключения не знаю как присовокупиться к висящему сеансу.

В инете рекомендуют использовать screen, который позволяет использовать несколько псевдотерминалов и подключаться к ним по мере необходимости.
http://libc6.blogspot.com/2008/09/screen-terminal.html

Попробую использовать его вместо bash, как оболочку по умолчанию для ssh-сеансов.

Как настроить автоматический запуск screen при входе по ssh

Достало постоянно вводить screen -dR при входе на удалённую машину. Погуглив нашёл простое решение. В конце ~/.bashrc дописать:

 if [ -z "$STY" ]; then
 exec screen -dR
 fi

У меня чуть более продвинутый вариант 🙂

В конец .bashrc надо добавить

if [ "$SSH_TTY" ]; then
 if [ ! "$STY" ]; then
  CHOICE=`SCREEN/choose`
  if [ -z "$CHOICE" ];
  then
   exec screen
  else
   exec screen -dr $CHOICE
  fi
 fi
fi

и создать файл ~/SCREEN/choose:

#!/bin/bash
USERNAME=`whoami`
i=0
declare -ax SCREENS
SOCKETS=`find /var/run/screen/S-$USERNAME -type p`
if [ -z "$SOCKETS" ];
then
exit 0
fi
for S in $SOCKETS
do
((i=$i+1))
S=`basename $S`
SCREENS[$i]=`screen -ls | grep $S | perl -e '$s=<>; $s =~ s/^\\t(.*)\s/$1/; $s =~ s/\s/_/g; print $s'`
done
MENU=""
for ((j=1; j do
MENU="$MENU $j ${SCREENS[$j]}"
done
WHICH=`dialog --stdout --menu Select: 0 0 0 $MENU`
echo ${SCREENS[$WHICH]} | sed -e 's/_(.*)$//'

При логине будет предлагаться меню со списком имеющихся сессий screen, можно выбрать нужную либо создать новую. Если запущенных screen’ов нет, автоматически запустится новая сессия.

Единственная (вроде бы) зависимость — нужно поставить dialog.

Ссылки:
http://www.truediamon.ru/content/kak-nastroit-avtomaticheskij-zapusk-screen-pri-vhode-po-ssh

Авторизация SSH по RSA ключу


Для начала создадим алиасы устройств — вместо длинной записи ssh -l user 192.168.0.1 будем использовать, например, ssh router. Красиво и эстетично! Для организации такой красоты достаточно создать конфигурационный файл SSH (если у вас его еще нет).

user$ mkdir ~/.ssh
user$ cd ~/.ssh
user$ nano config

Примерно такого содержания

Host router
    HostName 192.168.0.1
    User user
    Port 22

Немного поясню:

  • Host — наш алиас к устройству, по которому будем вызывать
  • HostName — имя или IP адрес устройства
  • User — имя пользователя для подключения к устройству
  • Port — номер порта SSH, если переопределено

Каждый алиас необходимо прописать соответствующим блоком, например, можно создать алиасы к одному устройству с разными именами пользователей. Теперь можно вызывать ssh router. Параметры для подключения к устройству router считаются из конфигурационного файла, который мы только что создали. Замечательно! Далее настроим, чтоб при подключении удаленное устройство не спрашивало пароль. Для таких целей достаточно создать пару RSA ключей и один из них поместить на удаленное устройство. Перед генерацией ключа проверим необходимые параметры в настройках системы на стороне клиента/etc/ssh/ssh_config.

user$ sudo nano /etc/ssh/ssh_config

Ищем нужный нам параметр, должно быть так

..
IdentityFile ~/.ssh/id_rsa
..

Подготовку сделали, можно генерировать пару RSA ключей

user$ ssh-keygen -t rsa

Отвечаем на несколько вопросов — нажимаем Enter 😉

Generating public/private rsa key pair.
Enter file in which to save the key (/home/user.ssh/id_rsa): <span style="color: red; font-weight: bold;"><-Enter</span>
Enter passphrase (empty for no passphrase): <span style="color: red; font-weight: bold;"><-Enter</span>
Enter same passphrase again: <span style="color: red; font-weight: bold;"><-Enter</span>
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
b6:a0:23:59:54:79:67:44:0f:e8:24:6b:5b:01:be:9b user@desktop
The key's randomart image is:
+--[ RSA 2048]----+
|  o++=*o         |
| . .oo.oo        |
|  + o  o.        |
| . =             |
|  o +   S        |
|   = + o         |
|  E o .          |
|   . .           |
|                 |
+-----------------+

Пара RSA ключей готова, теперь публичный ключ необходимо передать на удаленное устройство. Но перед этой операцией проверим настройки на удаленном устройстве /etc/ssh/ssh_config.

Ищем нужный нам параметр, должно быть так

..
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile %h/.ssh/authorized_keys
..

Параметр AuthorizedKeysFile предписывает, что принятые ключи будут храниться для каждого пользователя отдельно. Можно еще добавить следующие опции, хуже от этого не будет:

  • PermitRootLogin no — разрешается ли пользователю root логиниться по SSH. Лучше запретить, при необходимости права себе можно повысить, например, sudo.
  • PermitEmptyPasswords no — разрешить использовать пустые пароли. Даже не знаю для чего такую опцию оставили, если только для лабораторных отладок.
  • AllowUsers — указывает список пользователей, под которыми можно входить по SSH. Очень полезная опция! Если таковой нет в вашем конфиге — создайте ее. Формат AllowUsers user1 user2. В качестве логинов можно указывать user1@example.com (или user1@192.168.0.22), позволит логиниться пользователю user1 только с адреса example.com и 192.168.0.22
  • Port — указывает прослушиваемый демоном SSHD порт. По-умолчанию  — 22, для повышения безопасности лучше сменить его на что-то выходящее за пределы 1024 или еще лучше, за пределы 10000. К примеру поставить 55555, легко запоминается, а вот nmap’ом не просканишь.

Все готово. Передаем ключ на удаленное устройство.

user$ ssh-copy-id router

После успешного прохождения аутентификации ключ будет передан на удаленное устройство

Now try logging into the machine, with "ssh 'router'", and check in:
  .ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.

Пробуем подключится

user$ ssh router

Подключение успешно. Теперь подключаться к настроенным удаленным устройствам одно удовольствие. Вводим одну короткую команду и вуаля — вы уже управляете удаленным устройством. Надо заметить, что при подключении с другого устройства вам необходимо ввести все параметры подключения и пароль, но никто не запрещает вам повторить выше описанную процедуру и с этим устройством. Если, конечно, это необходимо. Приятной работы.