How to disable logging for illegal host headers request in nginx - nginx

In my nginx.conf, I add the following code to deny the illegal request:
server {
...
## Deny illegal Host headers
if ($host !~* ^(www.mydomain.com|xxx.xxx.xxx.xxx)$) {
return 444;
}
...
}
But this request info always be written in access log, which is monitor request I think because they are so many and from two unsafe site and just HEAD request.
So how to stop logging these illegal request info to access log?
Thanks.

You should use separate server blocks
server {
listen 80;
# valid host names
server_name www.example.com;
server_name xx.xx.xx.xx;
# you site goes here
}
# requests with all other hostnames will be caught by this server block
server {
listen 80 default_server;
access_log off;
return 444;
}
That would be simple and efficient

So shamed to find that nginx(1.7.0 and later) log moudle has provided conditional logging, and the document example is just the status condition:
The if parameter (1.7.0) enables conditional logging. A request will not be logged if the condition evaluates to “0” or an empty string. In the following example, the requests with response codes 2xx and 3xx will not be logged:
map $status $loggable {
~^[23] 0;
default 1;
}
access_log /path/to/access.log combined if=$loggable;
Also answer Disable logging in nginx for specific request has mentioned this info. I just neglected it.
Now I add the following code to nginx log settings:
map $status $loggable {
~444 0;
default 1;
}
access_log /var/log/nginx/access.log combined if=$loggable;
the illegal host headers request has not been logged.

Related

NGINX rate limitting by decoded values from JWT token

