nginx client_max_body_size per http method - nginx

I'm trying to setup nginx to separate client_max_body_size in one location per http method, but client_max_body_size isn't working with "if" and "limit_except":
1) Config:
location /test {
limit_except POST {
client_max_body_size 1g;
}
proxy_pass ...
}
nginx -s reload:
nginx: [emerg] "client_max_body_size" directive is not allowed here
2) Config:
location /test {
if ($request_method !~* POST) {
client_max_body_size 1g;
}
proxy_pass ...
}
I get the same message on reload.
How can I set client_max_body_size per http method?

Maybe you can solve this by defining an upstream and use proxy_pass to redirect at the right condition:
http://nginx.org/en/docs/http/ngx_http_upstream_module.html

Related

How to redirect API calls with nginx?

Using nginx I am trying to redirect API calls to an external API provider website but after a lot of research and tries I feel I miss something important.
For example, my goal is when I open https://mywebsite/api/somedata, then a remote API provider is called https://api-somewebsite.com/somedata.
My basic try was:
location /api/ {
proxy_pass https://api-somewebsite.com/;
}
I added a log format to try to get more informations:
log_format upstreamlog '[$time_local] $remote_addr - $remote_user - $server_name $host to: $upstream_addr: $request $status upstream_response_time $upstream_response_time msec $msec request_time $request_time';
Then used it to log the calls:
location /api/ {
proxy_pass https://api-somewebsite.com/;
access_log /var/log/nginx/upstream.log upstreamlog;
}
And it seems that the /api/ part is not well removed:
[21/Sep/2022:11:23:17 -0400] 88.163.105.196 - - - mywebsite.com mywebsite.com to: xxx.xx.xx.xx:xxx, xxx.xx.xx.xx:xxx: GET /api/somedata HTTP/1.1 502 upstream_response_time 0.005, 0.008 msec 1663773797.354 request_time 0.012
So basically it seems to call https://api-somewebsite.com/àpi/somedata which does not exist and thus return 502 error.
I have read that with the trailing / the /api/ part should be well removed automatically. But it does not work. So I tried to rewrite it by myself:
location /api/ {
proxy_pass https://api-somewebsite.com/;
access_log /var/log/nginx/upstream.log upstreamlog;
rewrite ^/api/(.*) /$1 break;
}
Still no luck.
I ended up trying some stuff found on the web but that I do not fully understand... like adding proxy_redirect instruction:
location /api/ {
proxy_pass https://api-somewebsite.com/;
access_log /var/log/nginx/upstream.log upstreamlog;
rewrite ^/api/(.*) /$1 break;
proxy_redirect https://api-somewebsite.com/ /api/;
}
Well, I feel that I lack some basic stuff to make it work, but I cannot find what. Any insights would be greatly appreciated.
====== EDIT 1 ======
According to Stephen Dunne answer, i tried to add an upstream for the server.
Here is my edited code:
upstream magiceden {
server api-mainnet.magiceden.dev:443 max_fails=0;
zone magiceden-api 64k;
keepalive 60;
}
server {
server_name genoverse.me www.genoverse.me;
location / {
root /home/hcomere/genoverse.me;
index index.html;
}
location /magiceden_api/ {
proxy_pass https://magiceden/;
access_log /var/log/nginx/access_magiceden.log upstreamlog;
}
listen [::]:443 ssl; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/genoverse.me/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/genoverse.me/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
I still have error 502 - Bad Gateway - when visiting https://www.genoverse.me/magiceden_api/
where i should get an error 400 - Not found - from the api provider
https://api-mainnet.magiceden.dev/
====== EDIT 2 ======
Oh well, i discovered that browsers have a redirect cache, this explain why sometimes things did not work where they should work.
Once i cleared the redirect cache after each config modification, things were way more smooth and understandable !...
I think the issue here is that you are using a Uri and not an upstream.
I have read that with the trailing / the /api/ part should be well removed automatically.
This is correct.
Try adding an upstream for the server.
upstream somesite {
server api-somewebsite.com:443 max_fails=0;
zone somesite-api 64k;
keepalive 60;
}
And then use the upstream in your location block (keeping the trailing slash)
location /api/ {
proxy_pass https://somesite/;
access_log /var/log/nginx/upstream.log upstreamlog;
}
Now when you browse to the /api location you should be redirected as expected.

NGINX as reverse proxy for http and ssh

I'm trying to set up NGINX as a reverse proxy for HTTP and SSL.
Here is a configuration in /etc/nginx/conf.d/default.conf:
upstream sample-client {
server sample-client:3006;
}
upstream sample-server {
server sample-server:3000;
}
upstream ssh {
server sample-server:22;
}
server {
listen 80;
location / {
proxy_pass http://sample-client;
}
location /api {
rewrite /api/(.*) /$1 break;
proxy_pass http://sample-server;
client_max_body_size 100M;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;
}
error_page 405 =200 #405;
location #405 {
root /usr/share/nginx/html;
proxy_pass http://sample-client;
}
}
server {
listen 22;
proxy_pass ssh;
}
But it throws the next error:
nginx: [emerg] "proxy_pass" directive is not allowed here in /etc/nginx/conf.d/default.conf:60
What's going wrong?
proxy_pass directive should be inside location block
described in https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/
To pass a request to an HTTP proxied server, the
proxy_pass directive is specified inside a
location .
this means that the second server location must include a location block
probably similar to
location / {
proxy_pass ssh;
}

