Nginx proxy_pass in docker container doesn't process static files - node.js

I have 2 services backend and frontend (nodejs) in docker that processed via nginx (also in docker).
Nginx config:
server {
listen 80;
listen 443 http2;
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
server_name example.com;
location /backend/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://backend-admin:2082/;
}
location ^~ / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://frontend-admin:8080;
}
location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|pdf|ppt|txt|bmp|rtf|ttf|svg|js)$ {
expires 2d;
add_header Cache-Control public;
}
}
I use nginx location /backend/ in order to proxy all request to example.com/backend/... to example.com:2082/... that nodejs listening.
Main problem is my static files from proxy_pass backend-admin:2082 nginx doesn't want to process.
I have path for uploaded images in my backend service /uploads/events/1.jpg if I open it like http://example.com:2082/uploads/events/1.jpg it works. But via nginx it doesn't http://example.com/backend/uploads/events/1.jpg. I think here nginx event doesn't try to reach image via proxy_pass.
Any ideas?

The reqular expression for the static files takes precedence over the /backend/ as it's longer match. The location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|pdf|ppt|txt|bmp|rtf|ttf|svg|js)$ means, match any query that ends with the listed suffixes. The .+ is the greedy part of the regex which will match anything that is written before the suffix is reached. Therefore anything that has the suffix from the list will be mathced as a longest match and sent to read from the local files, instead of sending the request to the '/backend/'.
There are multiple ways to fix this problem, depending on what you actually want to achieve. One approach is to add another location, just for the static files that are served from the container as follows:
location ~* ^/backend/.+\.(jpg|jpeg|gif|png|ico|css|pdf|ppt|txt|bmp|rtf|ttf|svg|js)$ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
rewrite ^/backend/(.*) /backend/$1 break;
proxy_pass http://backend-admin:2082;
expires 2d;
add_header Cache-Control public;
}
This fix will allow you to still have local files cached, but divert all other files that have /backend/ prefix to the container.
To better understand how the matching is done, you can use some of the online matching simulators. Here is the one I use Nginx location match tester

Related

nginx throws 404 on redirecting through proxy_pass to nodejs app

I'm serving multiple nodejs apps on a single server through pm2 and using nginx to manage reverse proxies. Right now if I use the server's ip and app port to reach the apps directly it all works fine. But if I try to navigate to my apps through the location paths set in the nginx config then I get 404 errors.
Below is my nginx default config:
upstream frontend {
server localhost:3000;
}
upstream backend {
server localhost:8000;
}
server {
listen 443 ssl;
server_name <redacted>;
ssl_certificate <redacted>.cer;
ssl_certificate_key <redacted>.key;
error page 497 301 =307 https://$host:$server_port$request_uri;
location /app/frontend {
proxy_pass http://frontend;
proxy_redirect off;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Ssl on;
}
location /api {
proxy pass http://backend;
proxy_redirect off;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Ssl on;
}
}
server {
listen 80;
server_name <redacted>;
return 301 https://$server_name$request_uri;
}
Now when I try to go to https://<server ip>:3000, the frontend loads just fine but if I go to https://<server ip>/app/frontend, I get the following 404 error:
Although the index.html loads up, it tries to find the static assets on https://<server ip>/ but rather should try to find them on https://<server ip>:3000. This is the exact behaviour that I'm trying to achieve.
What I have tried so far:
Using rewrites
Adding trailing slashes to both location path and proxy_pass
I know this can be solved by changing the app's base url or the build directory but that is not what I'm looking for.
Any help would be highly appreciated.

How do i configure nginx (and strapis) to correctly serve two strapi instances on the same server?

i want to host two small websites, both made with strapi backend and react frontend, on my server which is a digital ocean droplet.
I already configured nginx in order to work for one of the websites and everything is working correctly. I can access strapi from site1.com/dashboard and my queries point to site1.com/api/graphql. I followed some tutorials for that.
Here are the nginx files i added:
/etc/nginx/sites-available/site1.com:
server {
listen 80;
listen [::]:80;
root /var/www/site1.com/react;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name site1.com www.site1.com;
location /api/ {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://strapi;
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;
}
location /dashboard {
proxy_pass http://strapi/dashboard;
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;
}
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ /index.html;
}
}
file /etc/nginx/conf.d/upstream.conf:
upstream strapi {
server 127.0.0.1:1337;
}
What i now want to do is to deploy another website to the same server and configure nginx to serve it as well (on another domain, for example site2.com).
So i added the nginx virtual server file for the second website, copying the first one and changing the domain name and root directory.
The site 2 frontend is now working correctly and accessible on its domain.
However when i start the site 2 strapi instance it says the port 1337 is already in use (obviously, it is used by site 1 strapi instance that is running with pm2). So i changed the port in strapi config to be 1338 (is it ok?) but now i don't know what do to in nginx in order to serve the two different strapi instances on different domains.
The hostname you are using for the proxy_pass directive is the upstream name you defined in the separate config file. This is basically an indirection to one or more real backends. In your case that's the application running on port 1337 on the same machine. It could also be a list of external domains where nginx takes care to distribute the load to.
Your approach with additional virtual hosts already looks good. The frontend that already "works" under site2 is probably the old instance served under the new domain if your proxy_pass directive still points to http://strapi for site2 (which probably still resolves to `localhost:1337).
As you already mentioned, a second instance of the backend needs to run on a different port. The port number you use is not really important as you will control this with your upstream configuration. Just make sure to not use a port number below 1024 (which requires root permissions), don't conflict with other processes on the system (you will notice) and as best practice, don't use port numbers that are default for some other protocols (maybe check this list).
To fix your setup, just define a second upstream like the first one but pointing to the new url e.g. localhost:1338 and then reference this new name in the proxy_pass directive of site2.
Technically, with just one backend per upstream, you could also skip the upstream part completely and reference the URL directly in the proxy_pass directives, but using a shorthand name can also support readability of your configuration.

Nginx cache some location(static files) from another reverse proxy location

I have backend web-application working on 8081 port. It is Java spring boot application like uber-jar. So, static files placed into jar file. I have nginx as frontend. And I want to setting up cache static files on frontend. I thought what it is something like this:
proxy_cache_path /tmp levels=1:2 keys_zone=my_cache:10m max_size=10g
inactive=60m use_temp_path=off;
server {
listen 80;
server_name site.ru;
location /my_app {
proxy_pass http://127.0.0.1:8081;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ /my_app/.+\.css {
proxy_pass http://127.0.0.1:8081;
proxy_cache my_cache;
proxy_cache_valid 200 1d;
}
}
... but it is not working. I believe what I on right way, though a little bit wrong

nginx subdomain configuration example.com/blog

I've spent all day yesterday and today learning how nginx works and I got two different domains working, one with Ghost blogging platform and a static page (future NodeJS app), now I'm trying to setup the subdomain, but I'm kind of frustrated because I feel like I'm almost there but it's not working... This is my current setup:
#Main Domain
server {
listen 80;
listen [::]:80;
server_name example.com;
root /var/www/portfolio;
index index.html;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
# proxy_pass http://127.0.0.1:2222;
}
location ~ /.well-known {
allow all;
}
client_max_body_size 50m;
}
#Sub domain
server {
listen 80;
listen [::]:80;
server_name example.com/blog;
root /var/www/ghost/system/nginx-root;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:2368;
}
location ~ /.well-known {
allow all;
}
client_max_body_size 50m;
}
The idea is to create mysite.com/blog where eventually mysite would be a nodejs app, prob linking the route later will be another problem but... one at a time lol, how can I establish that subdomain?
If I separate the config file into a separate file, I would get the other domain working :/
Thanks
EDIT: I've found that with bucket in S3 on AWS I could acomplish that, but now I don't need it for what I'm doing jeje, but it's good to know.
First: it's not a subdomain, but a subfolder called blog.
If you want to run two apps where one appears in a subfolder, you could do the following
Define two upstreams / proxy pass them to different ports the
Have them in the same config file then
Have two location blocks (location / and location /blog)
Does that make sense? Otherwise one will probably shadow the other.
Note: This is not a complete answer, you probably will need to tinker a bit
As #Jonathan mentioned, from nginx's point of view this is the same site, but you need nginx to handle both locations differently.
Here's how it would look like
server {
listen 80;
listen [::]:80;
server_name example.com;
root /var/www/portfolio;
index index.html;
client_max_body_size 50m;
location / {
# your normal location settings
}
# your blog is defined here
location /blog {
root /var/www/ghost/system/nginx-root;
# You'll probably need to do a rewrite here, because a
# /blog/article needs to be passed as `/article` to the
# app server
# rewrite ^/blog/(.*) $1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:2368;
}
}
}

Nginx Proxy under multiple locations multiple server

I am trying to setup Nginx Proxy for multiple application from multiple servers.
server {
listen 80;
listen 443 ssl;
server_name 192.168.2.28;
ssl on;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
location /dashboard/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-for $remote_addr;
proxy_connect_timeout 300;
port_in_redirect off;
proxy_pass http://192.168.1.250/;
}
}
While running https://192.168.2.28/dashboard in browser I am getting the only root files i.e /favicon.png But inside subfolders like js/css are not resolving with location.
How to resolve domain with location with inside directories. I also attached the screenshot. Please, anyone, check and resolve.
Nginx SSL proxy error
if i understand your problem correctly, you want nginx to answer requests for static files directly while proxying everything else to your django-backend.
try adding this to your server config:
location /static/ {
alias /path/to/static/directory/;
}
as described in detail here
in case you want a location to represent a remote path,
nginx can rewrite requests like so:
location ~ /static/ {
rewrite (.*)/(.*) http://external.tld/static/$2;
}
more on that option here

Resources