What is Nginx?
- HTTP and reverse proxy server
- widely used webserver
How to install Nginx on Linux?
Nginx serves a static HTML file by default so we can verify the deployment.
Where is Nginx binary?
# which nginx
/usr/sbin/nginx
/usr/sbin/nginx
To check Nginx version:
# nginx -v
nginx version: nginx/1.24.0
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;
# user nginx;
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;
# worker_connections 1024;
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 the 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$;
# server_name phpfpm.local;
# server_name localhost;
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;
}
# serve dmg files
location ~ \.dmg$ {
try_files $uri $uri/ /index.php?$query_string;
}
# serve pkg files
location ~ \.pkg$ {
try_files $uri $uri/ /index.php?$query_string;
}
# serve bz2 files
location ~ \.bz2$ {
try_files $uri $uri/ /index.php?$query_string;
}
# serve zip files
location ~ \.zip$ {
try_files $uri $uri/ /index.php?$query_string;
}
# serve exe files
location ~ \.exe$ {
add_header Content-Disposition "attachment";
try_files $uri $uri/ /index.php?$query_string;
}
# return 404 for anything else
location / {
return 404;
}
# 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;
}
server block defines a virtual server that will handle requests. We can define multiple server blocks to handle different domains or ports.
- listen <port_number>
- Listen on port <port_number> for incoming HTTP connections.
- listen <port_number> ssl
- Listen on port <port_number> for incoming HTTPS connections.
- server_name <domain_name | IP>
- Domain name or IP address that this server block should respond to.
- localhost is typically used for local development. For local development we can actually use an arbitrary domain name value but then in /etc/hosts we need to add a line: 127.0.0.1 <domain_name>
- For a live server, replace this with the actual domain name.
- resolver
- error_log
- access_log
- client_body_temp_path
- root
- Set the root directory for the server. This is where Nginx will look for files to serve.
- This is where our application files should be located.
- /var/www/html is a common directory for web content.
- index <file_1> <file_2> ... <file_N>
- Specifies the default files to serve when a directory is requested.
- If a user navigates to http://example.com/, Nginx will look for index.html, index.htm and index.php, in that order.
- location / { ... }
- Defines how to process requests for the root URL path.
- This block specifies how to handle requests to the root of the website.
- location ~ \.php$ { ... }
- This block handles requests for PHP files.
- The tilde (~) indicates a regular expression match. Any request that ends in .php will be processed by this block.
- include
location block attributes:
- fastcgi_pass
- Specifies the address and port of the FastCGI server (PHP-FPM).
- Example: fastcgi_pass php-fpm:9000;
- In this case, php-fpm:9000 indicates that PHP-FPM is running on the php-fpm service on port 9000. php-fpm matches the hostname of the machine which runs the PHP-FMP service
- fastcgi_index
- Sets the default file to serve if the FastCGI request points to a directory. If a directory is requested, Nginx will serve index.php from that directory.
- Example:
- fastcgi_index index.php;
- fastcgi_index helloworld.php;
- include fastcgi_params;
- Includes a file with FastCGI parameters. These parameters are necessary for Nginx to communicate with PHP-FPM. The fastcgi_params file typically resides in /etc/nginx/ or /etc/nginx/conf.d/.
- fastcgi_param - sets FastCGI parameter's value that Nginx will send to php-fpm service (which is usually listening on port 9000)
- SCRIPT_FILENAME $document_root$fastcgi_script_name;
- Sets the SCRIPT_FILENAME parameter, which tells PHP-FPM the path of the script to execute. The value is constructed by appending the script name ($fastcgi_script_name) to the document root ($document_root).
- PATH_INFO $fastcgi_path_info;
- try_files path1 [path2] uri - Checks for the existence of files in order, and returns the first file that is found. A trailing slash indicates a directory - $uri /. In the event that no file is found, an internal redirect to the last parameter is invoked. The last parameter is the fallback URI and must exist, or else an internal error will be raised.
Nginx config file variables:
- $document_root
- a variable that represents the root directory for the current request. It is used to specify the base directory from which files are served. This variable is particularly useful when configuring PHP handling, redirections, and other file-serving directives.
- holds the path to the root directory specified in the root directive of the server or location block handling the request.
- commonly used in conjunction with other variables like $fastcgi_script_name to construct the full path to the PHP script being executed or served.
- Example: if root is set to /var/www/html, a request is made for /path/to/file.html (https://www.example.com/path/to/file.html), Nginx will look for the file at /var/www/html/path/to/file.html
- $fastcgi_script_name
- path of the requested PHP script relative to the document root. It is used to pass the script's path to PHP-FPM for processing.
- Suppose a client requests http://example.com/index.php
- If $document_root is /var/www/html, Nginx will look in /var/www/html for index.php
- $fastcgi_script_name would be /index.php, the path relative to $document_root.
- The full path passed to PHP-FPM via fastcgi_param SCRIPT_FILENAME would be /var/www/html/index.php.
--- --- ---
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()
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.
Running Nginx & PHP-FPM as Docker containers
Nginx and PHP-FPM can run separately, each in its own Docker container. For Nginx, we can use the original Nginx image and for PHP-FPM we can crate a custom image, which also contains our PHP application.
It is important that both containers need to have PHP application at the same path
- In PHP-FPM Dockerfile we can set WORKDIR to e.g. /var/www/html or /usr/share/nginx/app and copy our application's source code there
- In Nginx conf file, in server block, we then need to set root to the absolute path to the main php script e.g. index.php. If web requests is http://example.com/path/to/index.php and path to this script in PHP-FPM container is e.g. /usr/share/nginx/app/index.php then in nginx conf we'll use /usr/share/nginx/app/ as the value of root ($document_root)
- As Nginx container needs to have an access to PHP app's source code, we'll then use a volume which maps local directory with app to /var/www/html or /usr/share/nginx/app
----
No comments:
Post a Comment