Nginx on Ubuntu

As quoted in our parent article, Nginx is our thing. In order to create similar working environments on both your local machine as your server(s), we've written 2 sibling articles as close aligned as possible.

If you use a virtual webserver service like DigitalOcean, you can opt for a pre-installed LEMP stack (Linux, Nginx, MySQL and PHP). In that case you can ignore some of the bullets in this article - it's still useful to fine-tune your setup, and more important, it's always a good idea to know how your operating system works.

Set up

Install Nginx

We are going to use apt to install the latest nginx package. It never hurts to run an apt update first.

sudo apt-get update  
sudo apt-get install nginx  

This shouldn't take too long...

In Ubuntu 14.04, by default, Nginx automatically starts when it is installed.

Configure

Once the install is completed, we're going to look at the main config file, located at /etc/nginx/nginx.conf. Slightly more compact then what you'd expect.
With our local nginx variation in mind, we're going to tweak the config files a little.

The first thing to remember is the nginx user/group: www-data.
It's a good practise to create all your server users part of the www-data group.

user www-data;  
worker_processes 8;  
pid /run/nginx.pid;

events {  
        worker_connections 768;
}

Next, it doesn't hurt to think for a second about your specific server use case (like client_max_body_size).

http {

    ##
    # Basic Settings
    ##
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

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

    client_max_body_size 25m;

Some loggin and gzip settings are next

    ##
    # Logging Settings
    ##
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##
    gzip on;
    gzip_disable "msie6";
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

Finally, add your "always included" conf.d and sites-enabled folders to the mix. It's where you're going to keep your topical configurations and soft links to your vhost files respectively.

    ##
    # Virtual Host Configs
    ##
    include conf.d/*.conf;
    include sites-enabled/*;
}

We remove the mail configuration by default, since we use Mandrill as external - more reliable - service.

Every time you change one of the configuration files, we need to reload the nginx master.

# sudo service nginx reload

If everything went according to plan, the next thing you'll see when you test your webserver http://youripaddress is:
"Welcome to nginx!"

Config Files

We have a couple of boilerplate configuration files for easy vhost addition.

FastCGI

If you're using PHP, You'll need to pass the scripts to the FastCGI server listening on the php-fpm socket.
This setup varies between your local and server environment. Obviously, ignore this file if you're never going to use PHP. You might want to store it in conf.d/php-fpm.conf otherwise, for default addition.

location ~ \.php$ {  
        fastcgi_intercept_errors on;
        include fastcgi.conf;
}

General

Some global configurations are stored in global/general.conf and included in most of our vhosts

# Global configuration http file.
# Designed to be included in any server {} block.
listen 80;

rewrite ^(.+)/+$ $1 permanent;

location = /favicon.ico {  
        log_not_found off;
        access_log off;
}

location = /robots.txt {  
        allow all;
        log_not_found off;
        access_log off;
}

# Deny all attempts to access hidden files such as .htaccess or .DS_Store
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {  
        deny all;
}

# Directives to send expires headers and turn off 404 error logging.
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|tar|mid|midi|wav|bmp|rtf)$ {  
        expires max;
        log_not_found off;
        access_log off;
}

Laravel

Laravel and Nginx play well together. This global conf is tailored to be included in all your Laravel projects.

# Laravel php rules.
# Designed to be included in any server {} block.
# Use alongside global/general.conf
index index.php;

try_files $uri $uri/ @rewrite;

location @rewrite {  
    rewrite ^/(.*)$ /index.php?_url=/$1;
}

error_page 404 /404.html;  
error_page 500 502 503 504 /50x.html;  
location = /50x.html {  
    root /usr/share/nginx/html;
}

location ~ \.php$ {  
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
#    fastcgi_pass unix:/var/run/php5-fpm.sock;
#    fastcgi_index index.php;
#    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#    include fastcgi_params;
}

Wordpress

Wordpress is one of the older kids who's actually more used to play with Apache, so we'll need to set up some specific rules to keep it's behaviour predicatble.

# WordPress single blog rules.
# Designed to be included in any server {} block.
# Use alongside global/general.conf

index index.php;

# Deny access to any files with a .php extension in the uploads directory
location ~* /(?:uploads|files)/.*\.php$ {  
        deny all;
}

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

# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;  

Important: You should have cgi.fix_pathinfo = 0; in your php.ini at all times.

Vhosts

Your projects

Your vhost file is basicly your website directive, stored in sites-available. The configuration varies wildly, depending on your flavour of choice. We've added some examples.

Create project

As you might have guessed, you should start with creating your project root, with sandboxed user credentials.

# useradd -G www-data project
# passwd project
# mkdir /var/www/html/project
# chown project:www-data /var/www/html/project

Add vhosts

To add a vhost site, it's a good practise to add a file to sites-available and link it in sites-enabled. We'll describe the file's content later on.

# nano /etc/nginx/sites-available/project
# ln -s /etc/nginx/sites-available/project /etc/nginx/sites-enabled/project

Static project

Static projects (eg. a Grunt-generated web app) are usually pre-compiled and nimble in use. This should be reflected in the config file too.

server {  
  server_name www.project.com;
  return 301 $scheme://project.com$request_uri;
}

server {  
    server_name project.com;
    root /var/www/html/project/dist;

    include /usr/local/etc/nginx/global/general.conf;
    index index.html;

    location / {
        try_files $uri $uri.html $uri/ /index.html;
    }
}

Ghost project

If you want to add a ghost blog, you just need to proxy your site to the running ghost server.
Your file contents will look like this (port 2368 is your default Ghost port):

server {  
    listen 80;
    server_name project.com;

    location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header HOST $http_host;
            proxy_set_header X-NginX-Proxy true;
            proxy_pass http://127.0.0.1:2368;
            proxy_redirect off;
    }
}

Wordpress project

Who hasn't hosted a Wordpress website before, right? The default vhost entry points to the project root (we use project/www) and include the previously explained configurations.

server {  
    server_name project.com;
    root /var/www/html/project/www;

    # Wordpress configuration
    include global/general.conf;
    include global/wordpress.conf;
}

Laravel project

To set up a Laravel project, the nginx configuration file needs a couple of extra lines. We use php-fpm in this example.

server {  
    server_name project.com;
    root /var/www/html/project/public;

    # Laravel configuration
    include global/general.conf;
    include global/laravel.conf;
}

And as always, reload your nginx files.

# service nginx restart


Server Notes

VSFTP setup

If you want a safe server environment, you shouldn't use ftp. If you really - really - want to, revert to VSFTP, a.k.a. Very Secure FTP.
Install it as following (Ubuntu):
sudo apt-get install vsftpd

We default to an easy to maintain logic for each website entry that requires ftp: we create a user that remains sandboxed to it's identically named html folder counterpart. You'll need to tweak following entries in the sftp config file for this:

sudo nano /etc/vsftpd.conf

Make sure to switch the Anonymous_enable from YES to NO:

anonymous_enable=NO

If you don't, vsftpd allows anonymous, unidentified users to access the server's files. This is useful if you are seeking to distribute information widely, but obviously is a serious security issue.

After that, uncomment the local_enable option, changing it to yes and, additionally, allow the user to write to the directory.

local_enable=YES  
write_enable=YES  

Finish up by uncommenting command to chroot_local_user. When this line is set to Yes, all the local users will be jailed within their chroot and will be denied access to any other part of the server.

chroot_local_user=YES

Save and Exit the file.

Now you need to create a user each time you start a new project - a good habit to keep your passwords, users and security habits sandboxed. As mentioned before, don't forget to add your users to the www-data group. It typically goes something like this:

# useradd -G www-data project
# passwd project
# mkdir /home/project
# mkdir /var/www/html/project
# chown project:project /home/project
# chown project:www-data /var/www/html/project
comments powered by Disqus