Tuesday, April 5, 2016

How to Install FREE SSL Certificate from Let's Encrypt using Nginx

Yes! Finally FREE SSL Certificate issued by a trusted issuer!

Too good to be true? That is exactly what I thought at first also. But I decided to try it and was pleasantly surprised. Yes, it works! Plus it is faster and easier than buying and installing a paid version.

What is Let's Encrypt?

Let's Encrypt is an open source project created specifically to disrupt or solve the SSL certificate issue. I have always wondered why we always have to pay for a freaking certificate (especially just for domain validation) while we do most of the work validating our own control / ownership of the domain?!?  Sure, $10 / year does not break the bank, but it is still a good for lunch money :-)

How does Let's Encrypt work?

Let's Encrypt comes with a command line script called 'letsencrypt-auto'. I believe it was scripted using Python.  You just simply execute that script with all the parameters to request, generate and install the certificates in your server.

When execute 'letsencrypt-auto' script, it makes a request to Let's Encrypt server which will attempt to verify your domain by making a request at 'each' domain name you request certificate for (this is how it verify you are in control of your domain). So you need to have a working web server capable of serving http / https such as Apache / Nginx.

Here is an example command:

./letsencrypt-auto certonly --webroot -w /usr/share/www -d domain.com -d www.domain.com

The above command will tell Let's Encrypt server to check for

http://domain.com/.well-known/acme-challenge/{some mambo jumbo long file name}

http://www.domain.com/.well-known/acme-challenge/{some mambo jumbo long file name}

The {some mambo jumbo long file name} will contain some secret data, which Let's Encrypt has placed there before requesting the remote check. If the secret information matches... then your request will be considered valid and it will generate your certificate and place them in the following directory:

cd /etc/letsencrypt/live/domain.com/

which will contain the following files:

cert.pem  chain.pem  fullchain.pem  privkey.pem


Generate Strong Diffie-Hellman 2048-bit Group

For extra security I also recommend for you to generate Strong Diffie-Hellman Group bit group

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


Use the SSL Certificate in Nginx

I use usually use two Nginx virtual host configuration files:  'default' and 'default-ssl'

default is usually for port 80 HTTP protocol
default-ssl is usually for port 443 HTTPS protocol


In this example, I will show you how to serve 100% SSL (HTTPS only) for your entire website which is recommended by Google.

Edit your 'default' configuration:

nano /etc/nginx/sites-available/default

Here is the entire content of my 'default' configuration file:

server {
listen   80 default; ## listen for ipv4; this line is default and implied
listen   [::]:80 default ipv6only=on; ## listen for ipv6

root /usr/share/www;

server_name www.domain.com domain.com;

return 301 https://$host$request_uri;
}

Edit your 'default-ssl' configuration:

nano /etc/nginx/sites-available/default-ssl

Here is the entire content of my 'default-ssl' configuration file:

# HTTPS server
#
server {
listen 443 default;
server_name www.domain.com domain.com;

root /usr/share/www;
index index.php index.html index.htm;

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

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;


{ ...  more configuration here ... }

}


Restart and Test

Restart Nginx using this command:

service nginx restart


Go to your favorite browser and you should see this:



How to Renew / Automatically Renew

To renew manually just re-execute the same command when you generate the SSL certificate the first time. Which will prompt you with a chose to regenerate or renew like this:


To renew just select #2 and select 'OK', then restart Nginx web server.

Enjoy FREE SSL from Let's Encrypt

I know I will, I hope this helps somebody.

A BIG Thank You! to Let's Encrypt organization :-)))




Tuesday, March 29, 2016

How to redirect IP address request to the proper domain name using Nginx

For SEO purposes, it is good practice to redirect permanently traffic directed to the IP address of a particular website to be re-written to the actual domain name.

This is very easy to do using Nginx web server. Simply add this server configuration block.

In this example I am using IP address 123.234.123.234 to be 301 redirected to domain name yourdomainname.com.

# -----------------------------------------------------

server {
listen 80;
server_name 123.234.123.234;
return 301 $scheme://www.yourdomainname.com$request_uri;
}

Add simple HTTP Basic Authentication using Nginx

Protecting your website from public using Nginx using Basic HTTP Authentication is easy.

This example uses Nginx + FPM and PHP5

This is useful when you just need to have simple protection for the following purposes:

1. During development.
2. Private website.
3. Temporary protection for certain directories.

Where to implement Basic HTTP Authentication in Nginx?


Inside your virtual host / default host configuration file.
In this example I am using Ubuntu and default configuration, so my default host configuration file is located at:

/etc/nginx/sites-available/default

Add the following lines inside the location ~ \.php$ { .... } block.

auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;

My entire location block looks like this:

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;

fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;

fastcgi_split_path_info ^(.+\.php)(/.+)$;
# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

# With php5-cgi alone:
fastcgi_pass 127.0.0.1:9000;

# With php5-fpm:
# fastcgi_pass unix:/var/run/php5-fpm.sock;

fastcgi_index index.php;
include fastcgi_params;
}



How to protect SSL (HTTPS) also with Basic HTTP Authentication in Nginx?

Just repeat the above steps while editing the HTTPS version of the configuration file.

In this example I edited:

/etc/nginx/sites-available/default-ssl

Create the .htpasswd (HTTP Password) file

DO NOT place this file inside your document root. I actually place mine in the Nginx configuration directory in:

/etc/nginx

I simply named the file:  .htpasswd

it is a . (dot) file because incase you accidentally place it inside your document root, typical web servers will not serve dot files.

Use online HTTP Password generators, just google 'http password generator'.

Here is the content of my .htpasswd file:

username:$apr1$YHsIoLBd$Ut5NoTL7bIIp9ysyLcczn.

the above line will allow username=username with password=password to be authenticated. 

Restart Nginx to apply your configuration

service nginx restart

Sample PHP5 FPM Pool configuration for high volume trafic

PHP5 FPM configuration for high throughput / trafic

I have a web project that required a lot of request per page load. I did not measure it exactly how many request, but it is probably around 50 - 100 requests. And I saw a few request timed-out especially when I cleared my browser cache or during a hard refresh.

So I tweaked my FPM pool configuration to the following setting to allow for more throughput:


[yourdotcom]

listen = /var/run/php5-fpm/yourdotcom.socket
listen.backlog = -1
listen.owner = www-data
listen.group = www-data
listen.mode=0660

; Unix user/group of processes
user = www-data
group = www-data

; Choose how the process manager will control the number of child processes.
pm = dynamic
pm.max_children = 80
pm.start_servers = 20
pm.min_spare_servers = 10
pm.max_spare_servers = 40
pm.max_requests = 1000

; Pass environment variables
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

; host-specific php ini settings here
; php_admin_value[open_basedir] = /var/www/yourdotcom/htdocs:/tmp

Monday, February 22, 2016

Easily rotate Nginx logs using rename, truncate, then restart

The scripts below is probably one of the simplest way to keep a few days worth of logs (up to you) and still keep all logs organized enough without loosing track.


What the scripts below do:

1. change directory to /log/nginx  (this is where I keep my Nginx logs - yours may be different)
2. move (rename) a log file ie: access.log to access_YYYYMMDD.log
3. create a new log file (using touch) with zero bytes.
4. change permission of new log file to 777 (allow everything).
5. restart nginx process so that it will use newly created log files.

-----------------------------------------------

cd /log/nginx

mv access.log access_`date +"%Y%m%d"`.log
touch /log/nginx/access.log
chmod 777 /log/nginx/access.log

mv error.log error_`date +"%Y%m%d"`.log
touch /log/nginx/error.log
chmod 777 /log/nginx/error.log

mv api-access.log api-access_`date +"%Y%m%d"`.log
touch /log/nginx/api-access.log
chmod 777 /log/nginx/api-access.log

mv api-error.log api-error_`date +"%Y%m%d"`.log
touch /log/nginx/api-error.log
chmod 777 /log/nginx/api-error.log

mv default-access.log default-access_`date +"%Y%m%d"`.log
touch /log/nginx/default-access.log
chmod 777 /log/nginx/default-access.log

mv default-error.log default-error_`date +"%Y%m%d"`.log
touch /log/nginx/default-error.log
chmod 777 /log/nginx/default-error.log

mv default-ssl-access.log default-ssl-access_`date +"%Y%m%d"`.log
touch /log/nginx/default-ssl-access.log
chmod 777 /log/nginx/default-ssl-access.log

mv default-ssl-error.log default-ssl-error_`date +"%Y%m%d"`.log
touch /log/nginx/default-ssl-error.log
chmod 777 /log/nginx/default-ssl-error.log

mv rockmongo-access.log rockmongo-access_`date +"%Y%m%d"`.log
touch /log/nginx/rockmongo-access.log
chmod 777 /log/nginx/rockmongo-access.log

mv rockmongo-error.log rockmongo-error_`date +"%Y%m%d"`.log
touch /log/nginx/rockmongo-error.log
chmod 777 /log/nginx/rockmongo-error.log

kill -USR1 $( cat /var/run/nginx.pid )

-----------------------------------------------

What to do with all those files created with YYYYMMDD?

Well you can then remove them using the following crontab lines at your liking:

here is a line from my crontab that removes every file in my /log/ directory recursive that is older than 10 days:

19 4 * * * find /log/ -type f -mtime +10 | xargs rm


Sunday, February 7, 2016

My most up to date PHP development stack

A few people have asked me about which development tools, libraries, and technologies I am using. I want to create this blog to help current and new PHP developers get up to speed and hopefully not spend as much time as I had trying out different tools (or worst wrong tools) :-)

Computer:
In 2015 I ditched my Mac Pro for a Macbook Pro and good thunderbolt dock that can drive my 4K monitor. I did this so that I can be mobile and most importantly so that I do not sit on my a** all day.
Yes, sorry I do not recommend Windows, for web development (PHP, Python, Ruby, etc... ) Macs are much better choice.

Text Editor:
Sublime Text 3

Server OS:
Ubuntu LTS versions, currently 14.04

Web Server:
Nginx + FPM

Database Server:
MongoDB + ElasticSearch
I have developed my own DB framework which utilizes Redis > MongoDB > ElasticSearch all together in harmony.

PHP Framework:
Laravel + Composer
I used to be a code igniter fan, however Laravel is king today.
(Node JS sometime)

Javascript:
jQuery + Angular

HTML:
Bootstrap 3.x


I waited too long to jumped to Laravel.
In 2015, I have been blessed with TONS of work, so much work that I have not had a chance to re-factor my base codes to Laravel.  I wish I would have switch since version 4.  Anyways... make sure you checkout Laravel, it is almost as good as the next 'daily bread' for PHP.

I hope this article help someone new or even PHP veterans to compare with tools they are using.




Sunday, February 8, 2015

Truncate and rotate linux server log files using copy, truncate and restart gracefully

If you are not using auto-rotate of log files for certain daemons in your linux server, you may be looking for a solution to auto-rotate your log files.

Rotating a log file is necessary so that your log file will not be too big.

When log files gets too big, it has bitten me in the a** before.  Server runs out of disk space
and server process fails. Yes it is an embarrassing situation for any server admin.  Save yourself the embarrassment and spent 5 minutes implementing this simple rotate script:


cp /var/log/nginx/error.log /data/log/tmp_nginx_log/nginx_error_`date +"%Y_%m_%d"`.log; truncate -s0 /var/log/nginx/error.log; kill -USR1 $( cat /var/run/nginx.pid )


The code above will do the following:

  1. copy the current log file from /var/log/nginx/error.log to /data/log/tmp_nginx_log/
    while copying, it will also rename the file by appending specific date to it.
  2. next, it will truncate the current log file to zero size.
  3. finally, it will send message to nginx web server to reload gracefully and it will start logging errors into the new zero sized log file.

So now that we moved the log file to another directory what do we do with it there?

Since we named all files with their appropriate dates, we can easily review individual log files when we need too. 

Another purpose for separating the log files into separate dates, is so that we can clean-up old log files we no longer want. For example if you want to only keep log files for 30 days, you can easily run the following command or schedule in your crontab.


find /data/log/tmp_nginx_log -type f -mtime +3 | xargs rm


The command above will remove any files older than 3 days from /data/log/tmp_nginx_log directory.

For more options you can do to clean up files, read my blog about how to Remove Files in Directory Recursively.