Nginx 404 File not found error for django static files - nginx

I'm getting below error while trying to access static files files, though I'm trying to accessa static/js/main.js file, nginx is looking for static/js/main.js/index.html.. below is the error for the same.
2016/01/20 03:31:01 [error] 2410#0: *1
"/home/ubuntu/vnv/near/near/static/js/main.js/index.html" is not
found (20: Not a directory), client: 162.111.50.122, server: my.domain.com, request: "GET /static/js/main.js/ HTTP/1.1", host: "my.domain.com"
Below is my server block..
server {
listen 80;
server_name my.domain.com;
# location ~ ^/(static/.*) {
location ~ /static {
root /home/ubuntu/vnv/near/near; # near consist of static directory
}
location ~ / {
proxy_headers_hash_max_size 51200;
proxy_headers_hash_bucket_size 6400;
proxy_pass http://near_server;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Also it is appending / at the end of the URI, what could be the issue here?
Note: I've gone through most of the answers related to this, but I coudn't find proper solution for this situation.

If the request URI ends in a /, nginx will treat it as a directory and apply the indexing rules. Unless overridden, nginx looks for an index.html file.
From the error message we see that the GET request was for /static/js/main.js/. So the question is who appended the / to the request URI?
If you now look into the access log, you will see a line containing GET /static/js/main.js/ HTTP/1.1 404 which lists the HTTP response code.
If the line above contains GET /static/js/main.js HTTP/1.1 3xx then nginx added the extra /. If there is no such line, then the client asked for the wrong URL and you need to be looking for the solution to the problem elsewhere.
Unrelated to your question: Why are you using regular expression location blocks when prefix location blocks seem more appropriate?
You should probably be using:
location /static { ... }
location / { ... }
Your existing configuration is inefficient and matches URIs with /static embedded anywhere within the string, such as: /something/static.php.
See this document for location syntax and the processing rules.

Related

Nginx blatantly ignores location block even though it matches

When a user visits website.com I want the contents of the /home/user/project/frontend to be served (a single page app)
When a URL comes in that matches /assets, it should look into the /home/user/project/backend/staticfiles folder, which contains collected static files from django.
To the above effect, below is my Nginx conf
upstream backend {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name website.com www.website.com;
root /home/user/project/frontend;
index index.html index.htm;
location /assets {
root /home/user/project/backend/staticfiles;
}
location / {
try_files $uri $uri/ /index.html;
}
location ~^/(admin|api|auth|swagger|webhook) {
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://backend;
}
}
Intuitively, the above should work, right? However, when a request like website.com/assets/admin/css/base.css comes in, according to the logs, Nginx goes looking into the /home/user/project/frontend folder, which is NOT what the configuration is saying it should do.
2022/08/24 22:42:29 [error] 18946#18946: *1 open() "/home/user/project/frontend/assets/admin/css/base.css" failed (2: No such file or directory), client: xx.xx.xx.xx, server: xx.xx.xx.xx, request: "GET /assets/admin/css/base.css HTTP/1.1", host: "website.com"
On a different server, I have the EXACT same configuration, EXACT same django-react setup, EXACT nginx version, EXACT everything, yet, on this fresh installation, with the SAME configuration, Nginx is absolutely ignoring the location /assets { } block like it doesn't even exist.
Is there a typo or something somewhere? Because nginx -t also indicates the file is fine.
When I do website.com/assets/admin/css/base.css/ (note trailing forward slash), Nginx attempts THEN to look into the right folder, although it's off too.
2022/08/24 23:01:39 [error] 18946#18946: *4 "/home/user/project/backend/staticfiles/assets/admin/css/base.css/index.html" is not found (2: No such file or directory), client: xx.xx.xx.xx, server: xx.xx.xx.xx, request: "GET /assets/admin/css/base.css/ HTTP/1.1", host: "website.com"
Maybe the whole approach I'm using is buggy, unreliable and or inconsistent. Maybe there's a better approach (although as I type this, I have the EXACT same conf working as expected on another server).
Please enlighten me.
Here's an updated conf file, that I can confirm to be working on my new setup.
From this article:
The modifier ^~ in the following location block results in a case sensitive regular expression match. Therefore the URI /images or /images/logo.png will be matched but stops searching as soon as a match is found.
upstream backend {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name xx.xx.xx.xx;
root /home/user/project/frontend;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
location ^~ /assets/ {
root /home/user/project/backend;
}
location ~^/(admin|api|auth|swagger|webhook) {
...
}
}
And so with the above, when Nginx gets a request like
example.com/assets/admin/base.css, it points to the folder
/home/user/project/backend/assets/admin/base.css
Basically, it appends the location block URL to the root path.
In my django settings.py, I have these
STATIC_URL = "/assets/"
STATIC_ROOT = os.path.join(BASE_DIR, "assets")

NGINX Redirect Bad Gateway Only When a Subdirectory Is Provided

I've installed nginx on ubuntu 20.04 and set it up to do redirects. This is my conf file:
server {
listen 80 default_server;
location / {
proxy_pass http://10.0.0.185:6052;
}
location /esphome {
proxy_pass http://10.0.0.185:6502;
}
}
If I enter http://10.0.0.185 in a browser, it redirects me to the site.
If I enter http://10.0.0.185/esphome in a browser, it gives me a 502 error.
I've also tried just having the second location as the only one and still get the same error
I've tried adding ending slashes to the urls. It has no effect.
I've also tried other websites on the same server. When I tried /adguard to 10.0.0.185:8080, I got a forbidden response. When I tried /frigate to 10.0.0.185:5000, it just hung.
When I changed the entry to:
location /esphome {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded_Host $host;
proxy_set_header X-Forwarded_Port $server_port;
proxy_pass http://10.0.0.185:6052;
}
I get a 404 error. Strangely when I comment out the set header values, I still get the 404 error instead of the original 502.
Are there additional parameters that I have to add to the second location?
I have a small flock of web servers on the ubuntu image so I'd like to map to each one thus the need for a subdirectory.
You might want to try different matching types, e.g. ^~, = and so on to see if it matches your use case.
location / {
proxy_pass http://10.0.0.185:6052;
}
location ^~ /esphome {
proxy_pass http://10.0.0.185:6502;
}
You can find out more here:
https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms

Nginx set browser location root [duplicate]

I'm used to using Apache with mod_proxy_html, and am trying to achieve something similar with NGINX. The specific use case is that I have an admin UI running in Tomcat on port 8080 on a server at the root context:
http://localhost:8080/
I need to surface this on port 80, but I have other contexts on the NGINX server running on this host, so want to try and access this at:
http://localhost:80/admin/
I was hoping that the following super simple server block would do it, but it doesn't quite:
server {
listen 80;
server_name screenly.local.akana.com;
location /admin/ {
proxy_pass http://localhost:8080/;
}
}
The problem is that the returned content (html) contains URLs to scripts and style info that is all accessed at the root context, so I need to get these URLs rewritten to start with /admin/ instead of /.
How do I do this in NGINX?
We should first read the documentation on proxy_pass carefully and fully.
The URI passed to upstream server is determined based on whether "proxy_pass" directive is used with URI or not. Trailing slash in proxy_pass directive means that URI is present and equal to /. Absense of trailing slash means hat URI is absent.
Proxy_pass with URI:
location /some_dir/ {
proxy_pass http://some_server/;
}
With the above, there's the following proxy:
http:// your_server/some_dir/ some_subdir/some_file ->
http:// some_server/ some_subdir/some_file
Basically, /some_dir/ gets replaced by / to change the request path from /some_dir/some_subdir/some_file to /some_subdir/some_file.
Proxy_pass without URI:
location /some_dir/ {
proxy_pass http://some_server;
}
With the second (no trailing slash): the proxy goes like this:
http:// your_server /some_dir/some_subdir/some_file ->
http:// some_server /some_dir/some_subdir/some_file
Basically, the full original request path gets passed on without changes.
So, in your case, it seems you should just drop the trailing slash to get what you want.
Caveat
Note that automatic rewrite only works if you don't use variables in proxy_pass. If you use variables, you should do rewrite yourself:
location /some_dir/ {
rewrite /some_dir/(.*) /$1 break;
proxy_pass $upstream_server;
}
There are other cases where rewrite wouldn't work, that's why reading documentation is a must.
Edit
Reading your question again, it seems I may have missed that you just want to edit the html output.
For that, you can use the sub_filter directive. Something like ...
location /admin/ {
proxy_pass http://localhost:8080/;
sub_filter "http://your_server/" "http://your_server/admin/";
sub_filter_once off;
}
Basically, the string you want to replace and the replacement string
You may also need the following directive to be set before the first "sub_filter" for backend-servers with data compression:
proxy_set_header Accept-Encoding "";
Otherwise it may not work.
For your example it will look like:
location /admin/ {
proxy_pass http://localhost:8080/;
proxy_set_header Accept-Encoding "";
sub_filter "http://your_server/" "http://your_server/admin/";
sub_filter_once off;
}
You can use the following nginx configuration example:
upstream adminhost {
server adminhostname:8080;
}
server {
listen 80;
location ~ ^/admin/(.*)$ {
proxy_pass http://adminhost/$1$is_args$args;
proxy_redirect off;
proxy_set_header Host $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-Host $server_name;
}
}
If there are no hyperlinks which need to be rewritten with sub_filter,
you might just use the proxy_redirect directive:
location /admin/ {
proxy_pass http://localhost:8080/;
proxy_redirect / /admin/
}
It changes the Location-Header of the response according to the given 'match-rewrite' rule.

One out of three Nginx routes ignores upstream server

I have configured three locations for a nginx reverse proxy:
location / {
root /var/www/html;
index index.html;
}
location /login {
proxy_pass http://127.0.0.1:9080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /app {
rewrite ^/app/(.*)$ /$1 last;
proxy_pass https://10.11.12.13/1020/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
The server listening on port 9080 redirects to the route /app/{generated subpath}. The server on IP 10.11.12.13 processes the request on {generated subpath}. Therefore I remove the prefix path /app with a corresponding rewrite rule, then proxying the request to that server's /1020 endpoint.
For some reason, the nginx reverse proxy doesn't take the 10.11.12.13 upstream server but tries to find the path locally:
8888#8888: *470 open() "/var/www/html/html/createCustomer" failed (2: No such file or directory), client: x.x.x.x, server: 10.10.10.10, request: "GET /app/html/createCustomer?tokenId=0xC00FF3 HTTP/1.1", host: "10.10.10.10"
Instead of last I believe you are looking for break. From the rewrite documentation
last
stops processing the current set of ngx_http_rewrite_module directives and starts a search for a new location matching the changed URI;
The starts a search for a new location matching the changed URi is what is happening as you are removing the /app/ part which then matches the / location.
break
stops processing the current set

NGINX Rewriting subdomains as URL in a proxy_pass

I would like to redirect specifc subdomains of my domain to my backend as
prefixes of the URL that is passed to the backend. This is because I have a single server and I do not want to have to handle the multiple domains in the backend due to increased complexity.
Hence if I have:
sub1.domain.com => domain.com/sub1/
sub1.domain.com/pathname => domain.com/sub1/pathname
sub1.domain.com/pathname?searchquery => domain.com/pathname?searchquery
and so forth.
So far what I have come up with is the following:
server {
charset utf8;
listen 80;
server_name
domain.com,
sub1.domain.com,
sub2.domain.com,
sub3.domain.com,
sub4.domain.com,
sub5.domain.com;
# Default
if ($host ~ ^domain\.com) {
set $proxy_uri $request_uri;
}
# Rewrites
if ($host ~ (.*)\.domain\.com) {
set $proxy_uri $1$request_uri;
}
location / {
expires 1s;
proxy_pass http://node:8080$proxy_uri; #node is an internally listed host (docker container)
proxy_set_header Host domain.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache_valid 200 1s;
}
}
But unfortunately all I get is a 502: Bad Gateway with the following log, 2017/06/11 12:49:18 [error] 6#6: *2 no resolver defined to resolve node, client: 136.0.0.110, server: domain.com:8888,, request: "GET /favicon.ico HTTP/1.1", host: "sub1.domain.com:8888", referrer: "http://sub1.domain.com:8888/" Any idea how I can achieve my goal? Any help would be greatly appreciated :)
Cheers!
It seems I wasn't so far from the answer - adding an upstream block before the server block was sufficient to finalize the config to the desired effect.
upstream backend {
server node:8080;
keepalive 8;
}
I also had to slightly modify the proxy pass line to the following:
proxy_pass http://backend$proxy_uri;
The problem must likely have been one related to how NGINX parses the proxy pass urls - if anyone reading this can provide an insight into the reason, please edit this answer!

Resources