Cant access sub paths on Nginx + React router behind a proxy - reactjs

I have an nginx server with a local web app running locally in port 4000. I was able to create the Nginx rules to have it loaded trough the proxy, but now I can only access the website trough the main url, like "https://app.domain.com" (this works well), if I try entering trough any link like "https://app.domain.com/page" I get a 404.
This is my current nginx config;
server {
# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
# SSL configuration
listen 443;
listen [::]:443;
expires $expires;
ssl on;
ssl_certificate /etc/ssl/app.crt;
ssl_certificate_key /etc/ssl/app.key;
index index.html;
server_name app.domain.com;
proxy_intercept_errors on;
autoindex off;
root /var/www/domain-app;
# I am using this rule to allow files like icons or css to be accessed directly
location ~ ^.+\..+$ {
proxy_set_header Host $host;
proxy_pass http://localhost:4000;
proxy_redirect off;
if (!-e $request_filename){
rewrite https://$server_name break;
}
try_files $uri /index.html;
}
location / {
proxy_set_header Host $host;
proxy_pass http://localhost:4000;
proxy_redirect off;
try_files $uri /index.html;
}
}
I tried something like this on the location and it worked for root domain and for pages, but accessing the site from a sub-page like "https://app.domain.com/page/sub" failed; It loaded the page but it tried to find the assets under "https://app.domain.com/page/static/..."
location / {
proxy_set_header Host $host;
proxy_pass http://localhost:3000;
proxy_redirect off;
set $fallback_file /index.html;
if ($http_accept !~ text/html) {
set $fallback_file /null;
}
try_files $uri $fallback_file;
}

Alright, for anyone coming here I found the solution after some hours of research;
The problem was not my nginx config after all, but rather a Create React App/react-router thing.
In order for the URI of the assets to be properly replaced in all sub-paths by the application (NOT the server) your homepage in package.json needs to match the URL of your internal server/Proxy, so for example I was hosting the proxy locally at "http://localhost:4000" then that should also be the "homepage" attribute in package.json, differently from what other tutorials suggest of using just "./", since this is not a single page app.
Chhers!

Related

Nginx does not want to give me the .tsx file as an application/x-javascript, instead he gives application/octet-stream

