Nginx Learning Note

Nginx Learning Note

Nginx Learning Note

Nginx VS Apache

  • Apache: prefork: each process handle one request at a time
  • Nginx: asynchronous design: dynamic content is handled by another process separately
    • Faster static resources
    • High concurrency
    • thousands of requests per process
    • Load balancer
    • Mail server

⭐ Nginx interprets incoming requests as URI locations, Apache prefers to interpret requests as filesystem locations.

Nginx Features:

  1. High performance
  2. High Concurrency
  3. Low Resource Usage

Installation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ubuntu
apt-get update
apt-get install nginx
ps aux | grep nginx
ifconfig #we can see the link to nginx server after installing/autorun it
#centos

# Remove host history
ssh-keygen -R 111.11.11.11

yum install epel-release
yum install nginx
# not auto-run
systemctl start nginx.service
ps aux | grep nginx

Another way to install

1
2
3
4
5
6
7
8
9
10
11
apt-get update
wget https://nginx.org/download/nginx-1.21.4.tar.gz
ls -l
> nginx-1.21.4.tar.gz
tar -zxvf nginx-1.21.4.tar.gz
cd ./nginx-1.21.4
apt-get build-essential
./configure # install prerequsites
> ...
apt-get install libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev
./configure

./configure

Then, we can configure our Nginx server

https://nginx.org/en/docs/configure.html

1
2
3
4
5
6
7
8
./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre --pid-path=/var/run/nginx.pid --with-http_ssl_module
# To compile
make
make install
ls -l /etc/nginx/
nginx -V # show version and configuration we installed
> nginx version: nginx/1.xx.xx
ps aux | grep nginx

Two types of modules:

  1. Nginx 3rd party modules
  2. Bundle modules —with

https://nginx.org/en/docs/ Modules reference

Systemd: Add Service/ Command

1
2
nginx -h
nginx -s stop

https://www.nginx.com/resources/wiki/start/topics/examples/systemd/

Save this file as /lib/systemd/system/nginx.service

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]Type=forking
PIDFile=/var/run/nginx.pid # changed
ExecStartPre=/usr/bin/nginx -t # changed
ExecStart=/usr/bin/nginx
ExecReload=/usr/bin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]WantedBy=multi-user.target

Use systemd

1
2
3
4
systemctl start nginx
systemctl status nginx
systemctl stop nginx
systemctl enable nginx # allows auto-run when machine reboot!

Nginx Windows Limits

  • Poor performance
  • Single worker process
  • Unsupported modules

Configuration ⚙️

nginx.conf

Directive: server_name mydomain.com

Context: essentially the scope: http {...}

The conf file itself is included in a global context

The important context:

  • http
  • server
  • location

Create a virtual host

a virtual host is a server context

port : 80 for http, 443 for https

1
2
ls -l /etc/nginx/
> nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
# nginx.conf
events {}

http {
server{
listen 80;
server_name 167.99.xx.xx;

# root directive
# if http url requests mach with a filename on the directory
root /sites/demo;
}
}
1
2
3
nginx -t # syntax check
systemctl reload nginx # never stop | no down time
systemctl restart nginx # if error happens, do not auto start

Right now nginx is not sending the correct Content-Type as text/plain not stylesheets

To change this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# nginx.conf
events {}

http {

types {
text/html html;
text/css css;
}

server{
listen 80;
server_name 167.99.xx.xx;

# root directive
# if http url requests mach with a filename on the directory
root /sites/demo;
}
}

/etc/nginx/mime.types has already set all common types we need, so we only need:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# nginx.conf
events {}

http {

include mime.types; # same directory at /etc/nginx as a global value

server{
listen 80;
server_name 167.99.xx.xx;

# root directive
# if http url requests mach with a filename on the directory
root /sites/demo;
}
}

types: This context is again used for mapping. This context is used to map MIME types to the file extensions that should be associated with them. This is usually provided with Nginx through a file that is sourced into the main nginx.conf config file.

https://www.digitalocean.com/community/tutorials/understanding-the-nginx-configuration-file-structure-and-configuration-contexts

Match and intercept an incoming request URI and override the server context’s configuration inside the location context

location

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# nginx.conf
events {}

http {

include mime.types;
server{
listen 80;
server_name 167.99.xx.xx;

root /sites/demo;

#prefix match: anything starting from /greet
location /greet {
return 200 'Hello from /greet location';
}

#exact match
location = /greet {
return 200 'Hello from /greet location - EXACT MATCH';
}

#REGEX match - case sensitive
location ~ /greet[0 -9] {
return 200 'Hello from /greet location - REGEX MATCH';
}

#REGEX match - case insensitive
location ~* /greet[0 -9] {
return 200 'Hello from /greet location - REGEX MATCH INSENSITIVE';
}
}
}

