Saturday, January 26, 2013

Howto Raspberry Pi - Use your Pi as a secure Reverse Proxy gateway to your Web internal Sites and Services



Last update 02/01/2013





The Goal: 


You have a Raspberry Pi and want to use it as your secure Web reverse proxy gateway to access to your various Internal services through your main fully qualified domain name or IP.

Let's say:
  • You have a main router or ISP Box
  • Your Rpi will be in front of the Internet by redirecting http/https por
  • For this configuration to work from both inside and outside your home network, your domain name (here "myowndomain.com") must be associated with your public IP
  • ts from your router to your Rpi
  • You have or not internal servers providing Web sites or services your want to access from your public IP / domain name
We will use:
  • nginx as the great secure reverse proxy instance
  • SSL with auto signed or officially signed certificate to secure our web traffic
  • htpasswd to password protect your shellinbox from being visible and accessible whitout credentials
  • shellinabox to host a nice Web SSH frontend

Summary of steps: 

Step 1: OPTIONAL - Get a fully Qualified Domain Name (FQDN)
Step 2: Manage your SSL certificate
Step 3: Put a Shellinabox in your Pi ^^
Step 4: Install and configure Nginx



Step 1: OPTIONAL - Get a Fully Qualified Domain Name  

This is absolutely optional, but you could think about getting a qualified domain name to access to your home network. (a domain costs very few per year, and your can dynamically associate it with your public IP)

In many cases, when you connect from secure places (such as your company site), trying to access to a web site using its public IP will be prohibited by internals web proxies and firewalls.
By using a fqdn to associate your public IP to a real Internal domain name, your site is as official as any Internet company web site :-)

As an alternative to buy your own domain name, you can also use dynamic free domain name services such as no-ip.org, but most of company proxy will also block them.

And finally, this is just clean and beautiful ^^

In this post, i will assume for the example purpose that your domaine name is "myowndomain.com". (still the fqdn is optional)
  
Step 2: Manage your SSL certificate

Off course, we will want to secure our Web traffic using an SSL certificate, there is 2 ways to achieve this:

1. Generating an "auto-signed" SSL certificate

You can very easily generate an auto-signed SSL certificate, you will have exactly the same security and encrypting level than any official certificate but this certificate won't be officially recognized over the Internet.

That means that when connecting to your site, your Web browser will warn you about the impossibility to guaranty your security connecting to this site, and you have to accept this.

I personally prefer having an official SSL certificate :-)

2. Buy and generate an Officially signed SSL certificate

You can also buy an official SSL certificate for very few, in this case your browser will automatically recognize your certificate as valid and you won't get any warn.

There is some places where you can get a free official SSL certificate for personal use. (look for "startssl")

In both cases, Google is your friend ^^

How to generate an auto signed certificate:

Install OpenSSL:
$ sudo apt-get install openssl

Generate your self signed certificate:
sudo mkdir -p /etc/ssl/localcerts
openssl req -new -x509 -days 3650 -nodes -out /etc/ssl/localcerts/autosigned.crt -keyout /etc/ssl/localcerts/autosigned.key
chmod 600 /etc/ssl/localcerts/*

Note: Respond to OpenSSL questions as you wish, it does not really mind as your certificate is a self-signed anyway


Step 3: Put a shellinabox in your Pi ^^

As explained before, shellinabox is a wonderfull web frontend to SSH, this way you will access to your SSH server without having to deal with an SSH client.

By the past, i wrote an article about an other SSH web frontend "ajaxterm" which is nice too, but in my opinion much more limited and low.
So i recommend to use shellinabox instead.

You will be able to access to your SSH server using standard Web ports even when connecting from places where external SSH traffic is prohibited :-) 

To install:
# sudo apt-get install shellinabox

By default, shellinabox uses the port "4200" to listen to, you can let that as it is as your nginx reverse proxy take care about redirecting our request to this internal service. 

If you want to manage your shellinabox configuration, take a look at main config files:
  • /etc/default/shellinabox
  • /etc/shellinabox/*
Default configuration is ok for us, test your shellinabox by connecting from a browser inside your network: http://<mypiserver>:4200

Note that even if we won't use it, shellinabox comes with embeded SSL auto-signed certificate configuration to redirect http to https and secure your web traffic.


Step 4: Install and configure Nginx

Ok, serious things now, let's install and configure nginx.

Nginx is an extremely powerful Opensource Web server, light secure and fast, that can be used as reverse proxy instance gateway to your internal Web services.

It is more and more used by many companies web site with high load Web Sites, do not hesitate to take a look at official sites:
I used by the past Apache running as a reverse proxy to do this job, but nginx assumes this job with great success, it's very modular and easy to maintain, this is why i recommend your Nginx.

To install:
# sudo apt-get install nginx-full


Now let's configure the beast:

First, some configuration in main config file "/etc/nginx/nginx.conf", here is a sample config file:
# /etc/nginx/nginx.conf

user www-data;
worker_processes 4;
pid /var/run/nginx.pid;

events {
 worker_connections 768;
}

http {

 sendfile on;
 tcp_nopush on;
 tcp_nodelay on;
 keepalive_timeout 65;
 types_hash_max_size 2048;

 include /etc/nginx/mime.types;
 default_type application/octet-stream;

 access_log /var/log/nginx/access.log;
 error_log /var/log/nginx/error.log;

 gzip on;
 gzip_disable "msie6";

 include /etc/nginx/conf.d/*.conf;
 include /etc/nginx/sites-enabled/*;
}

Please note that as Apache configuration style under Debian/Ubuntu, any configuration file (for site or module) included in conf.d or sites-enabled will be loaded at Nginx start

A good practice is to create a symbolic link from "sites-available" to "sites-enabled".

Let's deactivate the default web site we won't use by removing its symbolic link:
$ sudo rm /etc/nginx/sites-enable/default 

Create an htpasswd file that will contain your credentials (adapt <username>)
$ sudo htpasswd -c /etc/nginx/.htpasswd <username>

Now create your main web site configuration file, example:
  • /etc/nginx/sites-available/main
Here is a sample secured configuration:
access_log off;
add_header Cache-Control public;
server_tokens off;


# HTTP 80
server {
 listen         80;
 server_name _;
 rewrite ^ https://myowndomain.com$request_uri? permanent;
}

# HTTPS 443
server  {

 include    /etc/nginx/proxy.conf;

 listen 443 ssl;
 keepalive_timeout 70;

 server_name myowndomain.com;

 # SSL config
 ssl on;
 ssl_certificate /etc/ssl/localcerts/autosigned.crt;
 ssl_certificate_key /etc/ssl/localcerts/autosigned.key;

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

 add_header X-Frame-Options DENY;

 # DDOS protection - Tune Values or deactivate in case of issue
 # limit_conn conn_limit_per_ip 20;
 # limit_req zone=req_limit_per_ip burst=20 nodelay;

 # status for ngxin auditing
 location /nginx-status {
      stub_status on;
      access_log off;
      allow 127.0.0.1;
      deny all;
  }

 location / {
  rewrite ^ https://myowndomain.com/shellinabox/ permanent;
  }

 location /shellinabox/ {
  proxy_pass http://localhost:4200;
                auth_basic            "Access Restricted";
                auth_basic_user_file  "/etc/nginx/.htpasswd";
                access_log /var/log/nginx/shellinabox.access.log;
                error_log /var/log/nginx/shellinabox.error.log;
  }
}

Create the file "/etc/nginx/proxy.conf" with following content:
proxy_redirect          off;
proxy_set_header        Host            $host;
proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

Activate your nginx web site and restart:
sudo ln -s /etc/nginx/sites-enables/main /etc/nginx/sites-available/main
sudo service nginx restart

NOTE:

For this configuration to work from both inside and outside your home network, your domain name (here "myowndomain.com") must be associated with your public IP


Now test accessing to your Web site from both internal and external access :-)

As you understood, you can manage as many internal Web sites as you need through a unique Web instance and virtual hosts. (called location in Nginx)

In the sample config, shellinabox is the default site accessible with your domain name, but you change it and/or add any other internal web sites very easily.

Just add a new location related to your internal Web site you want to be able to access and you're done :-)