Nginx Library

A repository of Nginx-related articles

Nginx configuration for XenForo

Writing a configuration file for XenForo is pretty simple and very similar to the Wordpress configuration where requests are internally redirected to the index.php file. With this configuration XenForo’s friendly URLs work perfectly, as well as external access is cut off for some directories like libraries and internal_data.

server {
    listen   [::]:80;
    server_name  example.com www.example.com;
    root   /var/www/example.com;
    index  index.html index.htm index.php;
    access_log  /var/www/logs/example.com.access.log;  

    location / {
        try_files $uri $uri/ /index.php?$uri&$args;
    }

    location ~ /(internal_data|library) {
         internal;
    }

    location ~ \.php$ {
        fastcgi_pass   unix:/tmp/php.socket;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include fastcgi_params;
    }   
}

For a XenForo installation in a sub directory xenforo, the configuration should be like this:

server {
    listen   [::]:80;
    server_name  example.com www.example.com;
    root   /var/www/example.com;
    index  index.html index.htm index.php;
    access_log  /var/www/logs/example.com.access.log;  

    location /xenforo/ {
        try_files $uri $uri/ /xenforo/index.php?$uri&$args;
    }

    location ~ /xenforo/(internal_data|library) {
         internal;
    }

    location ~ \.php$ {
        fastcgi_pass   unix:/tmp/php.socket;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include fastcgi_params;
    }   
}

Nginx configuration for phpBB

I had previously written an article about converting phpBB’s default htaccess rules to Nginx. Here I’ll share a full-blown Nginx configuration file for serving a phpBB forum.

This configuration file :

  • Redirects www sub domain to the bare domain along with any parked domains.
  • Prevents external access to files and directories like config.php, avatar upload directory, etc.
  • Sets proper Expires header for images.
server {
    listen   [::]:80;
    server_name  www.domain.com parkeddomain.com *.parkeddomain.com;
    rewrite ^    http://domain.com$request_uri? permanent;
}

