This page looks best with JavaScript enabled

Nginx - Pt. 1

 ·  ☕ 5 min read

What is Nginx

from nginx.org

nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev.

Nginx is built to be very fast with low memory and high concurrency.

While Apache uses a process model to handle the requests, nginx uses a event-driven model. Nginx delegates to his workers, in asyncronous mode, the management of the requests, so it can handle thousands of request in a non blocking mode.

Here a nice lecture on the event-driven model (https://vanseodesign.com/web-design/nginx-web-server/)

In Nginx there is only one master process thats controls many worker processes which actually do the job asynchronous. In the minimal configuration there is 1 master 1 worker wich can hadle many consurantly requests.

Configuration

The main part of the configuration resides in directory /etc/nginx. The starting point is the file /etc/nginx/nginx.conf

Lets' explore this main file, I’ll put some comments on the variuous declaration

# user running the ngxin process
user www-data;
# how many workers (N|auto)
worker_processes auto;
# where to store pid process
pid /run/nginx.pid;
# read other configuration modules from this position
include /etc/nginx/modules-enabled/*.conf;

# event context
events {
    # how many reqequestes can hadle a single worker
    worker_connections 768;
}

# http context
http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    # list of mime types used to return data
    include /etc/nginx/mime.types;
    # if no mime type is found or defined use this on
    default_type application/octet-stream;

    ssl_prefer_server_ciphers on;

    # where to put logs and what type of logs
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # use some kind of compression
    gzip on;

    # include all the configuration found in these locations
    include /etc/nginx/conf.d/*.conf;
    # virtual host location, this contains symbolic links to
    # /etc/nginx/sites-available/
    include /etc/nginx/sites-enabled/*;
}

test you configuration

-t
test the configuration file: nginx checks the configuration for correct syntax, and then tries to open files referred in the configuration.
-T
same as -t, but additionally dump configuration files to standard output (1.9.2).
nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

nginx -T | grep -v '^$\|^\s*\#'
# dumps all the configuration

very simple no?

First simple VHost

what is a vhost ( virtual host)

A physical server can hold many web sites. For example www.example.com blog.example.com or simply example.com. Every host needs a different configuration file on the server, so the name virtual host.

On the a Debian OS your configuration file can be put on sites-available directory and then create a symbolic link in site-enables in other systems you can put your vhosts configurations files in conf.d

Create a example configuration file to create a new vhost wich will respond to the requests made to example.com

server {
    # listen on port 80, of all the IPs of our server but you can change the default port for HTTP
    listen 80;
    # listen 127.0.0.1:80 ; # only localhost
    # listen 10.0.0.1:80 ; # only lan ip

    # define the server name, the request which contains
    # Host: example.com will be redirected to the vhost
    # here defined
    server_name example.com;

    root /var/www/html/default;
}

Manual says the server is a directive in the http context defined in nginx.conf as seen before

Syntax: server { ... }
Default: 
Context: http
ln -sf /etc/nginx/sites-available/example /etc/nginx/site-enabled/example

#create a test file
mkdir -p /var/www/example/
echo "server example" > /var/www/example/index.html

# restart
nginx -t
systemctl start nginx
systemctl status nginx

If you don’t pass the domain name as header, you won’t get the expected result

# this will return the index.html of the default vhost
# configured on the server
curl localhost

you need to pass in the header the name of the host required (HTTP 1.1),
or

curl --header "Host: example.com" localhost

# * Connected to localhost (127.0.0.1) port 80 (#0)
# > GET / HTTP/1.1
# > Host: example.com
# > User-Agent: curl/7.64.0
# > Accept: */*

Add some logs and custom error pages

suppose that we make a GET request to a page that does not exists. -v will show the headers of the request and response.

curl -v --header "Host: example.com" localhost/bla.html

> GET /bla.html HTTP/1.1
> Host: example.com
> User-Agent: curl/7.64.0
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Server: nginx/1.14.2
< Date: Sat, 12 Sep 2020 15:24:21 GMT
< Content-Type: text/html
< Content-Length: 169
< Connection: keep-alive
<
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.14.2</center>
</body>
</html>

server {
    # listen on port 80, of all the IPs of our server but you can change the default port for HTTP
    listen 80;
    # listen 127.0.0.1:80 ; # only localhost
    # listen 10.0.0.1:80 ; # only lan ip

    # define a test server name
    server_name example.com;

    root /var/www/html/default;

    error_page 404 /404.html

}

so when the server return 404 code the page 404.html will be shown

create and restart the service

echo "ERROR 404 - page not found"  > /var/www/default/404.html
curl  --header "Host: example.com" localhost/bla.html
# ERROR 404 - page not found

to keep some error_logs on the system add the following lines error_log documentation

error_log /var/log/nginx/example_error.log info;
Syntax: error_log file [level];
Default: error_log logs/error.log error;
Context: main, http, mail, stream, server, location

The second parameter determines the level of logging, and can be one of the following: debug, info, notice, warn, error, crit, alert, or emerg. Log levels above are listed in the order of increasing severity. Setting a certain log level will cause all messages of the specified and more severe log levels to be logged. For example, the default level error will cause error, crit, alert, and emerg messages to be logged. If this parameter is omitted then error is used.

and add also access_log to track connections access_log documentation

access_log /var/log/nginx/example_access.log combined;
Syntax:  access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
Default: access_log logs/access.log combined;
Context: http, server, location, if in location, limit_except

where combined id predefined, but you can change it.

log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

Complete Example

server {
	listen 80;
	server_name example.com;
	root /var/www/default/;
	error_page 404 /404.html;

	error_log /var/log/nginx/example_error.log error;
	access_log /var/log/nginx/example_access.log combined;
}
curl  --header "Host: example.com" localhost/dfg

logs

==> example_error.log <==
2020/09/12 17:50:52 [error] 6104#6104: *2 open() "/var/www/default/dfg" failed (2: No such file or directory), client: 127.0.0.1, server: example.com, request: "GET /dfg HTTP/1.1", host: "example.com"

==> example_access.log <==
127.0.0.1 - - [12/Sep/2020:17:50:52 +0200] "GET /dfg HTTP/1.1" 404 15 "-" "curl/7.64.0"