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
Related
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")
I have a web application that runs on WSGI server. The application has OpenID Connect identity provider endpoints, for instance:
/oidc/.well-known/openid-configuration
/oidc/.well-known/simple-web-discovery
/oidc/.well-known/webfinger
Requests to these endpoints are mapped to some functions in my project, which run necessary tasks for each endpoint. I can run my application, and all requests are successfully mapped and handled by the defined functions.
The challenge starts when I host my application on a public IP behind https. For this I use nginx to proxy access to my application. nginx makes my application accessible over a public IP over https. Here is key sections of my nginx config file:
server {
listen 80;
listen [::]:80 default_server;
server_name localhost;
root /home/user/myApp;
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://my_app;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-URL-SCHEME https;
}
}
server {
listen 443 ssl;
server_name localhost;
root /home/user/myApp;
ssl_certificate /home/user/cacert.pem;
ssl_certificate_key /home/user/privkey.pem;
include /etc/nginx/default.d/*.conf;
location ~ /\.well-known { allow all; }
location / {
proxy_pass http://my_app;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-URL-SCHEME https;
}
}
Every call is requested/posted correctly, except for the requests to /.well-known/* (actually location ~ /\.well-known { allow all; } in the config is an attempt to solve it), for which I get either 404 or 403 errors.
For instance, one error message in nginx error log reads:
open() "/home/user/myApp/oidc/.well-known/openid-configuration" failed (13: Permission denied), client: X.X.X.X, server: localhost, request: "GET /oidc/.well-known/openid-configuration HTTP/1.1", host: "X.X.X.X"
(IP addresses are masked out)
Few points:
I'm running my application with sudo privileges, so the application has r/w access to all the paths.
Actually, the path /home/user/myApp/oidc/.well-known/openid-configuration does not exist (and thats why I also get 404 error).
/oidc/.well-known/openid-configuration should be mapped to a function (as it happens when I host my application without nginx). So, I don't understand why nginx tries to access a non-existing /oidc/.well-known/* path/file ?!
The problem is the setting location ~ /\.well-known { allow all; }.
This should be removed. Additionally, the setting include /etc/nginx/default.d/*.conf; includes a default config file which also has the setting location ~ /\.well-known { allow all; }. This setting should be removed from that file too.
I'd like to run multiple docker containers on one host VM which would be accessible through only one domain. I wanted to use request url to differentiate between containers.
To achieve this I'm trying to set nginx server as reverse proxy and run it in the container also listening on port 80.
Let's say I have two containers running on port 3000 and 4000.
The routing would be following:
docker-host.example.com/3000 -> this will access container exposing port 3000
docker-host.example.com/4000 -> this will access container exposing port 4000
The thing is I'm currently stack even with trying to define static rule for such reverse proxy.
It works fine without any location:
upstream application {
server <docker container>:3000;
}
server {
listen 80;
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://application/;
}
}
But when I add port location and try to access it using localhost:{nginx port}/3000/
upstream application {
server <docker container>:3000;
}
server {
listen 80;
location /3000/ {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://application/3000/;
}
}
It seems that first resource (main html) is requested correctly, but any other depending resource (for example js or css needed for this site) is missing.
If I examine request for those resources I have in logs:
09:19:20 [error] 5#5: *1 open() "/etc/nginx/html/public/css/fonts.min.css" failed (2: No such file or directory), client: 172.17.0.1, server: , request: "GET /public/css/fonts.min.css HTTP/1.1", host: "localhost:8455", referrer:"http://localhost:8455/3000/"
So request url is http://localhost:8455/public/css/fonts.min.css
Instead of http://localhost:8455/3000/public/css/fonts.min.css
Could I ask you for any suggestions ? Is this scenario possible ?
You can select a docker container per port, your example:
http://example.com:4000/css/fonts.min.css
http://example.com:3000/css/fonts.min.css
But there is another approach that I like more, because I think it is clearer, access to a docker container by domain name, e.g:
http://a.example.com/css/fonts.min.css
http://b.example.com/css/fonts.min.css
Whichever you choose, there is a project in github that helps you to implement docker multi-container reverse proxy: https://github.com/jwilder/nginx-proxy
I've written an example using docker-compose for a similar scenario at: http://carlosvin.github.io/posts/reverse-proxy-multidomain-docker/
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.
I want to achieve the following:
Request Host:
http://example.com.proxy.myserver.com
Should be rewritten to
http://example.com
and passed to a squid server via nginx proxypass.
server {
listen 80;
server_name ~^(?<subdub>.*)\.proxy\.myserver\.com$;
location / {
rewrite ^ $scheme://$subdub break;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $scheme://$subdub;
proxy_set_header Request-URI $scheme://$subdub;
proxy_pass http://localhost:3128;
proxy_redirect off;
}
}
The problem is, that nginx redirects this request immediately to http://example.com
Any ideas how to get this working?
301 redirect is exactly what nginx shall do with that rewrite rule: because you put $scheme://$subdub at the replacement part, nginx will do a 301, ignoring that "break" flag.
If the replacement string begins with http:// then the client will be redirected, and any further rewrite directives are terminated.
Are you trying to "rewrite" or "redirect"? If it's just for rewrite, you can remove that rewrite directive:
rewrite ^ $scheme://$subdub break;
and it will work because your upstream server could rely on the HOST header to determine the traffic target (virtual hosting).
Also your host header sent to the upstream server is wrong. It should be
proxy_set_header Host $subdub;
$scheme should not be put in the Host header.