nginx: variable expansion inside split_clients not working? - nginx

i have the following config:
map $host $variant_a {
default 'a';
}
map $host $variant_b {
default 'b';
}
map $host $variant_c {
default 'c';
}
map $host $variant_d {
default 'd';
}
map $host $variant_default {
default 'default';
}
# a/b testing
split_clients "abtest${remote_addr}${http_user_agent}${date_gmt}" $variant_chosen {
20% $variant_a;
20% $variant_b;
20% $variant_c;
20% $variant_d;
20% $variant_default;
}
server {
# defaults test independent
listen 80;
server_name _;
root /home/vagrant/www;
index index.html;
error_page 404 = 404.html;
error_page 403 = 404.html;
location / {
echo a=$variant_a,variant_chosen=$variant_chosen
}
}
when i execute a query against the server:
curl -i http://192.168.33.10/
i can see that the variables inside the 'split_clients' get never expanded.
sample output:
vagrant#precise32:~/www$ curl -i http://192.168.33.10/
HTTP/1.1 200 OK
Server: nginx/1.1.19
Date: Mon, 04 May 2015 15:46:17 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
a=a,variant_chosen=$variant_default
anybody any idea why the variables are not expanded?
any help highly appreciated
cheers
marcel

Related

root context with preference over a regular expression

I have read the documentation and seems it is the same as explained here enter link description here, but during my tests the root context is having precedence over the regular expression one.
Does anyone know the reason?
See my nginx.conf file and a test curl I did to validate the configuration:
http {
server {
listen 80;
root /usr/share/nginx/html;
include /etc/nginx/mime.types;
location ~ /ui(/.*) {
try_files $1 $1/ #htmlext;
}
location #htmlext {
rewrite ^/ui(/\w*)(/.*)*$ $1.html last;
}
location / {
return 301 /ui$request_uri;
}
}
}
/ # curl -v http://localhost/ui/message?msg=error.forbidden
* Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /ui/message?msg=error.forbidden HTTP/1.1
> Host: localhost
> User-Agent: curl/7.67.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.19.0
< Date: Thu, 09 Jul 2020 22:34:49 GMT
< Content-Type: text/html
< Content-Length: 169
< Location: http://localhost/ui/ui/message?msg=error.forbidden
< Connection: keep-alive
<
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.19.0</center>
</body>
</html>
* Connection #0 to host localhost left intact
As you can see in the curl it is redirecting my /ui/message page instead of rendering it. If I remove the location / from the configuration it seems working, if I remove the #htmlext location and add that logic in the location ~ /ui(/.*) it seems working too. Then I think the reason of my error is the #htmlext redirect.
Does anyone know why?
Thanks

NGINX: How to return inline html?

I want to achieve something like this:
server {
listen 80;
location / {
return 200 <html><body>Hello World</body></html>
}
}
i.e., any request should return the inline html. Is this possible with NGINX?
EDIT:
I tried this:
server {
listen 80;
location / {
return 200 '<html><body>Hello World</body></html>'
}
}
But testing in browser did not render the html, instead the browser tried to download a file containing the html which is not the behavior I wanted.
Use the return directive to return HTML code. Remember to set proper content type, otherwise the browser will asume raw text and won’t render the code:
server {
listen 80;
location / {
add_header Content-Type text/html;
return 200 '<html><body>Hello World</body></html>';
}
}
just setting the content type header seems to work on some browsers, however safari on ios stil tries to download the file.
You might have set the content type somwhere else, resulting in 2 content type headers this way.
e.g. in my case curl showed me:
< date: Thu, 11 Nov 2021 01:00:06 GMT
< content-type: application/octet-stream
< content-length: 49
< content-type: text/html
The fix is to clear the global type and set one for a given url
server {
server_name example.com;
listen 80;
location / {
types {}
default_type text/html;
return 200 '<html><body>Hello World</body></html>';
}
}

Return 200 by Nginx without serving a file

I wrote this /etc/nginx/conf.d/apply.conf and started nginx.
server {
location = /hoge {
return 200;
}
}
but the curl command fails.
curl localhost:80/hoge
It says
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.13.9</center>
</body>
</html>
and the logs are
open() "/usr/share/nginx/html/hoge" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: "GET /hoge HTTP/1.1", host: "localhost"
I want to just return the status code without response body or with response body blank.
I changed to this but still not working.
location /hoge {
return 200 'Wow';
add_header Content-Type text/plain;
}
also tried this.
location /hoge {
return 200 'Wow';
default_type text/plain;
}
It is hard to say without context(how your entire nginx config file looks like), because of how nginx processes a request
A config file like the following, should work just fine for what you are looking for:
server {
listen 80;
location /hoge {
return 200;
}
}
However, if your config file has other location blocks(especially if they are regex based) then you may not get the expected solution.
Take an example of this config file:
server {
listen 80;
location /hoge {
return 200;
}
location ~* /ho {
return 418;
}
}
Sending a request to curl localhost:80/hoge would return a http status code 418 instead of 200. This is because the regex location matched before the exact location.
So, the long answer is; it is hard to tell without the context of the whole nginx conf file that you are using. But understanding how nginx processes a request will get you to the answer.

Nginx "auth_request" like option for rate limiting

In Nginx I want to send a pre-request to another endpoint which checks for rate limiting violations. Basically exactly what auth_request does, but where auth_request only accepts authentication status codes (200, 401, 403), I want it to only allow rate limiting codes (200 or 429).
Is there a more general version of auth_request which could be used for this?
For now we're using auth_request, but the downside is it turns 429 status codes into 500s.
Thanks!
Below config works for me and returns a 429 instead of 500
events {
worker_connections 1024;
}
http {
server {
listen 80;
location /api {
auth_request /rate_limit;
error_page 500 = #rate_limit_error;
echo "You were allowed to access the API";
}
location #rate_limit_error {
return 429 "Limit has been exceeded\n";
}
location = /rate_limit {
internal;
return 400 "Access is not allowed";
}
}
}
The test shows the correct response
$ curl -v localhost/api?count=2
* Trying ::1...
* Connected to localhost (::1) port 80 (#0)
> GET /api?count=2 HTTP/1.1
> Host: localhost
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 429
< Server: openresty/1.11.2.2
< Date: Sat, 30 Sep 2017 18:50:56 GMT
< Content-Type: text/plain
< Content-Length: 24
< Connection: close
<
Limit has been exceeded
* Closing connection 0
If you don't want to return a message or something else. You can also use error_page 500 = 429;

How to disable nginx access log by response header

I want to turn off the access log using the response header .
As in the following set .
You do not want to output a log when there is a header .
It does not work .
server {
listen 80;
server_name localhost;
access_log logs/access_debug.log debug_val_format if=$logging;
set $logging 1;
if ( $upstream_http_logoff ){
set $logging 0;
}
Response headers are sent .
Connection:keep-alive
Content-Length:5
Content-Type:text/html; charset=UTF-8
Date:Wed, 11 May 2016 12:04:57 GMT
logoff:1
Server:nginx/1.7.11
X-Powered-By:PHP/5.3.3
You should use map:
map $upstream_http_logoff $logging {
default 1;
1 0;
}
Maybe you should consider to inverse upstream logic, so it would be easier to understand:
Upstream header logging:0
map $upstream_http_logging $logging {
default 1;
0 0;
1 1;
}

Resources