ReactJS with Nginx 404 Not Found when entering a specific url path - node.js

What I am trying to do is to prepare this machine to serve my web application. It works without any problems when I serve it via npm start.
I have a domain, let's say, example.com on which I installed SSL with Certbot and have successfully rerouted http to https with www.example.com and example.com.
Now what happens is when I go to www.example.com or example.com it works fine, and I can move to whatever url path I want, as long as it is directly accessed from any button on the homepage, but whenever I try to access an individual url path, let's say myexample.com/admin/login (it is hidden from the homepage) or any manually entered url path, the webserver returns error 404. This does not happen when I do the same with npm start.
I am running an EC2 machine with the following components installed:
Operating System: Ubuntu 20.04 LTS
Webserver: Nginx 1.18
Node: 10.24.1
NPM: 6.14.12
SSL Provider: Let'sEncrypt (Certbot 0.40.0)
I have the following ports open from the EC2 Management Console:
80/custom anywhere (http)
443/custom anywhere (https)
22/custom my IP (ssh)
3000/Custom my IP (npm start default port)
I have also allocated an Elastic IP to my machine, let's say it's 1.1.1.1 .
My Nginx config file is located at:
/etc/nginx/sites-enabled
and is called: client-config
I have set up my Nginx config to look like this:
server {
server_name 1.1.1.1 example.com www.example.com; # 1.1.1.1 this is an example ip
root /home/ubuntu/app-deploy/build;
index index.html; # react by default generate the file in the build directory
location / {
try_files $uri $uri/ =404;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name 1.1.1.1 example.com www.example.com; # 1.1.1.1 this is an example ip
return 404; # managed by Certbot
}
Running nginx -t returns:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Related

nginx letsencrypt https redirect with express nodejs app not working

I need https to be the default way my site is served, I chose option 2 during letsencrypt cert generation.
I have https working on my site. It is a simple HTML page being served up by nodejs on port 3000. It is hosted in Oracle Cloud currently. I have opened the ports in iptables as Oracle does not use ufw.
If I go to https://www.example.com , the site loads securely so things are working.
If I go to http://www.example.com, the site also loads but not securely obviously.
If I go to example.com, the site loads in http, not https.
I am having trouble wrapping my mind around how I should write my nginx config file.
I need to proxy_pass using http to port 3000, but when I change the proxy_pass to https
proxy_pass https://localhost:3000;
It fails to load anything and that somewhat makes sense to me because my nodejs app does not have any code to support https and I was under the impression that nginx can handle all of that for me. That line of thinking is further supported because like I said above, https://www.example.com works just fine for my site now.
Below is my config with my server name removed. Please let me know how to best do what I am trying to accomplish.
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://localhost:3000;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 404; # managed by Certbot
}```
Thank you to Marc, it seems like my config was created strangely and certbot added in things slightly out of order to where it was getting confusing but I have figured it out. Like Marc said, redirect all 80 to https. In https server, make sure you have your certificates and proxy_pass there to your port 3000, or wherever your app is running.
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.example.com;
}
server {
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
proxy_pass http://localhost:3000;
}
}

Nginx With SSL and Frontend + Backend same server

I have a server (VPS Amazon) with Ubuntu. In this server is running my backend node and my frontend React.
My ReactApp is running over nginx and my backend over pm2.
In my react app I defined REACT_APP_BASE_URL: http://[my_ip_server]:4000.
So everything was working OK but after I configured SSL in nginx, I can access my frontend login page but when I send the request, I catch the following errors:
a) If I set https in my REACT_APP_BASE_URL (https://[my_ip_server]:4000), I get this error: ERR_SSL_PROTOCOL_ERROR.
b) If I let with http, I get Mixed Content error
Someone know How I do this work?
Thanks a lot!
My nginx.conf. At moment I'm using just port 80 until I solve my problem.
server {
#listen [::]:443 ssl ipv6only=on; # managed by Certbot
#listen 443 ssl; # managed by Certbot
#ssl_certificate /etc/letsencrypt/live/mysite.com.br/fullchain.pem; # managed by Certbot
#ssl_certificate_key /etc/letsencrypt/live/mysite.com.br/privkey.pem; # managed by Certbot
#include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
#ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
#if ($host = surveys.alcancenet.com.br) {
# return 301 https://$host$request_uri;
#} # managed by Certbot
listen 80 default_server;
listen [::]:80 default_server;
server_name mysite.com.br;
#return 404; # managed by Certbot
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri /index.html;
}
}
With help from #Markido. I managed to solve that.
I added in my backend the default route "/api" and after that I put in my nginx config the following
location /api {
proxy_pass http://localhost:4000;
}
Tks!!!
First off, there is a difference between running the applications (which is what i assume you are using PS2 for), and exposing them through an nginx proxy.
It would be most helpful to show us your nginx config file, and also tell us which port your backend runs on (assuming the frontend runs on port 4000).
Edit;
Thanks for the config and backend port.
I don't think you need to set the create react app base url to https, just set the port and run it on the VPS using PS2.
I can't see how you have any proxy at all pointing to 4000 in your config - do you not expose the backend?
The only exposed part is static html files. The relevant code is;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri /index.html;
}
If you want to call the backend using https, or generate your site using some tool with a process which entails HTTPS calls, you need to do so correctly in the frontend. IE something doesn't add up here.
The usual approach is;
Expose the backend and the frontend on port 443 SSL only, using different sub-domains (eg. api.mydomain.com), and then use the proxy in nginx to redirect 443 traffic for each domain to the corresponding local ports (4000, and the frontend port or static files directory more likely).
Instead of:
location / {
try_files $uri $uri /index.html;
}
Use something like:
location / {
proxy_pass http://localhost:4000;
}

NGINX: multiple proxy pass for same domain but different ports

Here's the situation:
I have up to 500 independent localhost applications all running simultaneously on a server. My router has ports 80, 443, 8000 to 8500 open. My clients can connect to each of the different localhost applications of their choice. My task is to figure out a way to do this, using 1 domain: example.com
It would be nice if I could use a query string to tell NGINX which application to redirect to. For example, if example.com is my domain name, and I have port 443 open to connect to it, it would be nice if I could do something like:
https://example.com?port=8300
then NGINX will redirect this request to localhost:8300
if this cannot be done, another solution could be to request:
https://example.com:8300
and then NGINX will redirect this request to localhost:8300
my current setup has https://example.com on port 443 redirecting to localhost:8080(the NGINX config code:)
server {
server_name example.com;
location / {
proxy_pass http://localhost:8080/;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by
Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by
Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
} server {
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name example.com;
return 404; # managed by Certbot
}
but I need a range of proxy_pass arguments, and they need to correspond to either a query string or a domain name's port.
I found no documentation or online articles on how to do this. Thanks!

NginX : Serve static content and proxy pass to Node API

I'm running a website composed of an API in a docker on port 8080, and a static folder containing the front-end react app.
The api is at /api
I'm trying to configure NginX to correctly serve this configuration, but I can't seen to figure out how to have both working.
If I setup my default like this:
server {
root /var/www/html;
server_name DOMAIN; # managed by Certbot
location #nodeapp {
# Redirect to the api
proxy_pass http://localhost:8080;
}
location / {
# Map all the routes to the index.html
try_files $uri #nodeapp;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/DOMAIN/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/DOMAIN/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
Then everything is redirected to my API, and the static content is not delivered if not explicitly specified (e.g. going to https://host/index.html)
If I add try_files $uri $uri/ #nodeapp; to serve the root folder as a directory, the index gets served, but I can't access the API anymore, it always serve the react app
I also tried to add
location /api/ {
proxy_pass http://localhost:8080
}
But no difference
What am I doing wrong ?
I found the answer, the react app I was using was setup with a service worker, which was messing with the routing. I removed it and it works like a charm now !

Set up nginx and node apps on ubuntu

Here's the situation -
node express app1 (backend app - REST API server) - running on port 8888 -
bunch of POST routes (auth, api, download, upload..) - communicating with mysql server - maintained by developer #1
node (webpack, react) app2 (front end app) running on port 80 - maintained by developer #2
This week we set up nginx and HTTPS (via Let's encrypt), which means that when a user comes to the www.oursite.com - it is redirected to the https site with nice green lock and secure site. So far so good. However, when the user enter her email, the app2 is supposed to call app1 and email with registration token should be sent. This worked well before we try to set up nginx - and use http on both apps. Now this call is not happening. This is our nginx setting:
server {
listen 80;
listen [::]:80;
root /var/www/oursite.com/html;
index index.html index.htm index.nginx-debian.html;
server_name oursite.com www.oursite.com;
location / {
try_files $uri $uri/ =404;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/oursite.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/oursite.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
# Redirect non-https traffic to https
# if ($scheme != "https") {
# return 301 https://$host$request_uri;
# } # managed by Certbot
}
My question (developer #1) - should I replace all routes in my app (backend app - app1 - backend) to be https instead of http? Apparently Chrome is not calling http request from https site (as is our case)
and how should I setup the nginx then - I belive I should add another location part in nginx setting.
If there are other suggestions please let us know.
Each port must get its own server{ } block, so port 80 gets one and port 443 get another each with a listen directive to the respective port ... in above you have both ports in the same server{ } block
If the app is exposed to the internet they should be using https and if not their incoming traffic using http which is port 80 block must get redirected to send traffic to 443 ... so your nginx config file will look similar to
server {
listen 80 ;
listen [::]:80 ;
server_name example.com, www.example.com;
# Redirect all HTTP requests to HTTPS
rewrite ^/(.*) https://example.com/$1 permanent;
}
server {
listen 443 ssl ;
listen [::]:443 ssl ;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/oursite.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/oursite.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
# direct traffic to my server on its host IP and port
proxy_pass http://172.19.0.5:3000/; # notice http not https
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
In your case looks like app1 is not exposed to the internet and so does not appear in your nginx config ... it only receives http traffic downstream from app2 ... all of above config is only for your app2 ... incoming internet traffic using secure https port 443 (or port 80 which gets redirected to 443) receives what is called TLS termination ... apps shielded from the internet by the nginx TLS termination receive http traffic not https which is fine since the app ports are not visable from the internet ... and so your app2 gets http traffic not https
We got this to work by setting the app1 (backend up) as https as well. However, this works in all major browser, except for firefox. SO I guess I shiuld post a new question now. The site is not letting through the form on firefox - but only if the address does not have www. That means https://testsite.com -> not working, https://www.testsite.com working ok. But is working ok on all other browsers.

Resources