REGEX match has higher priority than the prefix match

This overwrites the priority for the prefix match

1
2
3
4
#preferential prefix match
location ^~ /greet {
return 200 'Hello from /greet location';
}

Priority order

  1. Exact Match
  2. Preferential Prefix Match
  3. REGEX Match
  4. Prefix Match

Variables

http://nginx.org/en/docs/varindex.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# nginx.conf
events {}

http {

include mime.types;

server{
listen 80;
server_name 167.99.xx.xx;

root /sites/demo;

location /inspect {
return 200 "$host\n$uri\n$args";
}
}
}

Then when we go to the web 167.99.xx.xx/inspect?name=ray

we will have

1
2
3
167.88.xx.xx
/inspect
name=ray

We can output the exact arg to query

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# nginx.conf
events {}

http {

include mime.types;

server{
listen 80;
server_name 167.99.xx.xx;

root /sites/demo;

# Check static API key
if ( $arg_apikey != 1234 ) {
return 401 "incorrect api key"
}

set $weekend 'No';
if ( $date_local ~ 'Saturday|Sunday' ) {
set $weekend 'Yes';
}

location /inspect {
return 200 "Name: $arg_name";
}
}
}

Rewrite/ Redirect 🍥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# nginx.conf
events {}

http {

include mime.types;

server{
listen 80;
server_name 167.99.xx.xx;

root /sites/demo;

location /logo {
return 307 /thumb.png;
}
}
}

/logo is redirect to /thumb.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# nginx.conf
events {}

http {

include mime.types;

server{
listen 80;
server_name 167.99.xx.xx;

root /sites/demo;

#url is re-evaluated internally in Nginx
#rewrite ^/user/(\w+) /greet/$1 last; # ensures it is the last rewrite
rewrite ^/user/(\w+) /greet/$1;
rewrite ^/greet/john /thumb.png;

location /greet {
return 200 "Hello user rewrite";
}

location = /greet/john {
return 200 "Hello John";
}
}
}

try_files 📁

check if current URL exsits, if not try if /sites/demo/thumb.pngexitst, show it, if not try next one

Only last one would be seen as internal rewrite; meaning others refer to files URI, last one refers to address URL;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# nginx.conf
events {}

http {

include mime.types;

server{
listen 80;
server_name 167.99.xx.xx;

root /sites/demo;

# all relative to root
try_files $uri /thumb.png /greet /friendly_404;

location /friendly_404 {
return 404 "not found"
}

location /greet {
return 200 "Hello user rewrite";
}

}
}

Named location 📛

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# nginx.conf
events {}

http {

include mime.types;

server{
listen 80;
server_name 167.99.xx.xx;

root /sites/demo;

# all relative to root
try_files $uri /thumb.png /greet @friendly_404;

location @friendly_404 {
return 404 "not found"
}

location /greet {
return 200 "Hello user rewrite";
}

}
}

Logging 💬

We have set the logging location when we are configuring Nginx

1
2
ls -l /var/log/nginx/

Create log for a certain location

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# nginx.conf
events {}

http {

include mime.types;

server{
listen 80;
server_name 167.99.xx.xx;

root /sites/demo;

location /greet {
# this shut down the logging for this location
#access_log off

access_log /var/log/nginx/secure.access.log
return 200 "Hello user rewrite";
}

}
}

Inheritance ⭐

  1. Array directive: inherit straight down recursively in the scope (multiple allows)
  2. Standard directive: inherit straight down recursively in the scope
  3. Action directive: just there ~ perform some action

http → server → location

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
events {}

######################
# (1) Array Directive
######################
# Can be specified multiple times without overriding a previous setting
# Gets inherited by all child contexts
# Child context can override inheritance by re-declaring directive
access_log /var/log/nginx/access.log;
access_log /var/log/nginx/custom.log.gz custom_format;

http {

# Include statement - non directive
include mime.types;

server {
listen 80;
server_name site1.com;

# Inherits access_log from parent context (1)
}

server {
listen 80;
server_name site2.com;

#########################
# (2) Standard Directive
#########################
# Can only be declared once. A second declaration overrides the first
# Gets inherited by all child contexts
# Child context can override inheritance by re-declaring directive
root /sites/site2;

# Completely overrides inheritance from (1)
access_log off;

location /images {

# Uses root directive inherited from (2)
try_files $uri /stock.png;
}

location /secret {
#######################
# (3) Action Directive
#######################
# Invokes an action such as a rewrite or redirect
# Inheritance does not apply as the request is either stopped (redirect/response) or re-evaluated (rewrite)
return 403 "You do not have permission to view this.";
}
}
}