I have a dockerized React application that is built via Vite. I wish I could develop it on my own separate development domain. But apparently Nginx does not allow me to do this. And I'm getting the error with my main.tsx file "Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec."
nginx reverse-proxy conf
server {
# Listen to port 443 on both IPv4 and IPv6.
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
# Load the certificate files.
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# Load the Diffie-Hellman parameter.
ssl_dhparam /etc/letsencrypt/dhparams/dhparam.pem;
proxy_http_version 1.1;
location / {
resolver 127.0.0.11;
set $upstream http://example_front-app:80;
# nginx will now start if host is not reachable
proxy_pass $upstream;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
nginx configuration inside the container
server {
listen 80;
server_name example.com;
root /var/www;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ =404;
}
}
Please don't suggest that I compile files into a js extension and output them this way, I know it works. But I need hot development with ESNext

How to set up nginx config for a React.js app deployed on AWS ECS with path-based routing load balancer

I have an application which consists of two containers:
a backend node.js server on express.js, referred to as 'app-server'
a front-end react.js client based on create-react-app, referred to as 'app-client'. This one uses an nginx server to set up reverse proxy for /api requests to the application - like this post describes
Both are dockerized and deployed on AWS ECS Fargate and are supposed to be hosted on the same domain example.com, just different paths, respectively /app-server and app-client. So the users would access the app via https://example.com/app-client. In the future we would like to host more apps on the same domain using path based routing.
To achieve that we have defined a rule on the Application Load Balancer listener on EC2 which looks like this:
IF
- Path is: /app-client*
- Host is: example.com
THEN
- Forward to
- app-client-service-alb-h: 1 (100%)
- Group-level stickiness: Off
Also tested - Path is: /app-client, without the * at the end.
I managed to adjust the backend express server to work with this scenario but I'm struggling to make the React.js app work with the path forwarding - it just shows a blank page (worked without a problem when it was hosted directly on a domain, let's say http://app-client.com).
My guess is it has something to do with the nginx config because the request URL's are correct but there are just no .html, .js and .css files there.
Dockerfile looks like this:
FROM node:11.5.0 as builder
WORKDIR /usr/src/app
ADD ./ /usr/src/app
RUN npm install && \
npm run build
# ------------------------------------------------------
# Production Build
# ------------------------------------------------------
FROM nginx:1.16.0-alpine
COPY --from=builder /usr/src/app/build/ /usr/share/nginx/html
RUN rm -rf /etc/nginx/conf.d
COPY conf /etc/nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Nginx config is set up this way:
server {
listen 80;
server_name example.com;
location /api {
proxy_pass https://example.com/app-server;
proxy_pass_request_headers on;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
React app's package.json file was adjusted by adding homepage setting:
"homepage": "/app-client"
Also tried with "homepage": "https://example.com/app-client". In both scenarios requested paths look correct, for example:
https://example.com/app-client/static/js/main.32859df6.chunk.js
The problem is that there is nothing found under this address, the page is blank. That's why I am assuming that nginx config needs to be adjusted to provide the file from correct location but have no idea what to adjust (I did also test removing the "homepage" from package.json but that also didn't solve it.).
I tried changing the location to location /app-client { or location ^~ /app-client { but that didn't work:
location /app-client {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
I blindly followed many other solutions, for example:
Nginx Meets Amazon ECS: Hosting Multiple Back-End Services Using a Single Load Balancer
Based on this config
None of them fixed the problem and I'm a rookie in that area so I'm stuck... Please help :(
------- Edited -------
The issue is solved and I'm posting the answer in case someone else finds it helpful.
The Nginx config should look like this, with appropriate rewrite defined:
server {
listen 80;
# All files should be at this directory; put it above location, otherwise it was looking in a wrong directory somewhere in `/etc/...`
root /usr/share/nginx/html;
# Prefix app-client -> rewrite
location /app-client {
rewrite ^/app-client(?:/(.*))?$ /$1;
}
# proxy for backend server /api requests
location /api {
# the ending `/api` part depends on whether your server routes also start with `/api` or not, mine do hence it was required
proxy_pass https://example.com/app-server/api;
proxy_pass_request_headers on;
}
location / {
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
The issue is solved and I'm posting the answer in case someone else finds it helpful.
The Nginx config should look like this, with appropriate rewrite defined:
server {
listen 80;
# All files should be at this directory; put it above location, otherwise it was looking in a wrong directory somewhere in `/etc/...`
root /usr/share/nginx/html;
# Prefix app-client -> rewrite
location /app-client {
rewrite ^/app-client(?:/(.*))?$ /$1;
}
# proxy for backend server /api requests
location /api {
# the ending `/api` part depends on whether your server routes also start with `/api` or not, mine do hence it was required
proxy_pass https://example.com/app-server/api;
proxy_pass_request_headers on;
}
location / {
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
Here is an example of my microservices application hosted on AWS with ALB & ECS.
ECS has multiple backend services, react app static files being served from frontend container service which is NGINX reverse proxy.
NGINX_ALB is the ALB DNS name stored in env variable inside container during Dockerfile build.
Gets substituted into nginx config using:
CMD ["/bin/sh", "-c", "export NGINX_ALB && envsubst '$$NGINX_ALB' < /etc/nginx/conf.d/nginx.conf.template > /etc/nginx/conf.d/nginx.conf && nginx -g 'daemon off;'"]
upstream alb {
least_conn;
server ${NGINX_ALB}:80 max_fails=3;
}
server {
# ref https://www.veggiespam.com/bad-headers/
proxy_hide_header Server;
proxy_hide_header X-Powered-By;
proxy_hide_header X-AspNetMvc-Version;
proxy_hide_header X-AspNet-Version;
proxy_hide_header X-Drupal-Cache;
proxy_hide_header X-Drupal-Dynamic-Cache;
proxy_hide_header X-Generator;
proxy_hide_header X-Runtime;
proxy_hide_header X-Rack-Cache;
# proxy_set_headers moved to server directive allowing them to be referenced by all locations
proxy_http_version 1.1;
proxy_set_header Connection "";
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;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 300s;
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /auth/ {
proxy_pass http://alb;
proxy_redirect off;
}
location /api/sigma {
proxy_pass http://alb;
proxy_redirect off;
}
location /api/ {
proxy_pass http://alb;
proxy_redirect off;
}
location /db {
proxy_pass http://alb;
proxy_redirect off;
}
location /scheduler {
proxy_pass http://alb;
proxy_redirect off;
}
location /validator {
proxy_pass http://alb;
proxy_redirect off;
}
location /alarm/ {
proxy_pass http://alb;
proxy_redirect off;
}
location /reporter {
proxy_pass http://alb;
proxy_redirect off;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

Why can NGINX not load my react app with the right css & js files

So the issue i am facing is very frustating because is not clear to me what the problem is. I will do my best to describe it as best as i can.
I have a kubernetes cluster running in Azure. I have two components running which is a nginx ingress load balancer and a react application that is also running on a nginx server. Both services are running on their own pod. The load balancer is directing traffic to my react application via HTTPS.
Before this implementation i was exposing the react application directly to the internet. That was working good without any issue's since i am using the load balancer my react app does not work anymore.
This is the error that i am getting:
error1
error2
What the errors are saying is that the js and css files are loaded with the index.html code, so thats why my react app cannot be loaded. I tried to figure out why this is happening, but did not have any success. I also checked the files on the server and there they are not showing the content of the index.html files. They are showing the content that came out of my react build which is correct.
This is my config file for nginx:
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
The contents of my html folder:
Hope somebody can help me with this, thanks in advance and if you need more info pls let me know.
So the issue was with my nginx ingress.
This annotation was messing with the routing of my frontend application:
nginx.ingress.kubernetes.io/rewrite-target
My website is working!
Try adding try_files to your location block:
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html =404;
}
It will first look for the file in your root directory.
If it cannot find the file, it will serve your index.html file, which is what you want for a single page app.
Failing that, it will fall back to 404.
I hope this helps.
Static Block required to map static files
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name my_server_name;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_bind 127.0.0.1;
proxy_pass http://localhost:3000/;
proxy_ssl_session_reuse off;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
}
location /static/ {
root /home/myusername/my-react-app-dir/build/;
}
}

Cannot use url to navigate in react through nginx

I am serving my static file using nginx(react frontend).
I have used different urls like /login /user /home for each page.
My nginx doesn't redirect these to my index.html file.
I made some changes and now I cannot get my main page either. It returns cannot get /.
This is my nginx.conf file. I am running it on windows. My index.html is inside the build folder. How do I get my nginx to use Router and Link in reactjs, so that I can get the page by referring to the link or through navigation bar?
worker_processes 5;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name ip;
location / {
root /Users/username/projectfolder/build;
index index.html index.htm;
try_files $uri $uri/ index.html;
proxy_pass http://ipaddress:portnumber;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
}
UPDATE:
I have tried the following configuration
server {
listen some_port;
server_name some_ip;
root C:\\nginx-1.17.1\\build\\;
index index.html index.htm;
location /test/ {
alias C:\\nginx-1.17.1\\build\\;
index index.html index.htm;
try_files $uri \\index.html;
#internal;
#return index;
}
location = /index.html {
# no try_files here
return 502;
}
location / {
#root C:\\Users\\DEV-a0a02yc\\insurance_automation\\build;
try_files $uri $uri\ \index.html?$args;
#try_files $uri/ index.html;
proxy_pass http://some_ip:some_port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
In the /test/ url I am getting a blank page and a rewrite/internal redirection error saying :
2019/07/01 09:53:22 [error] 17820#18008: *1 rewrite or internal redirection cycle while internally redirecting to "/favicon.ico\ \index.html\ \index.html\ \index.html\ \index.html\ \index.html\ \index.html\ \index.html\ \index.html\ \index.html\ \index.html\ \index.html"
This is my network tab:
How do I serve my index.html file here to handle redirection when entering this url?
What are the proxy lines for in your configuration?
Shouldn't you either serve from html files or proxy pass to a different address?
I would suggest trying to remove the proxy lines from the configuration.
Also on an unrelated note the proxy_pass line is invalid. The server address "ipaddress" is a far stretch (though not impossible with dns) and the port "portnumber" is definitely invalid.
So the minimum required configuration is the following:
location / {
root /folder/subfolder/build;
try_files $uri /index.html;
}
root defines your react build folder location and try_files defines that nginx should look if the requested file exists, if not it serves the index.html.

nginx config for react Single Page Apps (SPA) hosted on s3 not working

I am trying to get nginx with single page apps hosted on s3 folders to work. For master pushes we use the regular cloudfront, s3 and route 53. But for branch deployments we do not want cloudfront for each developer. So what we do is push the assets to s3 bucket my.example.com/branch-name/ and we create a route 53 A record - branch-name.my.example.com which points to the nginx server.
Here is my nginx config :
server {
listen 8443;
server_name *.my.example.com;
index index.html;
location / {
resolver 8.8.8.8;
set $bucket "my.example.com.s3-website-us-west-1.amazonaws.com";
rewrite ^([^.]*[^/])$ $1/ permanent;
# matches: branch-name
if ($host ~ ^([^.]*)\.my\.example\.com) {
set $branch $1;
proxy_pass http://$bucket/${branch}$uri;
}
try_files '' /index.html =404;
proxy_intercept_errors on;
proxy_redirect off;
proxy_set_header Host $bucket;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header x-amz-id-2;
proxy_hide_header x-amz-request-id;
}
}
The behaviour I am looking for is if I go to http://branch-name.my.example.com it should load the http://$bucket/${branch}/index.html.
If I go to http://branch-name.my.example.com/garbage-nonexistent-path/more-garbage/... it should preserve the url in the browser but still load http://$bucket/${branch}/index.html
If I go to http://branch-name.my.example.com/correct-path/ it should be routed to the correct tab in my app as react router has a component for /correct-path.
If I go to http://branch-name.my.example.com/correct-path/sdcsd/sdcsd/ it should still route to the correct page but preserve the url.
Right now the behaviour I get is I can only go to the root url i.e http://branch-name.my.example.com and I get routed to the proper index.html and then I click on tab "correct-path" on that page and the url will change accordingly http://branch-name.my.example.com/correct-path/ and its fine.
But if I try to go to http://branch-name.my.example.com/correct-path/ directly I just get the following error from s3:
404 Not Found
Code: NoSuchKey
Message: The specified key does not exist.
Key: branch-name/correct-path/index.html
RequestId: 92ADA29566570E8C9
HostId: wT4JdQrkB7KI0+Gnb4+88WNdnX0NXCHB6/KP5RxqJMozAx8z3RlC4T6uefk2LA=
An Error Occurred While Attempting to Retrieve a Custom Error Document
Code: NoSuchKey
Message: The specified key does not exist.
Key: index.html
If I go to http://branch-name.my.example.com/correct-path (note there is no ending slash), it just keeps loading indefinitely.
Please help. Thanks.
Try this config
server {
listen 80;
location = / {
proxy_pass http://bucketname-ap-southeast-2.amazonaws.com;
proxy_intercept_errors on;
error_page 404 =200 #spa-root;
}
location / {
proxy_pass http://bucketname-ap-southeast-2.amazonaws.com;
proxy_intercept_errors on;
error_page 404 =200 #spa-root;
}
location #spa-root {
proxy_pass http://bucketname-ap-southeast-2.amazonaws.com;
}
}

Resources