I have a question regarding NGINX rate limiting.
Is it possible to do rate limiting based on the decoded value of JWT token? I cannot find any information like this in the docs.
Or even if there is a way of doing rate limiting by creating pure custom variable (using LuaJIT) which will be assigned with a value from my decoded JWT - will also do the job.
The thing is that the limit_req module seems to execute way before the request reaches the luaJIT stage so its already too late!
A solution will be appreciated.
As you may know that rate limit is applied through unique ip address for best result you should use unique jwt value or token to rate limit.
You can follow any of these 3 methods
Method
You can directly use jwt token in limit_req_zone.
http {
...
limit_req_zone $http_authorization zone=req_zone:10m rate=5r/s;
}
conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
if ($http_authorization = "") {
return 403;
}
location /jwt {
limit_req zone=req_zone burst=10 nodelay;
return 200 $http_authorization;
}
...
}
Method
You can send decoded jwt value from frontend in reqest header like http_x_jwt_decode_value and then you can use that in limit_req_zone.
http {
...
limit_req_zone $http_x_jwt_decode_value zone=req_zone:10m rate=5r/s;
}
conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
if ($http_x_jwt_decode_value = "") {
return 403;
}
location /jwt {
limit_req zone=req_zone burst=10 nodelay;
return 200 $http_x_jwt_decode_value;
}
...
}
Method
You can decode jwt token in nginx though njs javascript module or perl module or lua module and assign it to variable then use that to rate limit.
Description: here i just decoded jwt value and checked if its not empty you can use it to work with and jwt decoded value.
jwt_example.js
function jwt(data) {
var parts = data.split('.').slice(0,2)
.map(v=>String.bytesFrom(v, 'base64url'))
.map(JSON.parse);
return { headers:parts[0], payload: parts[1] };
}
function jwt_payload_sub(r) {
return jwt(r.headersIn.Authorization.slice(7)).payload.sub;
}
export default {jwt_payload_sub}
nginx.conf
# njs module
load_module modules/ngx_http_js_module.so;
http {
...
include /etc/nginx/conf.d/*.conf;
js_import main from jwt_example.js;
js_set $jwt_payload_sub main.jwt_payload_sub;
limit_req_zone $jwt_payload_sub zone=req_zone:10m rate=5r/s;
}
conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
if ($jwt_payload_sub = "") {
return 403;
}
location /jwt {
limit_req zone=req_zone burst=10 nodelay;
return 200 $jwt_payload_sub;
}
...
}
JWT Auth for Nginx
nginx-jwt is a Lua script for the Nginx server (running the HttpLuaModule) that will allow you to use Nginx as a reverse proxy in front of your existing set of HTTP services and secure them (authentication/authorization) using a trusted JSON Web Token (JWT) in the Authorization request header, having to make little or no changes to the backing services themselves.
IMPORTANT: nginx-jwt is a Lua script that is designed to run on Nginx servers that have the HttpLuaModule installed. But ultimately its dependencies require components available in the OpenResty distribution of Nginx. Therefore, it is recommended that you use OpenResty as your Nginx server, and these instructions make that assumption.
Configuration
At the moment, nginx-jwt only supports symmetric keys (alg = hs256), which is why you need to configure your server with the shared JWT secret below.
1.Export the JWT_SECRET environment variable on the Nginx host, setting it equal to your JWT secret. Then expose it to Nginx server:
# nginx.conf:
env JWT_SECRET;
2.If your JWT secret is Base64 (URL-safe) encoded, export the JWT_SECRET_IS_BASE64_ENCODED environment variable on the Nginx host, setting it equal to true. Then expose it to Nginx server:
# nginx.conf:
env JWT_SECRET_IS_BASE64_ENCODED;
JWT Auth for Nginx

How to test load balancing in nginx?

I done congfiguration in nginx for redirection and it works successfully.
But in that i want load balancing :-
for that i already create load-balancer.conf as well as give server name into that file like :-
upstream backend {
# ip_hash;
server 1.2.3.4;
server 5.6.7.8;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
In both instances i did same configuration
and it default uses round-robin algorithm so in that request transfer via one pc to another pc.....
but it were not working
can any one suggest me anything that secong request going to another server 5.6.7.8
so i can check load balancing.
Thankyou so much.
Create a log file for upstream to check request is going to which server
http {
log_format upstreamlog '$server_name to: $upstream_addr {$request} '
'upstream_response_time $upstream_response_time'
' request_time $request_time';
upstream backend {
# ip_hash;
server 1.2.3.4;
server 5.6.7.8;
}
server {
listen 80;
access_log /var/log/nginx/nginx-access.log upstreamlog;
location / {
proxy_pass http://backend;
}
}
and then check your log file
sudo cat /var/log/nginx/nginx-access.log;
you will see log like
to: 5.6.7.8:80 {GET /sites/default/files/abc.png HTTP/1.1} upstream_response_time 0.171 request_time 0.171

How to keep track of an upstream when nginx has multiple upstreams?

upstream app_server {
server unix: server1
}
upstream app_server_new {
server unix: server2
}
server {
location ^~ /about {
proxy_pass http://app_server_new
}
location #app {
proxy_pass http://app_server
}
}
So when the user hits /about, the server redirects to upstream app_server_new.
Now I have a development.log file for puma. But that doesn't tell to which upstream the redirect went. Is there any way by which I can know if the redirect actually works, like keeping a log about hits to that upstream?
You can define custom log for that.
Use the fields of your choice:
log_format upstream '$remote_addr - $upstream_addr - $request - $upstream_response_time - $request_time';
Then use it in the context specific to your needs:
access_log /var/log/nginx/upstream.log upstream;
More information can be found there:
http://nginx.org/en/docs/http/ngx_http_log_module.html
http://nginx.org/en/docs/http/ngx_http_upstream_module.html

In Nginx, "etag" directive doesn't work for proxy_pass?

I'm using Nginx 1.9.2 and following is my configuration
upstream httpserver0{
server 127.0.0.1:35011 max_fails=3 fail_timeout=30s; #H_server0
}
server {
listen 443 ssl;
listen 80;
server_name 11.22.33.44; #my_server_name
etag on;
location ~* \.(ts|raw)$ {
set $server_id "0";
if ( $uri ~ ^/(.*cfs+)/(.*)$ ){
set $server_id $1;
}
if ( $server_id = "4cfs" ){
proxy_pass http://httpserver0$request_uri;
}
}
}
I'm using upstream module and proxy_pass for reverse proxy, and I enabled etag function by etag on within the server block.
However, when I check the Header of HTTP response, I didn't find the etag field at all..
Does anyone have ideas about this? Thanks!
No, it does not work for proxy_pass.
http://nginx.org/r/etag
Enables or disables automatic generation of the “ETag” response header field for static resources.
Even more, it's turned on by default.

How to configure nginx to auto redirect to the main hostname?

Each nginx config can act for a wide range of domains but I want to auto-redirect requests to the first domain name (the official one).
server {
server_name a.example.com b.example.com;
}
I want that if someone enters b.example.com/some, to go directly to a.example.com/some
This is pretty much the same thing as the GOOD example for http://wiki.nginx.org/Pitfalls#Server_Name. That is, you should use two servers:
server {
server_name b.example.com;
return 301 $scheme://a.example.com$request_uri;
# For pre-0.8.42 installations:
# rewrite ^ $scheme://a.example.com$request_uri? permanent;
}
server {
server_name a.example.com;
# Do stuff
}
To do this in a single server block, you can use an if and the $server_name variable:
server_name primary.tld secondary.tld;
if ($host != $server_name) {
rewrite ^ $scheme://$server_name permanent;
}
Or, to keep any query parameters:
server_name primary.tld secondary.tld;
if ($host != $server_name) {
rewrite ^/(.*) $scheme://$server_name/$1 permanent;
}
Here, $server_name refers to primary server name, which is the first name in the server_name directive, while $host refers to the hostname given in the HTTP request.
Note that the if statement in nginx configuration does not always do what you would expect and its use is discouraged by some. See also https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/
This answer was inspired by this answer to another question which uses a similar aproach.
Combined version of #kolbyjack and #Matthijs answers with one server block. This config will redirect all requests with Host header different from example.com and process only example.com requests.
server {
server_name example.com a.example.com b.example.com;
if ($host != $server_name) {
return 301 $scheme://$server_name$request_uri;
}
# processing requests to $server_name (example.com) only
...
}

Resources