Tag Archives: nginx

Fix nginx ssi unsafe URI was detected error

If your FE project enabled SSI (Server Side Includes) plugin, you may get some errors or a lots:

[error] 1788#0: *149 unsafe URI “xxx” was detected while sending response to client

Normally, nginx support SSI syntax like

<!--# include virtual="include/foo.html"-->

But if your include path has some go up dir such as ../, then get our errors:

<!--# include virtual="../include/foo.html"-->

have a search NGINX source code, got the SSI related files

ngx_http_parse_unsafe_uri in src/http/ngx_http_parse.c

if (ngx_path_separator(ch) && len > 2) {

    /* detect "/../" and "/.." */

    if (p[0] == '.' && p[1] == '.'
            && (len == 3 || ngx_path_separator(p[2])))
    {
        goto unsafe;
    }
}

OK, for develop ENV test, we can fix this issues by comments these codes:

ngx_http_ssi_include in src/http/modules/ngx_http_ssi_filter_module.c

/*
if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
    return NGX_HTTP_SSI_ERROR;
}
*/

PHP_FPM of unix sockets vs TCP ports

When setup PHP-FPM for nginx pass_proxy, we may setup the php-fpm.conf include one of the config below:

listen = /var/run/php5-fpm.sock –> [nginx.conf] fastcgi_pass unix:/var/run/php5-fpm.sock;

listen = 127.0.0.1:9000 –> [nginx.conf] fastcgi_pass 127.0.0.1:9000;

Performance of unix sockets vs TCP ports

When you are using TCP, you are also using the whole network stack. Even if you are on the same machine, this implies that packets are encapsulated and decapsulated to use the network stack and the related protocols.

If you use unix domain sockets, you will not be forced to go through all the network protocols that are required otherwise. The sockets are identified solely by the inodes on your hard drive.

Make PHP-FPM Listen at “IPAddress:Port” Instead of “/var/run/php5-fpm.sock;”

Sockets are slightly faster as compared to TCP/IP connection. But they are less scalable by default.

If you start getting errors like below

connect() to unix:/var/run/php5-fpm.sock failed or **apr_socket_recv: Connection reset by peer (104)**

Then it means you need to either switch to TCP/IP or tweak with linux-system parameter so that your OS can handle large number of connections.

So, for high-load cases this is what it’s supposed to be: listen = 127.0.0.1:9000 and that fixed everything!

Reference Links

Remove PHP X-Powered-By & Nginx Version

For some website’s security reason, we need remove X-Powered-By and NGINX Version from response headers.

PHP:

To remove X-Powered-By completely, search line in php.ini.

expose_php = Off

or add the following directive to the Nginx configuration:

# Prevent version info leakage
fastcgi_hide_header X-Powered-By;

Nginx:

To remove Server Version from Header, server_tokens should be disabled in nginx.conf.

# http://wiki.nginx.org/HttpCoreModule#server_tokens
server_tokens off;

Change server string by recompiling Nginx source:

vim +49 src/http/ngx_http_header_filter_module.c

Find the lines:

static char ngx_http_server_string[] = "Server: nginx" CRLF;
static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;

see also: Customize Your Nginx Server Name After Compiling From Source

Rotate Nginx log files

Nginx is a great web server, however a default install will not rotate log files for you. there’s no size limit, it will keep getting bigger until your disk is full.

this is a problem especially on busy sites, as the access log can eat up disc space quite quickly.

In this tutorial, I will show you how to rotate ngnix log files automatically, my version is nginx/1.4.3. but any modern distribution should function in a similar way.

Manual rotating nginx log files via Cron

First we need to create the job bash script for cron that will do the log rotation.

sudo vi /usr/local/sbin/rotate_nginx_log.sh

Here are the contents of the script (this is based off the example from the Nginx wiki):

#!/bin/bash
# <https://gist.github.com/allex/10360845>

# Set variable
logs_path="/var/log/nginx/"
old_logs_path=${logs_path}/old
nginx_pid=`cat /var/run/nginx.pid`

time_stamp=`date -d "yesterday" +%Y-%m-%d`

mkdir -p ${old_logs_path}

# Main
for file in `ls $logs_path | grep log$ | grep -v '^20'`
do
    if [ ! -f ${old_logs_path}/${time_stamp}_$file ]
    then
        dst_file="${old_logs_path}/${time_stamp}_$file"
    else
        dst_file="${old_logs_path}/${time_stamp}_$file.$$"
    fi
    mv $logs_path/$file $dst_file
    gzip -f $dst_file  # do something with access.log.0
done

kill -USR1 $nginx_pid

Note:

First, we move the current log to a new file for archiving. A common scheme is to name the most recent log file with a suffix of current time stamp. e.g, $(date "+%Y-%m-%d").

The command that actually rotates the logs is kill -USR1 $(cat /var/run/nginx.pid). This does not kill the Nginx process, but instead sends it a SIGUSR1 signal causing it to re-open its logs.

THen execute sleep 1 to allow the process to complete the transfer. We can then zip the old files or do whatever post-rotation processes we would like.

Next please make sure that the script file is executable by running

chmod +x /usr/local/sbin/rotate_nginx_log.sh

In our final step we will create a crontab file to run the script we just created.

sudo crontab -e

In this file let’s create a cron job to run every day at 1am

Add the following lines to the file as follows:

00 01 * * * /usr/local/sbin/rotate_nginx_log.sh &> /dev/null

Also we can config suppressing cron jobs status email notifications. see Suppressing Cron Job Email Notifications


Log Rotation With Logrotate

The logrotate application is a simple program to rotate logs.

sudo vim /etc/logrotate.d/nginx

Put this content inside and modify the first line to match your Nginx log file

/var/log/nginx/*.log {
    daily
    missingok
    rotate 30
    dateformat .%Y-%m-%d
    compress
    delaycompress
    notifempty
    create 640 nginx adm
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] &amp;&amp; kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

Wait 24 hours until cron daily runs and check out if you see any .gz file inside your logs directory, if you see some gzipped files, your Nginx rotation is working fine :D


Related References:

Nginx – confusion with root & alias

Descritpions:

There is a very important difference between the root and the alias directives.
This difference exists in the way the path specified in the root or the alias is processed.

In case of the root directive, full path is appended to the root including the location part, whereas in case of the alias directive, only the portion of the path NOT including the location part is appended to the alias.

Understand:

Let’s say we have the config

location /static/ {
    root /var/www/app/static/;
    autoindex off;
}

In this case the final path that Nginx will derive will be:

/var/www/app/static/static

This is going to return 404 since there is no static/ within static/

This is because the location part is appended to the path specified in the root. Hence, with root, the correct way is:

location /static/ {
    root /var/www/app/;
    autoindex off;
}

On the other hand, with alias, the location part gets dropped. So for the config:

location /static/ {
    alias /var/www/app/static/;
    autoindex off;
}

the final path will correctly be formed as:

/var/www/app/static

See the documentation here: http://wiki.nginx.org/HttpCoreModule#alias

Nginx install and configuration skills

Compile and installation

Get latest source code from http://nginx.org/en/download.html

Some 3rd-party modules here

tar xzf nginx-1.4.3.tar.gz
cd nginx-1.4.3
./configure --prefix=/usr/local/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/tmp/nginx/body --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi --http-proxy-temp-path=/var/tmp/nginx/proxy --http-scgi-temp-path=/var/tmp/nginx/scgi --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid
make
make install

Some optional options for advanced features:

--with-http_gzip_static_module

Sending precompressed files with the .gz filename extension instead of regular files by gzip_static on.

--add-module=/path/to/echo-nginx-module

Compile with module for bringing the power of echo, sleep, time and more to nginx’s config file. see more

location /test {
  echo "uri = $uri";
  echo "args = $args";
  ...
}

Nginx compile issues

./configure: error: the HTTP rewrite module requires the PCRE library. You can either disable the module by using --without-http_rewrite_module option, or install the PCRE library into the system, or build the PCRE library statically from the source with nginx by using --with-pcre option.

[Solution]

yum install pcre-devel.x86_64

[Note]

If pcre already installed, but still cannot find the pcre references:

In this case, when compiling nginx against a custom compiled library, such as pcre, zlib and OpenSSL, you must use the options --with-cc-opt and --with-ld-opt

--with-cc-opt="-I/usr/local/pcre/include" --with-ld-opt="-L/usr/local/pcre/lib"

./configure: error: SSL modules require the OpenSSL library. You can either do not enable the modules, or install the OpenSSL library into the system, or build the OpenSSL library statically from the source
with nginx by using --with-openssl option.

[Solution]

yum install openssl.x86_64 openssl-devel.x86_64

Nginx configuration guidlines

First understand IfIsEvil

set customize header

Add customize header for upstream identify when development environment (add variable$hostname to http headers).

add_header X-Original-Via $hostname;

Fastcgi normalize SCRIPT_FILENAME

With fastcgi_split_path_info we can customize the $fastcgi_path_info and $fastcgi_script_name

fastcgi_split_path_info regex; Defines a regular expression that captures a value for the $fastcgi_path_info variable. The regular expression should have two captures: the first becomes a value of the $fastcgi_script_name variable, the second becomes a value of the $fastcgi_path_info variable. For example, with these settings

location ~ ^(.+\.php)(.*)$ {
   fastcgi_split_path_info       ^(.+\.php)(.*)$;
   fastcgi_param SCRIPT_FILENAME /path/to/php$fastcgi_script_name;
   fastcgi_param PATH_INFO       $fastcgi_path_info;
}

and the “/show.php/article/0001” request, the SCRIPT_FILENAME parameter will be equal to “/path/to/php/show.php”, and the PATH_INFO parameter will be equal to “/article/0001”.

Related Links: