Friday 10 May 2024

Introduction to Nginx

 




What is Nginx?

HTTP and reverse proxy server.


How to install Nginx on Linux?


Where is Nginx binary?

# which nginx
/usr/sbin/nginx

To check Nginx version:

# nginx -v
nginx version: nginx/1.24.0


Nginx Configuration



Nginx configuration file is /etc/nginx/nginx.conf.

cat /etc/nginx/nginx.conf
#######################################################################
#
# This is the main Nginx configuration file.
#
# More information about the configuration options is available on
#   * the English wiki - http://wiki.nginx.org/Main
#   * the Russian documentation - http://sysoev.ru/nginx/
#
#######################################################################

#----------------------------------------------------------------------
# Main Module - directives that cover basic functionality
#
#   http://wiki.nginx.org/NginxHttpMainModule
#
#----------------------------------------------------------------------

user                 mywebapp-user;
worker_processes     auto;
worker_rlimit_nofile 10000;

#timer_resolution 100ms;

error_log  /var/log/nginx/error.log;
#error_log  /var/log/nginx/error.log  notice;
#error_log  /var/log/nginx/error.log  info;

pid        /var/run/nginx.pid;

#----------------------------------------------------------------------
# Events Module
#
#   http://wiki.nginx.org/NginxHttpEventsModule
#
#----------------------------------------------------------------------

events {
worker_connections  4000;
use epoll;
#    accept_mutex on;
}

#----------------------------------------------------------------------
# HTTP Core Module
#
#   http://wiki.nginx.org/NginxHttpCoreModule
#
#----------------------------------------------------------------------

http {

server_names_hash_bucket_size 128;

        map $http_cf_ipcountry $allowed_country {
           default 1;
           "KP"    0; # Korea, Democratic Peoples Republic of (North Korea)
        }

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

        log_format    main '$remote_addr - $remote_user [$time_local] "$host"
                      "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" 
                      "$http_cf_ipcountry"';

access_log  /var/log/nginx/access.log  main;

gzip            on;
gzip_vary       on;
gzip_types      text/plain 
                        text/xml 
                        text/css 
                        application/json
                        application/x-javascript;
gzip_min_length 1024;

server_tokens off;

# Replace client IP from proxies
real_ip_header X-Forwarded-For;
set_real_ip_from 10.0.0.0/8;  # AWS VPC CIDR
set_real_ip_from 108.22.214.0/22; # Cloudflare 
...
set_real_ip_from 2b06:27c0::/29; # Cloudflare 
real_ip_recursive on;

sendfile        on;
# tcp_nopush      on;
# tcp_nodelay     on;

keepalive_timeout  60;

server {
  listen 80;
server_name "";
return 403;
}

# Load config files from the /etc/nginx/conf.d directory
include /etc/nginx/conf.d/*.conf;
}

This is a base config file which is usually enough if we're hosting a single website.

If we're hosting multiple websites/domains/brands, we want to keep their configuration isolated in separate files which reside in /etc/nginx/conf.d/*.conf. We create a config file for each website and define for example different error and access log files.

ls -la /etc/nginx/conf.d/
total 56
drwxr-xr-x. 3 root     root       175 May  8 13:07 .
drwxr-xr-x. 4 root     root     16384 May  8 13:07 ..
drwxr-x---. 2 ec2-user ec2-user 16384 May  8 13:07 includes
-rw-r-----. 1 ec2-user ec2-user  1474 May  8 13:03 nginx.brandA.conf
-rw-r-----. 1 ec2-user ec2-user  1434 May  8 13:03 nginx.brandB.conf
-rw-r-----. 1 ec2-user ec2-user  1545 May  8 13:03 nginx.brandC.conf
-rw-r-----. 1 ec2-user ec2-user   858 May  8 13:03 nginx_status.conf

Let's check what can be in override file: 

cat  /etc/nginx/conf.d/nginx.brandA.conf 
server {

# server settings
listen      80;
# listen      443 ssl;
server_name ~^(dev-|stage-|beta-)?(mywebapp)\.mydomainA\.com$; 
               
resolver    149.214.169.253; # Amazon EC2 inside VPC

# log settings
error_log /home/mywebapp-user/logs/nginx/error-mywebapp.log;
access_log /home/mywebapp-user/logs/nginx/access-mywebapp.log main;

# client settings
client_body_temp_path /home/mywebapp-user/tmp/client_body;

        # block visitors from certain countries
        if ($allowed_country = 0) {
          return 403; # forbidden
        }

# path settings
root  /home/mywebapp-user/public;
index index.html index.htm index.php;

# protect private files
        location ~ ^/private/(.*)$ {
include conf.d/includes/nginx.trusted-ips.conf;
include conf.d/includes/nginx.php-fpm-brandA.conf;
}

        # block countries defined in nginx.conf
        include conf.d/includes/nginx.geoip2.conf;

# allow .php files to be executed
include conf.d/includes/nginx.php-fpm-brandA.conf;
}


Before restarting or reloading Nginx server completely it is advisable to test its configuration file:

nginx -t
nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If we try to run this command as non-admin user, we'll get an error:

nginx -t
nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)
2024/05/09 16:12:33 [emerg] 349382#349382: open() "/etc/nginx/nginx.conf" failed (13: Permission denied)
nginx: configuration file /etc/nginx/nginx.conf test failed


Nginx Service



To check if Nginx service is running:

# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/nginx.service.d
             └─php-fpm.conf
     Active: active (running) since Wed 2024-05-08 13:31:37 UTC; 1 day 19h ago
    Process: 3797 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
    Process: 3804 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
    Process: 3805 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
   Main PID: 3806 (nginx)
      Tasks: 3 (limit: 2120)
     Memory: 9.6M
        CPU: 42.250s
     CGroup: /system.slice/nginx.service
             ├─3806 "nginx: master process /usr/sbin/nginx"
             ├─3807 "nginx: worker process"
             └─3808 "nginx: worker process"

May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Starting nginx.service - The nginx HTTP and reverse proxy server...
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[3804]: nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[3804]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[3804]: nginx: configuration file /etc/nginx/nginx.conf test is successful
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[3805]: nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Started nginx.service - The nginx HTTP and reverse proxy server.

If we try to run the binary when service is already working, it will try to bind to local ports which would obvously fail:

# nginx
nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:81 failed (98: Address already in use)
nginx: [emerg] still could not bind()


To verify that nginx processes are listening on TCP ports 80 and 81 we can use lsof (list open files) command with option -i (match Internet address):

# lsof -i TCP:80
COMMAND    PID          USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
nginx     3806          root   18u  IPv4   20970      0t0  TCP *:http (LISTEN)
nginx   559036 my-user    3u  IPv4 3101478      0t0  TCP ip-10-107-112-168.ec2.internal:http->ip-10-107-112-40.ec2.internal:36372 (ESTABLISHED)
nginx   559036 my-userk    9u  IPv4 3101479      0t0  TCP ip-10-107-112-168.ec2.internal:http->ip-10-107-112-141.ec2.internal:14406 (ESTABLISHED)
...
nginx   559036 my-user   15u  IPv4 3101485      0t0  TCP ip-10-107-112-168.ec2.internal:http->ip-10-107-112-59.ec2.internal:29186 (ESTABLISHED)
nginx   559036 my-user   18u  IPv4   20970      0t0  TCP *:http (LISTEN)
nginx   559037 my-user   18u  IPv4   20970      0t0  TCP *:http (LISTEN)

# lsof -i TCP:81
COMMAND    PID          USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx     3806          root   19u  IPv4  20971      0t0  TCP *:81 (LISTEN)
nginx   559036 my-user   19u  IPv4  20971      0t0  TCP *:81 (LISTEN)
nginx   559037 my-user   19u  IPv4  20971      0t0  TCP *:81 (LISTEN)


Changing the configuration


After changing nginx.conf we need to restart nginx:

$ /etc/init.d/nginx stop
rm: cannot remove ‘/var/run/nginx.pid’: Permission denied  [FAILED]

We need to become root in order to restart nginx:

# /etc/init.d/nginx stop
Stopping nginx:                                            [  OK  ]

# /etc/init.d/nginx start
Starting nginx:                                            [  OK  ]


To reload the configuration without downtime:

# systemctl reload  nginx


Let's check the status again:

# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/nginx.service.d
             └─php-fpm.conf
     Active: active (running) since Wed 2024-05-08 13:31:37 UTC; 1 day 19h ago
    Process: 3797 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
    Process: 3804 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
    Process: 3805 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
    Process: 559035 ExecReload=/usr/sbin/nginx -s reload (code=exited, status=0/SUCCESS)
   Main PID: 3806 (nginx)
      Tasks: 3 (limit: 2120)
     Memory: 10.3M
        CPU: 42.343s
     CGroup: /system.slice/nginx.service
             ├─  3806 "nginx: master process /usr/sbin/nginx"
             ├─559036 "nginx: worker process"
             └─559037 "nginx: worker process"

May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Starting nginx.service - The nginx HTTP and reverse proxy server...
...
May 10 09:11:32 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Reloading nginx.service - The nginx HTTP and reverse proxy server...
May 10 09:11:32 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[559035]: nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
May 10 09:11:32 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Reloaded nginx.service - The nginx HTTP and reverse proxy server.


----

No comments: