CORS Errors with Cloudflare, ExpressJS and ReactJS on nginx - reactjs

I am stuck on being unable to overcome CORSĀ errors after switching to domain name via Cloudflare. I just can't seem to get the backend api to use the domain name like https://www.my_domain.com/api
What I have done:
Applied nginx solution and restarted nginx
In cloudflare I updated DNS management with three A records: *, www, and <my_domain.com>
In cloudflare Always Use HTTPS is set to On
ExpressJS enabled cors library
Applied nginx solution below...
Note: I have React running on port 3000. React shows when visiting the domain name in the browser!
location /api {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
Command I used to test and restart nginx:
sudo nginx -t && sudo systemctl restart nginx
In cloudflare DNS management...
A record, Name: *, Content: <server_ip>, TTL: Auto, Proxy status: DNS only
A record, Name: <my_domain_name>, Content: <server_ip>, TTL: Auto, Proxy status: Proxied
A record, Name: www, Content: <server_ip>, TTL: Auto, Proxy status: Proxied
In cloudflare, SSL/TLS,Edge Certificates, Always Use HTTPS is set to On.
ExpressJS enabled cors library
And certainly, I have added the cors library to express like so:
const express = require("express");
const cors = require("cors");
require('dotenv').config()
const app = express();
if (process.env.NODE_ENV === 'production') {
app.use(cors({ origin: `${process.env.CLIENT_URL}` }));
}
my backend .env file:
NODE_ENV=production
CLIENT_URL=http://my_domain.com
my frontend react .env file
CLIENT_URL=/api
I noticed also that in the browser console, it shows the request is being sent as http://<server_ip>:8000/api and not https:<domain_name>/api as is expected.
Also, I just made the change to the domain name today.
Despite having these settings above, when I try to login, I see the request gets blocked due to cors error.
What could be causing the cors error?

Followed this tutorial...
https://medium.com/#nishankjaintdk/serving-a-website-on-a-registered-domain-with-https-using-nginx-and-lets-encrypt-8d482e01a682
Resulted in discovering these instructions...
https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx
Ran these commands (from the certbot instructions) in my linux terminal...
sudo snap install core; sudo snap refresh core; sudo apt-get remove certbot; sudo snap install --classic certbot; sudo ln -s /snap/bin/certbot /usr/bin/certbot; sudo certbot --nginx
There was a prompt for domain names at this point. So, I entered my domains like this...
my_domain.com www.my_domain.com
Per the instructions, I then tested the renewal (you'll need to annually renew but these will be put into cron for *hopefully autorenew)
sudo certbot renew --dry-run
The domain api worked but the react app did not show yet, indicating perhaps some issue in Cloudflare.
After, I got my website to show up in the browser like this...
Logged into Cloudflare.com
Went to the domain's SSL/TLS encryption settings
Changed it from Flexible to Full
Clicked on the Edge certificates
Turned off the HTTPS Always On
After doing all of the above, it resulted in the domain showing my react app which fully worked with the api and no CORS errors.

Related

SSL causing CORS issue when fetching data from Strapi back-end on nginx VPS

I have created a mock e-commerce store using React. The back-end is built using Strapi.
I have deployed the Strapi backend to an nginx VPS running on ubuntu.
When I attempt to fetch the data from my mock e-commerce store domain, let's call it mymockstore.com I am only able to fetch the data successfully when there is no SSL certificate.
If I fetch from http://mymockstore.com everything works as expected.
If I install an SSL certificate on my domain and attempt to fetch from https://mymockstore.com I receive a CORS issue in the console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at
https://194...**/api/products?populate=*&[filters][type][$eq]=featured.
(Reason: CORS request did not succeed). Status code: (null).
The Strapi cors middleware config file defaults to Access-Control-Allow-Origin: ['*']
My /etc/nginx/sites-available/api file currently looks like this:
server {
listen 80;
location / {
proxy_pass http://localhost:1337;
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;
}
}
It is a project on my first developer portfolio website and I'll use the work-around of removing the SSL but it would be great to figure this problem out.
Please let me know if you have any ideas on what could solve this?
Thanks in advance!

Nginx reverse proxy with JWT cookies

I've been working on a Full stack project with React, Mysql, Express and Nginx. The project is working fine locally. I'm trying to deploy this project on a GCP instance.
I'm struggling with how to handle authorization and cookies like accessToken and refreshToken with reverse proxy.
Made some changes in the Nginx configs and server at port 80.
Here is the overview :
I'm using reverse proxy method to interact with the server running at the instance with the help of PM2 module.
Nginx config :
server {
listen 80;
server_name GCP IP;
location / {
# proxy_bind 127.0.0.1;
client_max_body_size 100m;
proxy_buffers 8 16k;
proxy_buffer_size 16k;
add_header 'Access-Control-Allow-Origin' http://localhost:3000; #frontend port
add_header 'Access-Control-Allow-Credentials' 'true';
proxy_pass http://localhost:8800;
# replace port with your backend port
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $http_host;
proxy_set_header Cookie $http_cookie;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
port_in_redirect off;
}
}
So, I'm able to access the frontend with http:// GCP IP , registering a user is working with "http:// gcp_ip /api/users/addUsers" . But when it comes to check the cookies it doesn't work http:// gcp_ip /api/users/token.
Login provides accessToken and refreshToken , a route which authenticate user's token at http:// gcp_ip /api/users/token just after someone logged in . This route interacts with the cookies.
const refreshToken = req.cookies.refreshToken;
Nginx is not able to access the cookie through the frontend for authentication.

How would you enable HTTPS on a default nextjs app, Linux

When I run 'next start' on my Linux server, nextjs only seems to host on HTTP. I've installed let's encrypt but can't seem to find a way to link the certificate with the default next js server. However, I've seen that there is a solution that involves creating a server.js file to manually start up your next server but using that also inhibits nextjs's ability to use features such as server-side rendering and serverless functions. I find it hard to believe there isn't a way around this due to the mainstream use of nextjs?
If anyone has found a way around this or has any information, please share.
You need to set up nginx to route your domain to your Nextjs port. Check which port your nextjs is running. Example port 3000 is the default.
On your server, install nginx as normal. Many tutorials on the web. Once installed:
cd /etc/nginx/sites-available
nano example.com
Copy/Paste nginx setup from below
# *q is our domain, replace port 3000 with your port number
server {
listen 80;
listen [::]:80;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
location / {
proxy_pass http://localhost:3000;
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;
}
# for letsencrypt
location ~ /.well-known {
allow all;
}
}
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
nginx -t
service nginx restart
Make sure your Nextjs is running.
Install Letsencrypt as normal. Many tutorials on the web.
sudo apt update && sudo apt install certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.com
certbot certonly --standalone --preferred-challenges http -d example.com
certbot renew --dry-run

Nextjs path invoked from browser return 404 (Nextjs, NGINX)

How does the nextjs handle SEO? I am trying to render page by invoking it directly (localhost:8080/about) from the browser, but NGINX is returning 404. The link to same page embedded in the home page is working but the page can not be loaded directly using URL. Are additional configurations needed either in NGINX or Nextjs app.
Since you're using NGINX as your web server, you may want to reverse proxy to your NextJS app. https://medium.com/#deresegetachew/serving-react-spa-using-nginx-and-reverse-proxy-4e5485c814a0
React/NextJS uses port 3000 by default. Your URL in your post is pointing to port 8080. NGINX is not used by NextJS by default, so I believe a different web server is rendering your page, i.e. NGINX.
When you run the following commands on your nextjs project, you'll see the following output and it'll say what port is being served. Then try viewing that with your web browser.
$ npm install
$ npm run dev
...
[ wait ] compiling ...
[ ready ] compiled successfully - ready on http://localhost:3000
If your have a server.js in your projects top directory, or you can add one to configure which port your app will serve. https://nextjs.org/docs/old#custom-server-and-routing
If your web server has a firewall enabled, not all ports will be available.
NextJS serves the site itself and doesn't use nginx or Apache.
In your package.json file, you should have a next command in the scripts section. I normally have:
"scripts": {
"build": "next build",
"dev": "next"
}
Running yarn dev or npm run dev will bootstrap the site and allow you to connect to the site locally and see how it handles 404s and other errors.
When you deploy your site, it will be using this kind of server set-up rather than either of the servers mentioned above.
I hope that's helpful.
Could you share some configuration code?
Out of the box nextjs should display the default export react component that lives under pages/about.js or pages/about/index.js /about when hitting https://localhost:8080/about.
Next.Js has it's on server so you don't have to use another one.
Just run the command npm run dev after installing the next.js using the command prompt for running locally in you machine.
maybe you run application on port 3000 and when you want to serve on another port for example 80 or 8080, you need redirect Nginx requests to port 3000 in this way that you make redirection in Nginx's config file :
(replace server-ip with your server ip or localhost or 127.0.0.1)
location / {
proxy_pass http://<server-ip>:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
although you can run PM2 for manage and run your application on the server easily
as I saw your nginx serve nothing on 8080 port, that's why you didn't reach to your application on http://localhost:8000, so you can test with http://localhost:3000 because default port is 3000
that's all it.

How can I access my containerized create-react-app if I bind a HOST to it?

I need to bind a HOST to my React app on development so that I can proxy to other services in the cloud. Let's say the host is local.myapp.example.com.
I've been running my e2e tests by starting up a couple of containers including one with an instance of my React app and then making Puppeteer do requests to it. Up to this point, the app has been accessible through localhost just by exposing the port:
// docker-compose.e2e.yml
- ports:
- 8080:3000 # app is running on 3000 inside the container.
Now that I've bound it to the HOST above, I cannot access the app inside the container. I have updated my laptop's /etc/hosts to have:
// /etc/hosts - laptop
0.0.0.0 local.myapp.example.com
With this, it works when I run the app in my laptop, but it doesn't when I run it inside the container
What am I missing?
Update 1
If I go inside the container, I can run curl local.myapp.example.com:3000 and it works.
From the other container (the one with Puppeteer) I don't know what URL to use to hit it. Before adding the HOST I would just use the name of the docker container like http://frontend:3000, but now I don't know, as the URL doesn't work
Update 2
Here's my docker-compose file. I didn't mention it before because I didn't want to ask an overcomplicated question, but since I'm posting the docker-compose, might as well: the container is behind a reverse proxy:
version: '3'
services:
nginx:
container_name: nginx
image: nginx
depends_on:
- frontend
- backend
volumes:
- ./frontend.conf:/etc/nginx/conf.d/frontend.conf
ports:
- "9520:8080"
frontend:
container_name: frontend
build:
context: ..
dockerfile: Dockerfile.e2e
depends_on:
- backend
backend:
container_name: backend
image: my.private.registry/user/backend:latest
// reverse proxy conf
server {
listen 8080;
location /api {
proxy_pass http://backend:3000/api;
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;
}
location / {
# proxy_pass http://frontend:3000;
proxy_pass https://frontend:3000;
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;
}
}
From Chrome I used to hit http://localhost:9520. Now that I need to bind a HOST (and also I need HTTPS=true on my create-react-app), I need to hit http://local.myapp.example.com:9520 from Chrome (not sure if https need to go here?).
From within the reverse proxy container, I can do curl --insecure --header 'Host: local.myapp.example.com' https://frontend:3000 and it resolves.
From Chrome, I try to hit both http and https local.myapp.example.com:9520 but it doesn't work.
From Postman, it works if I do http://local.myapp.example.com:9520
Summary
I need to be able to hit https://local.myapp.example.com:9520 from Chrome (or Puppeteer) on my laptop, it should go to the reverse proxy container on port 8080. The reverse proxy then will proxy_pass it to the frontend container on port 3000.

Resources