Worker process

nginx worker is asynchronous, it will handle as much requests as possible as long as hardware is capable of.

number of process ←→ number of cores

1
2
3
4
5
6
7
systemctl status nginx
nproc
> 1
lscpu
> ... cpu info
ulimit -n
> 1024 ...number of files reading at once
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
user www-data;

worker_processes auto; #important!

events {
worker_connections 1024;
}

http {

include mime.types;

server {

listen 80;
server_name 167.99.93.26;

root /sites/demo;

index index.php index.html;

location / {
try_files $uri $uri/ =404;
}

location ~\.php$ {
# Pass php requests to the php-fpm service (fastcgi)
include fastcgi.conf;
fastcgi_pass unix:/run/php/php7.1-fpm.sock;
}

}
}

max connections = worker_processes * worker_connections

1
ls -l /var/run/nginx.pid
1
2
# change pid directive
pid /var/run/new_nginx.pid;

Buffers

  • Nginx worker recieves request from a TCP port 80
  • Nginx worker writes the data to memory RAM (Buffering)
    • If overflow writes into Disk
  • Nginx worker reads data from disk to memory (Buffering)
    • sends to client from memory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
user www-data;

worker_processes auto;

events {
worker_connections 1024;
}

http {

include mime.types;

# Buffer size for POST submissions
client_body_buffer_size 10K;
client_max_body_size 8m;

# Buffer size for Headers
client_header_buffer_size 1k;

# Max time to receive client headers/body
client_body_timeout 12;
client_header_timeout 12;

# Max time to keep a connection open for
keepalive_timeout 15;

# Max time for the client accept/receive a response
send_timeout 10;

# Skip buffering for static files | could be very helpful to send static files
sendfile on;

# Optimise sendfile packets | could be very helpful to send static files
tcp_nopush on;

server {

listen 80;
server_name 167.99.93.26;

root /sites/demo;

index index.php index.html;

location / {
try_files $uri $uri/ =404;
}

location ~\.php$ {
# Pass php requests to the php-fpm service (fastcgi)
include fastcgi.conf;
fastcgi_pass unix:/run/php/php7.1-fpm.sock;
}

}
}

http://nginx.org/en/docs/syntax.html

Adding new modules 🆕

New modules require to build Nginx from the source

1
2
3
4
5
6
nginx -V
> ./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre --pid-path=/var/run/nginx.pid --with-http_ssl_module

./configure --help
> ...all help config
./configure -- help | grep dynamic
1
2
./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre --pid-path=/var/run/nginx.pid --with-http_ssl_module --with-http_image_filter_module=dynamic

we need to append --modules-path=/etc/nginx/modules

to make dynamic modules to be loaded to the corresponding module

1
2
3
4
5
6
apt-get install libgd-dev
./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre --pid-path=/var/run/nginx.pid --with-http_ssl_module --with-http_image_filter_module=dynamic
make
make install
nginx -V
systemctl reload nginx

http://nginx.org/en/docs/http/ngx_http_image_filter_module.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
user www-data;

worker_processes auto;

load_module modules/ngx_http_image_filter_module.so;

events {
worker_connections 1024;
}

http {

include mime.types;

# Buffer size for POST submissions
client_body_buffer_size 10K;
client_max_body_size 8m;

# Buffer size for Headers
client_header_buffer_size 1k;

# Max time to receive client headers/body
client_body_timeout 12;
client_header_timeout 12;

# Max time to keep a connection open for
keepalive_timeout 15;

# Max time for the client accept/receive a response
send_timeout 10;

# Skip buffering for static files
sendfile on;

# Optimise sendfile packets
tcp_nopush on;

server {

listen 80;
server_name 167.99.93.26;

root /sites/demo;

index index.php index.html;

location / {
try_files $uri $uri/ =404;
}

location ~\.php$ {
# Pass php requests to the php-fpm service (fastcgi)
include fastcgi.conf;
fastcgi_pass unix:/run/php/php7.1-fpm.sock;
}

location = /thumb.png {
image_filter rotate 180;
}

}
}

Performance

Headers & Expires

Defines the duration of how long a static file a browser should cache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
user www-data;

worker_processes auto;

events {
worker_connections 1024;
}