nginx http server location include unknown directive error

my nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
upstream app_servers {
server 127.0.0.1:5000;
server 127.0.0.1:5001;
}
server {
listen 6200;
server_name test;
add_header X-GG-Cache-Status $upstream_cache_status;
include rewrite.conf;
}
}
and my rewrite.conf in the same folder as that
location = / {
rewrite ^/some-custom-destination/?$ /destination/detail?id=33;
proxy_pass http: //app_servers;
proxy_intercept_errors on;
error_page 400 404 /;
error_page 500 502 503 504 /error.html;
location = /error.html {
root /etc/nginx/;
}
}
when I use nginx -s reload command getting that error : nginx: [emerg] unknown directive "location" in /etc/nginx/rewrite.conf:1
How can I fix that?
Help, please. Thank you.
Apart from the space in your proxy_pass directive, there is one more issue with your location block.
From the nginx documentation about nginx location directive (http://nginx.org/en/docs/http/ngx_http_core_module.html#location), you cannot have a nested location inside a location block “location = /”.
“Also, using the “=” modifier it is possible to define an exact match of URI and location. If an exact match is found, the search terminates. For example, if a “/” request happens frequently, defining “location = /” will speed up the processing of these requests, as search terminates right after the first comparison. Such a location cannot obviously contain nested locations.”

Why is my nginx "rewrite" directive causing a redirection loop?

Given the following http block, nginx performs as expected. That is, it will rewrite a URL such as http://localhost/3ba48599-8be8-4326-8bd0-1ac6591c2041/ to http://localhost/modif/3ba48599-8be8-4326-8bd0-1ac6591c2041/ and pass it to the uwsgi server.
http {
upstream frontend {
server frontend:8000;
}
server {
listen 8000;
server_name localhost;
root /www/;
location ~* "^/([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})/?$" {
include uwsgi_params;
set $uuid $1;
if ($cookie_admin) {
# if cookie exists, rewrite /<uuid> to /modif/<uuid> and pass to uwsgi
rewrite / /modif/$uuid break;
uwsgi_pass frontend;
}
content_by_lua_block {
ngx.say("Ping! You got here because you have no cookies!")
}
}
}
}
However, when I add another location block in the manner displayed blow, things fall appart and I get ERR_TOO_MANY_REDIRECTS.
http {
# access_log /dev/stdout; # so we can `docker log` it.
upstream frontend {
server frontend:8000;
}
server {
listen 8000;
server_name localhost;
root /www/;
location / { # THIS MAKES EVERYTHING FALL APART :(
uwsgi_pass frontend;
include uwsgi_params;
}
location ~* "^/([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})/?$" {
include uwsgi_params;
set $uuid $1;
if ($cookie_admin) {
# if cookie exists, rewrite /<uuid> to /modif/<uuid> and pass to uwsgi
rewrite / /modif/$uuid break;
uwsgi_pass frontend;
}
content_by_lua_block {
ngx.say("Ping! You got here because you have no cookies!")
}
}
}
}
What's going on here, exactly? How can I fix this?
I see your Nginx is listening on port 8000, but your upstream server is at 'frontend', also on port 8000. If frontend resolves to the same server that Nginx is running on, then you've got a loop of proxy requests happening.

Nginx proxy_next_upstream doesn't work

I want nginx to search my local host for the file first and on a 404 error it should search server 1.1.1.1.
I am able to fetch the file that is located on local host, but not able to get from server 1.1.1.1.
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/access.log main;
location /products/ {
proxy_next_upstream http_404;
root /var/foo;
}
}
server {
listen 80;
server_name 1.1.1.1;
location /products/ {
#########
}
}
I guess proxy_next_upstream is not switching to the server.
Any help on this would be appreciated.
The proxy_next_upstream directive is a configuration directive to control re-request from a group of upstream servers by a proxy_pass if request to one of them fails. It doesn't make sense without proxy_pass and an upstream block defined. You may use it if you proxy to multiple upstream servers like this:
upstream backends {
server 192.2.0.1;
server 192.2.0.2;
...
}
server {
...
location / {
proxy_pass http://backends;
proxy_next_upstream error timeout http_404;
}
}
If you want nginx to search for a file on disk, and if it's not found - proxy request to another server, configure it e.g. using try_files fallback instead:
location / {
root /path/to/root;
try_files $uri #fallback;
}
location #fallback {
proxy_pass http://...
}
See http://nginx.org/r/try_files for more info about the try_files directive.

Resources