Let’s encrypt!

“The Let’s Encrypt project aims to make encrypted connections to World Wide Web servers ubiquitous. By getting rid of payment, web server configuration, validation emails, and dealing with expired certificates it is meant to significantly lower the complexity of setting up and maintaining TLS encryption.”Wikipedia

Let’s Encrypt is a service provided by the Internet Security Research Group (ISRG), a public benefit organization. Major sponsors are the Electronic Frontier Foundation (EFF), the Mozilla Foundation, Akamai, and Cisco Systems. Other partners include the certificate authority IdenTrust, the University of Michigan (U-M), the Stanford Law School, the Linux Foundation as well as Stephen Kent from Raytheon/BBN Technologies and Alex Polvi from CoreOS.

So, in summary, with Let’s Encrypt you will be able to request for a valid SSL certificate, free of charges, issued for a recognized CA and avoiding the mess of the mails, requests, forms typical of the webpages of the classic CA issuers.

The rest of the article shows the required steps needed for a complete setup of a Nginx server using Let’s encrypt issued certificates:

Install letsencrypt setup scripts:

cd /usr/local/sbin
sudo wget https://dl.eff.org/certbot-auto
sudo chmod a+x /usr/local/sbin/certbot-auto

Preparing the system for it:

sudo mkdir /var/www/letsencrypt
sudo chgrp www-data /var/www/letsencrypt

A special directory must be accesible for certificate issuer:

root /var/www/letsencrypt/;
location ~ /.well-known {
allow all;
}

Service restart. Let’s encrypt will be able to access to this domain and verify the athenticity of the request:

sudo service nginx restart

Note: At this point you need a valid A DNS entry pointing to the nginx server host. In my example, I will use the mydomain.com domain as an example.

Requesting for a valid certificate for my domain:

sudo certbot-auto certonly -a webroot --webroot-path=/var/www/letsencrypt -d mydomain.com

If everything is ok, you will get a valid certificate issued for your domain:

/etc/letsencrypt/live/mydomain.com/fullchain.pem

You will need a Diffie-Hellman PEM file for the crypthographic key exchange:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Setting the nginx virtual host with SSL as usual but using the Let’s encrypt issued certificate:

...
ssl on;
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
...

Check the new configuration and restarting the Nginx:

nginx -t
sudo service nginx restart

Renewing the issued certitificate:

cat >> EOF > /etc/cron.d/letsencrypt
30 2 * * 1 root /usr/local/sbin/certbot-auto renew >> /var/log/le-renew.log
35 2 * * 1 root /etc/init.d/nginx reload
EOF

Automated multihosting with Nginx for PHP with FastCGI

Nginx configuration for this:

  • if client request does not have x_forwarded_for, deny the request showing a 404
  • allow access site even if x_forwarded_for:
  • if “Host” header is a IP use /var/www/vhosts/ip as root dir
  • if “Host” header is a domain use /var/www/vhosts/$domain as root dir
  • if “Host” is sub0.sub1.oranything.domain still goes to /home/vhosts/$domain
  • backend for PHP fastcgi
  • if requested file doesnt exist throw 404 error
  • setting the default index page

Strongly based on http://kbeezie.com/view/nginx/

server {

server_name www.example.com default_server;
listen 0.0.0.0:80;

# Keep a root path in the server level, this will help automatically fill
# Information for stuff like FastCGI Parameters
root /var/www/vhosts/;

# You can set access and error logs at http, server and location level
access_log /var/log/nginx/server.access.log;
error_log /var/log/nginx/server.error.log debug;

# if client request does not have x_forwarded_for, deny the request,
if ($http_x_forwarded_for = "" ) { set $x 1; }
# .. except if host is www.public1.com|www.public2.com
if ($host ~* "(www\.public1\.com|www\.public2\.com)" ) { set $x 0; }
# .. or if uri is publicdir
if ($uri ~* "(publicdir)" ) { set $x 0; }
# .. evaluating $x
if ($x = 1) { return 404; }

# if Host is a IP vhost is "ip"
if ($host ~* "(\d+)\.(\d+)\.(\d+)\.(\d+)" ) { set $vhost "ip"; }

# if Host is a DN vhost is the vhost
if ($host ~* "(\w+\.)*(\w+)\.([a-z]+)" ) { set $vhost "$2.$3"; }

# If file doesnt exist: Error 404
if (!-e $document_root/$vhost/$uri) { return 403; }

# Setting the index page
set $i "/index.html";
if (-e $document_root/$vhost/index.php) { set $i "/index.php"; }
if (-e $document_root/$vhost/index.htm) { set $i "/index.htm"; }
if ($uri ~* "(.*)/") {
rewrite ^(.*)(/)$ $1$i redirect;
}
if (-d $document_root/$vhost/$uri) {
rewrite ^(.*)$ $1$i redirect;
}

# It will try for static file, folder, then falls back to index.php
# Assuming index.php is capable of parsing the URI automatically
location / {
try_files /$vhost$uri /$vhost/index.php ;
}

# Prevent ".." navigations: Error 403
location ~ \..*/.*\.php$ {
return 403;
}

# This block will catch static file requests, such as images, css, js
# The ?: prefix is a 'non-capturing' mark, meaning we do not require
# the pattern to be captured into $1 which should help improve performance
location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
# Some basic cache-control for static files to be sent to the browser
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}

# PHP location block and parameters
location ~ \.php {
if (!-e $document_root/$vhost/$uri) { return 404; }
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root/$vhost/$fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;

fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;

fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
#fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_ADDR $remote_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param HTTP_HOST $host;

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 8 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

# I use a socket for php, tends to be faster
# for TCP just use 127.0.0.1:port#
# fastcgi_pass unix:/opt/php-fpm.sock;
fastcgi_pass 127.0.0.1:9000;

# Not normally needed for wordpress since you are
# sending everything to index.php in try_files
# this tells it to use index.php when the url
# ends in a trailing slash such as domain.com/
fastcgi_index index.php;
}

# Most sites won't have configured favicon or robots.txt
# and since its always grabbed, turn it off in access log
# and turn off it's not-found error in the error log
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }

# Rather than just denying .ht* in the config, why not deny
# access to all .invisible files
location ~ /\. { deny all; access_log off; log_not_found off; }
}

HTML tables sorter from Canada

I’m very fascinated by one JavaScript library that I’ve found recently. The purpose of this library is very simple: Making  HTML tables sortable.

The performance of sorting a table using this JavaScript library is much better than other table sorting strategies (for example, AJAX+JSON queries to server side).
The quiz of this library is that it  uses the quicksort (makes O(nlogn) comparisons to sort n items) algorithm.

Links:

– Project HomePage: http://www.terrill.ca/sorting/
– JavaScript library: http://www.terrill.ca/sorting/TSorter_1.js
– The example: http://www.terrill.ca/sorting/table_sort_example.php

Proxying with Nginx

nginx logo

Today, something refer to Nginx and proxy rules. The tips showed bellow aren’t a advanced rules but should be valid for 80% of all cases that we should want to us.

server {
  listen   8008;
  server_name server.net;
  access_log  /var/log/nginx/server.net.access.log;

  location /reflector/mcast {
    proxy_pass        http://93.37.29.30:80;
    include /etc/nginx/include-enabled/proxy_settings.conf;
    # Other settings related to proxy: headers, timeouts ...
    rewrite  ^/reflector/mcast/8$  http://93.37.29.30:80/video.php?channel=8 redirect;
    rewrite  ^/reflector/mcast/12$  /video.php?channel=12  break;
  }
  ...
}

The /etc/nginx/include-enabled/proxy_settings.conf would be something like this:

proxy_set_header  X-Real-IP  $remote_addr;
proxy_set_header  X-Forwarded-For  $remote_addr;
proxy_read_timeout 300;

The first rewrite rule defines a 302 redirection behavior. The server respond to client a 302 response refer to http://93.37.29.30:80/video.php?channel=8. The second one, respond a 20X response. Petition will be rewrite to /video.php?… and it’ll be delegate to proxy_pass module. In this case, the server implement a reverse proxy behavior.
Observe next items:

  • All petitions like /videos/ are proxified to http://10.13.30.26:8004/videos/:
    location /videos/ {
      proxy_pass        http://10.13.30.26:8004;
      include /etc/nginx/include-enabled/proxy_settings.conf;
    }
  • All petitions like /media/video.mpeg are proxified to http://10.14.20.41:8004/videos/video.mpeg:
    location /media/ {
      proxy_pass        http://10.14.20.41:8004/;
      include /etc/nginx/include-enabled/proxy_settings.conf;
      rewrite  ^/media/(.*)$ /videos/$1  break;
    }
  • All petitions like /media/8 are proxified to http://10.14.20.42:8004/?video=8:
    location /media/ {
      proxy_pass        http://10.14.20.42:8004/;
      include /etc/nginx/include-enabled/proxy_settings.conf;
      rewrite  ^/media/(.*)$ /?video=$1  break;
    }

Finally, next rule uses $arg_ special var to refer the get parameters in the URI. In this case, this server expect URLs like “/play?mo=video.mpeg” and it’ll try to serve video.mpeg storaged on /var/www.

location /play {
  root /var/www/;
  rewrite ^/play /$arg_mo redirect;
}

Enjoy it!.