http {

include mime.types;

server {

listen 80;
server_name 167.99.93.26;

root /sites/demo;

index index.php index.html;

location / {
try_files $uri $uri/ =404;
}

location ~\.php$ {
# Pass php requests to the php-fpm service (fastcgi)
include fastcgi.conf;
fastcgi_pass unix:/run/php/php7.1-fpm.sock;
}

#location = /thumb.png {
#add_header Cache-Control public;
#add_header Pragma public;
#add_header Vary Accept-Encoding;
#expires 60m;
#}

location ~* \.(css|js|jpg|png)$ {
access_log off;
add_header Cache-Control public;
add_header Pragma public;
add_header Vary Accept-Encoding;
expires 1M;
}

}
}

gzip

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
user www-data;

worker_processes auto;

events {
worker_connections 1024;
}

http {

include mime.types;

gzip on;
gzip_comp_level 3;

gzip_types text/css;
gzip_types text/javascript;

server {

listen 80;
server_name 167.99.93.26;

root /sites/demo;

index index.php index.html;

location / {
try_files $uri $uri/ =404;
}

location ~\.php$ {
# Pass php requests to the php-fpm service (fastcgi)
include fastcgi.conf;
fastcgi_pass unix:/run/php/php7.1-fpm.sock;
}

location ~* \.(css|js|jpg|png)$ {
access_log off;
add_header Cache-Control public;
add_header Pragma public;
add_header Vary Accept-Encoding;
expires 1M;
}

}
}

FastCGI Cache

cache between Nginx and backend-server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
user www-data;

worker_processes auto;

events {
worker_connections 1024;
}

http {

include mime.types;

# Configure microcache (fastcgi)
fastcgi_cache_path /tmp/nginx_cache levels=1:2 keys_zone=ZONE_1:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
add_header X-Cache $upstream_cache_status;

server {

listen 80;
server_name 167.99.93.26;

root /sites/demo;

index index.php index.html;

# Cache by default
set $no_cache 0;

# Check for cache bypass
if ($arg_skipcache = 1) {
set $no_cache 1;
}

location / {
try_files $uri $uri/ =404;
}

location ~\.php$ {
# Pass php requests to the php-fpm service (fastcgi)
include fastcgi.conf;
fastcgi_pass unix:/run/php/php7.1-fpm.sock;

# Enable cache
fastcgi_cache ZONE_1;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $no_cache;
fastcgi_no_cache $no_cache;
}

}
}

Security

HTTPS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
user www-data;

worker_processes auto;

events {
worker_connections 1024;
}

http {

include mime.types;

# Redirect all traffic to HTTPS
server {
listen 80;
server_name 167.99.93.26;
return 301 https://$host$request_uri;
}

server {

listen 443 ssl http2;
server_name 167.99.93.26;

root /sites/demo;

index index.html;

ssl_certificate /etc/nginx/ssl/self.crt;
ssl_certificate_key /etc/nginx/ssl/self.key;

# Disable SSL
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

# Optimise cipher suits
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

# Enable DH Params
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

# Enable HSTS
add_header Strict-Transport-Security "max-age=31536000" always;

# SSL sessions
ssl_session_cache shared:SSL:40m;
ssl_session_timeout 4h;
ssl_session_tickets on;

location / {
try_files $uri $uri/ =404;
}

location ~\.php$ {
# Pass php requests to the php-fpm service (fastcgi)
include fastcgi.conf;
fastcgi_pass unix:/run/php/php7.1-fpm.sock;
}

}
}

Rate Limiting

  • Security - Brute Force Protection
  • Reliability - Prevent Traffic Spikes
  • Shaping - Service Priority

。。。要用到再看吧https://www.udemy.com/course/nginx-fundamentals/learn/lecture/10617504#questions

Reverse Proxy

The proxy allows users to be anonymous to the server.

The reverse proxy allows the server to be anonymous to users

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffers

https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/

Load balancer

  1. Distribute requests to multiple servers
  2. Provide redundancy (if one fails, Nginx can redirect to another server)

upstream is the key. Round-Robben: We then distribute requests to all upstream servers equally!!

See docs for detail

http://nginx.org/en/docs/http/ngx_http_upstream_module.html

https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/

http://nginx.org/en/docs/http/load_balancing.html

If one server is down, Nginx will automatically redirect requests to the available server! So cool!

Other load balance option

  1. Sticky Session: ip_hash; (for example: session state )
  2. Avoid heavy connections on a server: least_conn

Some docs:

https://www.digitalocean.com/community/search?q=nginx

http://nginx.org/en/docs/

https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/

Other Adds -on | My Notes 📒

http:// 80

https:// 443

Benefits of proxy

  1. Anonymity
  2. Caching
  3. Blocking unwanted sites
  4. GeoFencing

Benefits of reverse proxy

  1. Load balancing
  2. Caching
  3. Isolating internal traffic
  4. Canary Deployment

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!