Learn the basics of nginx
Maxime Thoonsen6 min read
The purpose of this article is to explain the basic things you’ll need when you start using nginx. I will assume that we are on a ubuntu Trusty(14.04) OS, I let the readers translate the command for their own OS.
Why Nginx?
Nginx is the “new” popular webserver that competes with Apache. So why use it?
Let’s take a quote from the wiki:
“Apache is like Microsoft Word, it has a million options but you only need six. Nginx does those six things, and it does five of them 50 times faster than Apache.”
— Chris Lea
Installation and useful commands
It’s very simple on ubuntu:
$ apt-get install nginx
If you need to run some PHP you need to also install FPM
$ apt-get install php7.0-fpm
Then you can manage it with the classic services commands like:
$ service nginx start
$ service php7.0-fpm restart
If your nginx webserver doesn’t start, you may have a problem in your conf. To have more info you can test your nginx conf with this command:
$ nginx -t
If everything is good you should see something like:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Some basic vhosts
I will now show you some vhosts and explain their use cases but first let’s have a look in the /etc/nginx/nginx.conf
file. By default there are already basic settings.
user www-data;
This line means that Nginx will run as the www-data user (as Apache usually does).
If you continue through the file you can see where the logs will be recorded by default, and then you have those lines
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
As you have guessed, thoses lines include all conf from conf.d
directory and all vhosts defined in sites-enabled
. Therefore all the vhosts files below need to be in the sites-enabled
directory and will be automatically loaded in nginx (after a reload or restart).
How to host a basic html website
If you only need to serve html pages. All you need for your vhosts is:
server {
listen 80 default_server;
root /var/www/;
}
It creates a default webserver that listens on the regular port 80 where basic http requests from browsers come. It also indicates that the root of your website is located at /var/www/
. To display your website you only have to create a /var/www/index.html
file and it will work.
Basic html website with a server_name
If you want to host many websites on the same machine. You need to use server_name directive so nginx can know which files it has to serve.
server {
listen 80;
server_name www.myamazingwebsite.com;
root /var/www/myamazingwebsite/;
}
server {
listen 80;
server_name www.notsobadwebsite.com;
root /var/www/notsobadwebsite;
}
You can also use it to protect yourself against people who create a fake domain name for your website. Like if your dns is like that:
myamazingwebsite.com. A 173.194.41.191
Someone can buy “thisisashittywebsite.com” domain name and create this DNS A record:
thisisashittywebsite.com. A 173.194.41.191
And people going on thisisashittywebsite.com will see your website unless you specified a server_name.
More informations about server_names
Basic PHP website
If you need to run some PHP pages, you will need to use the FastCGI-server.
server {
listen 80;
server_name nginx-php.demo;
root /var/www/php/;
location ~ \.php {
fastcgi_index index.php;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
We use location directive to tell nginx that urls matching *.php
need to use fastcgi. The fastcgi_pass tells nginx the socket on which FastCGI-server is listening.
Symfony website
This is an example conf for symfony websites in dev mode.
server {
listen 80;
server_name nginx-symfony.demo;
root /var/www/symfony/web;
#We add the logs
error_log /var/www/symfony/app/logs/nginx.error.log;
access_log /var/www/symfony/app/logs/nginx.access.log;
#We activate gzip
gzip on;
gzip_min_length 1000;
gzip_comp_level 9;
gzip_proxied any;
gzip_types application/javascript application/x-javascript application/json text/css;
#default index
index app_dev.php;
#So we don't have to see the app_dev.php or the app.php of symfony
try_files $uri @rewrite;
location @rewrite {
rewrite ^/?(.*)$ /app_dev.php/$1 last;
}
location ~ ^/(app|app_dev)\.php {
fastcgi_index $1.php;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Added to avoid 502 Bad Gateway errors
fastcgi_buffer_size 512k;
fastcgi_buffers 16 512k;
}
#HTTP 304 NOT CHANGED
location ~* \.(css|txt|xml|js|gif|jpe?g|png|ico)$ {
expires 1y;
log_not_found off;
}
}
Https website
If your website needs secure communications between your server and the client, you will need to enable ssl on your webserver. The vhost below redirects every http requests to the https equivalent. It also configures your server to use a custom certificate that you would have put in the conf.d
directory.
server {
listen 80;
root /var/www/https;
server_name nginx-https.demo;
#Permanent redirection
return 301 https://nginx-https.demo$request_uri;
}
server {
listen 443 ssl; #default https port
root /var/www/https/;
access_log /var/log/nginx/https.access.log;
error_log /var/log/nginx/https.error.log;
server_name nginx-https.demo;
ssl_certificate conf.d/myssl.pem;
ssl_certificate_key conf.d/myssl.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:!EXP:!LOW:!DSS:!3DES:!PSK:!aNULL:!eNULL:!RC4:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
}
Most of the time, for production you won’t generate your custom certificate but you’ll buy one. Have a look at the nginx’s documentation for more information.
Reverse proxy
There are many cases where you can need a reverse proxy. Nginx is known to make it very easy the use of reverse proxies. At Theodo, we use it in most of our AngularJs apps that call a node server through a reverse proxy.
Here is an example where everything is proxified to the 8080 port.
server {
listen 80;
server_name nginx-proxy.demo;
#Every url starting by '/' are proxified to 127.0.0.1:8080
location / {
#You can specify which dns server or /etc/hosts file to resolve the domain
resolver localhost;
#Set the header to keep the IP of the client
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080;
}
}
#You can put here a lot of services that don't listen to the port 80. Like a node server.
server {
listen 8080;
root /var/www/simple-proxy/;
access_log /var/log/nginx/proxy.access.log myCustomLog;
error_log /var/log/nginx/proxy.error.log;
}
The proxy_pass directive is the most important directive. It’s here that you specify the machine and the port where you want to proxify the request. Behind a proxy, you might want to modify the way your logs are recorded. I have here chosen a custom format for the access_log.
You can create your own log_format by creating a myCustomLog.conf file in the conf.d directory
log_format myCustomLog
'$remote_addr forwarded for $proxy_add_x_forwarded_for - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"'
'real_ip $http_x_real_ip';
Here is a quick list of nginx variables that you can use (The complete one is here).
- $remote_addr The remote host
- $remote_user The authenticated user (if any)
- $time_local The time of the access
- $request The first line of the request
- $status The status of the request
- $body_bytes_sent The size of the server’s response, in bytes
- $http_referer The referrer URL, taken from the request’s headers
- $http_user_agent The user agent, taken from the request’s headers
Sandbox
We have seen some examples of nginx vhosts that will cover most of your basic needs. I have also made a sandbox with Vagrant and Ansible to allow you to easily test different nginx configurations. There is even a little exercise in the README.
If you have some ideas for pertinent vhosts or exercises don’t hesitate to make a PR!