How to set http2 for a specific location block inside nginx configuration file - http

Question related to proxy_http_version in nginx
I have multiple location blocks inside my server block and I want to set h2 protocol on certain locations.
Ex: nginx location block which is inside a server block which has multiple location blocks is placed below.
location ~^/app$|^.*\.(js|css|woff|ttf)$ {
proxy_cache eggstatic;
expires 1d;
proxy_cache_valid 200 1h;
proxy_cache_revalidate on;
proxy_cache_lock on;
proxy_set_header Connection "";
proxy_http_version 1.1; // want to change this to h2
proxy_pass https:site_id;
}
```

Related

Sharing location configuration in nginx

I could not decide the best name for the question.
Essentially what I want to achieve is to set a custom allowed body size for a specific location on the webserver.
On the other hand, I was able to achieve the necessary result already with duplicate code, so I am really looking for a way how to make the code reusable and to better understand the observed behavior.
The server reverse-proxies all API requests to the backend service.
In global nginx config /etc/nginx/nginx.conf I set the rule for max allowed body size like so client_max_body_size 50k;.
Then, in individual server config /etc/nginx/conf.d/example.com I have the following config (simplified):
server {
listen 80;
listen [::]:80;
server_name api.example.com www.api.example.com
location ~* /file/upload {
client_max_body_size 100M;
# crashes without this line
proxy_pass http://localhost:90;
#proxy_pass http://localhost:90/file/upload; # also works
}
location / {
# does not work
#location ~* /file/upload {
# client_max_body_size 100M;
#}
proxy_pass http://localhost:90;
}
}
I am trying to override the max body size for file upload endpoint. See that there is 1 proxy_pass for location /file/upload and another proxy_pass for location / pointing to the same internal service.
Question 1. If I remove the proxy_pass from the location /file/upload then error is returned by the server. (no status code in chrome debugger). Why is this happening? Shouldn't request be propagated further to location /?
Question 2. Why is it not possible to define the sublocation with body size override inside the / location as in commented section in example above? If I set it like this, then 413 error code is returned, which hints that the client_max_body_size rule is ignored..
Question 3. Finally, is it possible to tell nginx, after the request hits the /file/upload location - to apply all the rules from the / section? I guess one solution to this problem would be to move the common configuration into separate file and then import it in both sections.. I was thinking if there is any solution that does not require creating new files?
Here is the reusable config I am talking about basically:
location / {
#.s. kill cache. use in dev
sendfile off;
# kill cache
add_header Last-Modified $date_gmt;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
if_modified_since off;
expires off;
etag off;
# don't cache it
proxy_no_cache 1;
# even if cached, don't try to use it
proxy_cache_bypass 1;
proxy_pass http://localhost:90;
client_max_body_size 100M;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass_request_headers on;
}
This is not the final version. If I had to copy this piece of code to 2 sections this would not be very friendly approach. So, it would be nice to hear some nginx lifehacks on how accomplish what I try to accomplish in a most friendly way and get some explanations for observed behavior.
Answer 1
If I remove the proxy_pass from the location /file/upload then error is returned by the server. (no status code in chrome debugger). Why is this happening?
Every location have a so-called content handler. If you don't specify content handler explicitly via proxy_pass (fastcgi_pass, uwsgi_pass, etc.) directive, nginx will try to serve the request locally.
Shouldn't request be propagated further to location /?
Of course not. What makes you think it should?
Answer 2
Why is it not possible to define the sublocation with body size override inside the / location as in commented section in example above? If I set it like this, then 413 error code is returned, which hints that the client_max_body_size rule is ignored..
I'd rather expect you'll get the same error as in the first case since your nested location does not have an explicitly specified content handler via the proxy_pass directive. However the following config is worth to try:
location / {
# all the common configuration
location /file/upload {
client_max_body_size 100M;
proxy_pass http://localhost:90;
}
proxy_pass http://localhost:90;
}
Answer 3
Finally, is it possible to tell nginx, after the request hits the /file/upload location - to apply all the rules from the / section?
No, unless you use a separate file via include directive in both locations. However you can try to move all the upstream related setup directives one level up to the server context:
server {
...
# all the common configuration
location / {
proxy_pass http://localhost:90;
}
location /file/upload {
client_max_body_size 100M;
proxy_pass http://localhost:90;
}
}
Note that some directives (e.g. add_header, proxy_set_header) are inherited from the previous configuration level if and only if there are no those directives defined on the current level.
Very often dynamic settings for different locations can be achieved using the map block in a following way:
map $uri $max_body_size {
~^/file/upload 100M;
default 50k;
}
server {
location / {
...
client_max_body_size $max_body_size;
...
}
}
Unfortunally not every nginx directive accepts variable as its argument. Usually when nginx documentation doesn't explicitly states that some directive can accept variables, it means it cannot, and the client_max_body_size is exactly that kind of directive, so the above configuration won't work.

Nginx upstream failure configuration file

I'm trying to start up my node service on my nginx webserver but I keep getting this error when I try to do nginx -t
nginx: [emerg] "upstream" directive is not allowed here in /etc/nginx/nginx.conf:3
nginx: configuration file /etc/nginx/nginx.conf test failed
My current nginx.conf is like this:
upstream backend {
server 127.0.0.1:5555;
}
map $sent_http_content_type $charset {
~^text/ utf-8;
}
server {
listen 80;
listen [::]:80;
server_name mywebsite.com;
server_tokens off;
client_max_body_size 100M; # Change this to the max file size you want to allow
charset $charset;
charset_types *;
# Uncomment if you are running behind CloudFlare.
# This requires NGINX compiled from source with:
# --with-http_realip_module
#include /path/to/real-ip-from-cf;
location / {
add_header Access-Control-Allow-Origin *;
root /path/to/your/uploads/folder;
try_files $uri #proxy;
}
location #proxy {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://backend;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
I tried to look up some solutions but nothing seem to work for my situation.
Edit: Yes, I did edit the paths and placeholders properly.
tldr; The upstream directive must be embedded inside an http block.
nginx configuration files usually have events and http blocks at the top-most level, and then server, upstream, and other directives nested inside http. Something like this:
events {
worker_connections 768;
}
http {
upstream foo {
server localhost:8000;
}
server {
listen 80;
...
}
}
Sometimes, instead of nesting the server block explicitly, the configuration is spread across multiple files and the include directive is used to "merge" them all together:
http {
include /etc/nginx/sites-enabled/*;
}
Your config doesn't show us an enclosing http block, so you are most likely running nginx -t against a partial config. You should either a) add those enclosing blocks to your config, or b) rename this file and issue an include for it within your main nginx.conf to pull everything together.

nginx proxy config not forwarding requests to backend server

Below is the relevant section of my nginx.conf file.
I only see the js|css... requests forward to my backend server when i remove the initial location block in the conf file. What im trying to accomplish is to turn off nginx access logging for files of those extensions.
Anybody know a working nginx config technique to allow me to turn off the access logs yet still forward these requests to the proxy location?
...
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
access_log off;
}
location / {
if ($ignore_ua) {
access_log off;
return 200;
}
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:7777/;
}
nginx chooses a location block to process a request. In the case of .js files, your location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ block is used. None of the directives within the location / block are involved. See this document for details.
If you need conditional logging, you could use the if= parameter to the access_log directive instead of a separate location block. See this document for an example.
In your case, it might look like this:
map $request_uri $loggable {
default 1;
\.(js|css|png|jpg|jpeg|gif|ico)(\?|$) 0;
}
access_log /path/to/access.log combined if=$loggable;
Note that the map directive goes in the http block.

Merging two location blocks in nginx

I want to merge 2 location blocks in my nginx so that i can prevent unnecessary copy pasting and duplication
Take the following block for example
location ~ \.php$ {
....
}
and
location ~ ^/somedirectory/(.+\.php)$ {
....
}
Here both location blocks contain exact data
How can i modify
location ~ \.php$ {
so that its works even for subdirectories
I think regex should be use here?
Can anyone guide me please
Regards
to avoid nginx duplication in location blocks either use nginx includes OR use nested location blocks - A nested location block example follows ...
location / {
proxy_pass http://mywebfeservers;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_host;
proxy_set_header X-Request-ID $uuid;
proxy_set_header Via $via;
location /aaa {
# proxy_pass is not inherited, unsure about proxy_http_version
proxy_pass http://mywebfeservers;
proxy_http_version 1.1;
# Prevent caching
if_modified_since off;
}
}
Here all locations have these various headers set. Only the /aaa location prevents caching however BUT it still uses the same headers without repeating the config. Sadly, you DO HAVE TO repeat proxy pass since inheritance does not work with the proxy pass directive (for reasons of which I am unaware).

nginx subdomain to directory , too many redirect , why?

this is my config:
server {
listen 80;
server_name ~^(?<sb>.+)\.a\.b\.c\.com$;
access_log /data/logs/nginx/tas.access.log main;
location / {
proxy_intercept_errors on;
proxy_pass http://b.c/a/$sb/;
proxy_set_header Host $host;
proxy_redirect off;
}
}
and browser report to many redirects.
If, as you say, you want to proxy to localhost:8082, you need to say so in the proxy_pass line:
server {
listen 80;
server_name ~^(?<sb>.+)\.a\.b\.c\.com$;
access_log /data/logs/nginx/tas.access.log main;
location / {
proxy_intercept_errors on;
proxy_pass http://localhost:8082/a/$sb/;
proxy_set_header Host $host;
proxy_redirect off;
}
}
Without all of the information, it's hard to guess what's going on. Based on the comments, my guess is that you are using virtual hosting so that the upstream site is also served by the same nginx. So this line is the problem:
proxy_set_header Host $host;
The nginx variable $host is pointing to the current Host header (which matches the server_name). So if you set the same host header for the upstream again, then nginx will find the same location block above because nginx relies on the Host header to find the proper server. Thus the redirect loop.
Set
proxy_set_header Host your_upstream_server_name
will fix it then.

Resources