server {
    listen   [::]:80;
    server_name  domain.com;
    root   /var/www/domain.com;
    index  index.php index.html index.htm;
    access_log  /var/logs/domain.com.access.log;

    location ~ /(config\.php|common\.php|cache|files|images/avatars/upload|includes|store) {
        deny all;
        return 403;
    }

    location ~* \.(gif|jpe?g|png|css)$ {
        expires   30d;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass   unix:/tmp/php.socket;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Resolving “403 Forbidden” error

403 Forbidden errors are Nginx’s way of telling “You have requested for a resource but we cannot give it to you.” 403 Forbidden is technically not an error but a HTTP status code. 403 response headers are intentionally returned in many cases such as -

  • User is blocked from requesting that page/resource or the site as a whole.
  • User tries to access a directory but autoindex is set to off.
  • User tries to access a file that can be only accessed internally.

These are some among many cases where a 403 Forbidden response is intentionally returned. But here we will talk about the causes of 403 responses that are unintentional/not desired which generally occur as a result of misconfiguration on the server side.

Permissions are not set correctly

This is the most common cause of this error. By permissions, I do not only mean the permissions for the file that is being accessed. In order to serve a file, Nginx needs to have read permissions for the file as well as execute permissions for every hierarchial parent directory of the file to chdir to it. For example, to access the file located at -

/usr/share/myfiles/image.jpg

Nginx needs to have read permissions for the file as well as execute permissions for /, /usr, /usr/share and /usr/share/myfiles. If you use the standard 755 for directories and 644 for files (umask: 022), you should not run into this problem.

To check for ownership and permissions on a path, we can use the namei utility like this -

$ namei -l /var/www/vhosts/example.com

f: /var/www/vhosts/example.com
drwxr-xr-x root     root     /
drwxr-xr-x root     root     var
drwxr-xr-x www-data www-data www
drwxr-xr-x www-data www-data vhosts
drwxr-xr-x clara    clara    example.com

Directory index is not properly defined

Sometimes, the index directive does not contain the desired directory index. For example, for a standard setup with PHP, the index directive should be -

index index.html index.htm index.php;

According to this example, when a directory is acessed directly, Nginx will try to serve index.html, then index.htm and index.php after that. If none of them are found, Nginx will return a 403 header. If index.php were not defined in the root directive, Nginx would have returned 403 without checking for the existence of index.php.

Similarly, for a Python setup, index.py should be defined as a directory index.

These are the most common causes of undesired 403 responses. Feel free to leave a comment if you are still getting 403s.

Using CloudFlare for country blocking

CloudFlare is an innovative service, providing webmasters with a CDN (Content Delivery Network) and many other things. Among these other things, it provides an IP geolocation service using which we can use to redirect/block visitors from specific countries.

We need to first enable ‘IP Geolocation’ in the CloudFlare settings for this to work -

IP geolocation

We also need to make sure that the A record for the domain/sub domain is being proxied though the CloudFlare proxy. So, enable CloudFlare for the relevant A record from the DNS settings if it hasn’t been set accordingly.

If everything is done properly, the HTTP_CF_IPCOUNTRY environment variable should contain the country code for the visitor. To test it, we can write a small script in Perl.

1
2
#!/usr/bin/perl
print "Content-type: text/html\n\n$ENV{'HTTP_CF_IPCOUNTRY'}";

Run the script and it should show you your country code. A list of country codes can be found here.

Now, we need to take care of the Nginx configuration. We need to map the environment variable to a variable of our own, so that the value of our variable changes depending on whether we want to allow visitors from the country or not.

We need to put the following code inside the http block but outside the server block for your website. It can be put in /etc/nginx/nginx.conf inside the HTTP block or in your vhosts file, outside of the server block.

map $http_cf_ipcountry $allow {
        default yes;
        CN no;
        MX no;
        NO no;
}

This sets $allow to yes or no, depending on the country of the visitor. Here, we are setting the variable to no if the visitor is from China, Mexico, or Norway. We can also set the default to no, and allow countries one by one if we need to allow only a few countries and block all others. Now that the variable is set, we need to instruct Nginx to serve a 403 page to the visitors from the blocked countries. Add this anywhere inside the server block :

if ($allow = no) {
    return 403;
}

This will make Nginx return a 403 Forbidden HTTP status code. A custom 403 error page can also be defined to make the error page more helpful.

If you are not using CloudFlare, you can still block visitors by country using the GeoIP module.

Nginx 1.0.11 has been released

Nginx 1.0.11 has been released.

Download it : http://nginx.org/en/download.html

The changes include :

  • Change: now double quotes are encoded in an “echo” SSI-command output. Thanks to Zaur Abasmirzoev.

  • Feature: the “image_filter_sharpen” directive.

  • Bugfix: a segmentation fault might occur in a worker process if SNI was used; the bug had appeared in 1.0.9.

  • Bugfix: SIGWINCH signal did not work after first binary upgrade; the bug had appeared in 1.0.9.

  • Bugfix: the “If-Modified-Since”, “If-Range”, etc. client request header lines might be passed to backend while caching; or not passed without caching if caching was enabled in another part of the configuration.

  • Bugfix: in the “scgi_param” directive, if complex parameters were used.

  • Bugfix: “add_header” and “expires” directives did not work if a request was proxied and response status code was 206.

  • Bugfix: in the “expires @time” directive.

  • Bugfix: in the ngx_http_flv_module. Thanks to Piotr Sikora.

  • Bugfix: in the ngx_http_mp4_module.

  • Bugfix: nginx could not be built on FreeBSD 10.

  • Bugfix: nginx could not be built on AIX.

Nginx 1.0.10 has been released

Nginx 1.0.10 has been released.

Download it : http://nginx.org/en/download.html

The changes include :

  • Bugfix: a segmentation fault might occur in a worker process if resolver got a big DNS response. Thanks to Ben Hawkes.

  • Bugfix: in cache key calculation if internal MD5 implementation was used; the bug had appeared in 1.0.4.

  • Bugfix: the module ngx_http_mp4_module sent incorrect “Content-Length” response header line if the “start” argument was used. Thanks to Piotr Sikora.

Nginx 1.0.9 has been released

Nginx 1.0.9 has been released.

Download it : http://nginx.org/en/download.html

The changes include :

  • Change: now the 0x7F-0x1F characters are escaped as \xXX in an access_log.

  • Change: now SIGWINCH signal works only in daemon mode.

  • Feature: “proxy/fastcgi/scgi/uwsgi_ignore_headers” directives support the following additional values: X-Accel-Limit-Rate, X-Accel-Buffering, X-Accel-Charset.

  • Feature: decrease of memory consumption if SSL is used.

  • Feature: accept filters are now supported on NetBSD.

  • Feature: the “uwsgi_buffering” and “scgi_buffering” directives. Thanks to Peter Smit.

  • Bugfix: a segmentation fault occurred on start or while reconfiguration if the “ssl” directive was used at http level and there was no “ssl_certificate” defined.

  • Bugfix: some UTF-8 characters were processed incorrectly. Thanks to Alexey Kuts.

  • Bugfix: the ngx_http_rewrite_module directives specified at “server” level were executed twice if no matching locations were defined.

  • Bugfix: a socket leak might occurred if “aio sendfile” was used.

  • Bugfix: connections with fast clients might be closed after send_timeout if file AIO was used.

  • Bugfix: in the ngx_http_autoindex_module.

  • Bugfix: the module ngx_http_mp4_module did not support seeking on 32-bit platforms.

  • Bugfix: non-cacheable responses might be cached if “proxy_cache_bypass” directive was used. Thanks to John Ferlito.

  • Bugfix: cached responses with an empty body were returned incorrectly; the bug had appeared in 0.8.31.

  • Bugfix: 201 responses of the ngx_http_dav_module were incorrect; the bug had appeared in 0.8.32.

  • Bugfix: in the “return” directive.

  • Bugfix: the “ssl_verify_client”, “ssl_verify_depth”, and “ssl_prefer_server_ciphers” directives might work incorrectly if SNI was used.

Nginx 1.0.7 has been released

Nginx 1.0.7 has been released.

Download it : http://nginx.org/en/download.html

The changes include :

  • Change: now if total size of all ranges is greater than source response size, then nginx disables ranges and returns just the source response.

  • Feature: the “max_ranges” directive.

  • Feature: the module ngx_http_mp4_module.

  • Feature: the “worker_aio_requests” directive.

  • Bugfix: if nginx was built –with-file-aio it could not be run on Linux kernel which did not support AIO.

  • Bugfix: in Linux AIO error processing. Thanks to Hagai Avrahami.

  • Bugfix: in Linux AIO combined with open_file_cache.

  • Bugfix: open_file_cache did not update file info on retest if file was not atomically changed.

  • Bugfix: reduced memory consumption for long-lived requests.

  • Bugfix: in the “proxy/fastcgi/scgi/uwsgi_ignore_client_abort” directives.

  • Bugfix: nginx could not be built on MacOSX 10.7.

  • Bugfix: in the “proxy/fastcgi/scgi/uwsgi_ignore_client_abort” directives.

  • Bugfix: request body might be processed incorrectly if client used pipelining.

  • Bugfix: in the “request_body_in_single_buf” directive.

  • Bugfix: in “proxy_set_body” and “proxy_pass_request_body” directives if SSL connection to backend was used.

  • Bugfix: nginx hogged CPU if all servers in an upstream were marked as “down”.

  • Bugfix: a segmentation fault might occur during reconfiguration if ssl_session_cache was defined but not used in previous configuration.

  • Bugfix: a segmentation fault might occur in a worker process if many backup servers were used in an upstream.

Nginx 1.0.6 has been released

Nginx 1.0.6 has been released.

Download it : http://nginx.org/en/download.html

The changes include :

  • Feature: cache loader run time decrease.

  • Feature: loading time decrease of configuration with large number of HTTPS sites.

  • Feature: now nginx supports ECDHE key exchange ciphers. Thanks to Adrian Kotelba.

  • Feature: the “lingering_close” directive.

  • Feature: now shared zones and caches use POSIX semaphores on Solaris. Thanks to Den Ivanov.

  • Bugfix: nginx could not be built on Linux 3.0.

  • Bugfix: a segmentation fault might occur in a worker process if “fastcgi/scgi/uwsgi_param” directives were used with values starting with “HTTP_”; the bug had appeared in 0.8.40.

  • Bugfix: in closing connection for pipelined requests.

  • Bugfix: nginx did not disable gzipping if client sent “gzip;q=0” in “Accept-Encoding” request header line.

  • Bugfix: in timeout in unbuffered proxied mode.

  • Bugfix: memory leaks when a “proxy_pass” directive contains variables and proxies to an HTTPS backend.

  • Bugfix: in parameter validaiton of a “proxy_pass” directive with variables. Thanks to Lanshun Zhou.

  • Bugfix: SSL did not work on QNX.

  • Bugfix: SSL modules could not be built by gcc 4.6 without –with-debug option.