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

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

Related

NextJS 500 internal server error on deployed website. But build works PERFECTLY on local

Build is working perfectly on my local PC with pm2, no errors at all. Every page loads perfectly, there are no 404 or 500 errors in fetching files. It's great! This is EXACTLY how I want it to run.
But when I try and deploy this on Ubuntu with pm2 I am getting two sets of errors:
I'll put screenshots here:
https://i.imgur.com/IdnEH7r.png
Written form:
Script_app-a44cfb7405f734c3.js
Script_buildManifest.js
Script_ssgManifest.js
Script_middlewareManifest.js
(And others) all are giving me a 500 Internal Server Error no matter what I do.
Attempted Solutions
I've tried many approaches and all of them end with this error/failure when I am navigating to my deployed website.
Upload manually with filezilla.
Git clone from my repository, build on the server (no build errors) and then deploy with pm2. No errors with pm2 either! But then I am given 404/500 errors.
I've tried this in different folders, I've tried it with a host of different commands. I am completely out of ideas and I've uploaded and tried to get my files on there and install packages and more.
Nginx error?
This might be nginx error? But the nginx settings work perfectly fine for a brand new "npx create-next-app#latest" Following this exact tutorial to the letter: https://www.youtube.com/watch?v=x6ci2iCckWc&t=658s&ab_channel=DigitalCEO
My nginx file
"server {
server_name specialservername.com;
gzip on;
gzip_proxied any;
gzip_types application/javascript application/x-javascript text/css text/javascript;
gzip_comp_level 5;
gzip_buffers 16 8k;
gzip_min_length 256;
location /_next/static/ {
alias /var/www/frontend/.next/static/;
expires 365d;
access_log off;
}
#EDITS
location ~ ^/_next/static/(.*)$ {
root /.next;
try_files "/static/$1" "/server/static/o$1" #proxy_pass;
}
#END EDITS
location / {
proxy_pass http://127.0.0.1:3000; #change to 3001 for second app, but make sure second nextjs app starts on new port in packages.json "start": "next start -p 3001",
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;
add_header Access-Control-Allow-Origin *;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/specialservername.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/specialservername.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 =specialservername.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name specialservername.com;
return 404; # managed by Certbot
}"
What I was Expecting
The NextJS build to be deployed on this server no different than it is on my local machine. On my local machine it's BEAUTIFUL!
If you're seeing an "Internal Server Error" when trying to access your Next.js application on Ubuntu with nginx, it's likely that there's an issue with your configuration.
Here are a few things you can try:
Check your nginx error logs: Look in your nginx error logs (typically located in /var/log/nginx/error.log) for any error messages that might indicate what's causing the issue.
Check your Next.js logs: You should also check your Next.js logs (usually located in the .next directory of your application) for any error messages that might indicate what's causing the issue.
Check your Next.js configuration: Make sure your Next.js configuration is set up correctly for production deployment. You should make sure that your next.config.js file has the necessary settings for production deployment, such as setting target: 'server', configuring your build options, and setting your asset prefix if necessary.
Check your environment variables: Make sure any environment variables that your application depends on are set correctly on your Ubuntu server.
Check for permission: Make sure file, build files on server has enough permissions.
Also if everything from above works fine than try dockerizing your application with nginx and run on local then simply mimic the same on server(ubuntu) that would definatly give you some clue.
and lastly, don't panic. šŸ˜ƒ

CORS Errors with Cloudflare, ExpressJS and ReactJS on nginx

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.

Running Docusaurus with HTTPS=true yields ERR_SSL_PROTOCOL_ERROR

We are making a V2 Docusaurus website.
After building the website in the server, we could well use it with https. Here is a part of my_server_block.conf:
server {
listen 3001 ssl;
ssl_certificate /certs/server.crt;
ssl_certificate_key /certs/server.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:3002;
proxy_redirect off;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Ssl on;
}
}
In localhost, http works. However, we need to test https in localhost now. But https returns an error, though I started it by HTTPS=true yarn start: This site canā€™t provide a secure connection localhost sent an invalid response. ERR_SSL_PROTOCOL_ERROR:
Does anyone know what I should do to make https work in localhost?
Edit 1: I tried HTTPs=true SSL_CRT_FILE=certs/server.crt SSL_KEY_FILE=certs/server.key yarn start, https://localhost:3001 still returned the same error. Note that certs/server.crt and certs/server.crt are the files that make https work in our production server via ngnix:
server {
listen 3001 ssl;
ssl_certificate /certs/server.crt;
ssl_certificate_key /certs/server.key;
You are using Nginx, so use it for SSL offloading (your current config) and don't start https on the Docusaurus site. So user in the browser will use https, but Docusaurus will be using http.
If you start https on the Docusaurus site and you will be proxypassing with http proxy_pass http://localhost:3002;, then it is obvious problem - connection with http protocol to https endpoint. You may proxypass with https protocol proxy_pass https://localhost:3002; of course, but that may need more advance configuration. Just keep it simple and use SSL offloading in the Nginx.
There is an issue with https support on localhost in react-dev-utils#^v9.0.3, which is a dependency of docusaurus.
https://github.com/facebook/create-react-app/issues/8075
https://github.com/facebook/create-react-app/pull/8079
It is fixed in react-dev-utils#10.1.0
Docusaurus 2 uses Create React App's utils internally and you might need to specify the path to your cert and key as per the instructions here. I'm not familiar with the server config so I can't help you there.
Maybe this answer will be helpful - How can I provide a SSL certificate with create-react-app?

Config problem - Serve react app and spring boot backend with http basic-authentication behind nginx https reverse proxy orchested by docker

Him
Iā€™ve got a problem that I canā€™t solve.
When I query my springboot backend it works fine. The password is asked then when Iā€™m authenticated, I receive the answer.
But, if I first call the front-end, (the basic authentication also works) but the nginx proxy doesnā€™t forward queries to the spring-boot backend anymore.
Could you please help me to figure out whatā€™s wrong with my config. Do I have forgotten a https setting?
In fact, if I turn ssl off, then itā€™s working perfectly. And disabling basic authentication with ssl doens't solve the problem.
Thanks for help
Here are some more details:
I have a react app created with create-react-app tool.
The app call a spring-boot backend.
I use docker to run all that stuff.
I use https to prevent clear-text password of basic authentication.
I serve my app at this example name: https://myPublicHostname (on port 443)
The backend must be reachable with this name: https://myPublicHostname/rest/myapi/
Here is my deploying files structure:
WebDockerService
\-- my-react-app
\-- public
\-- src
\-- package.json
\-- default.conf
\-- Dockerfile
\-- fullchain.pem
\-- htpasswd
\-- privkey.pem
\-- my-api
\-- my-api-0.0.1-SNAPSHOT.jar
\-- Dockerfile
\-- docker-compose.yml
Here is my Docker-compose file
version: '3.1'
services:
frontendwithproxy:
build: ./my-react-app
ports:
- 80:80
- 443:443
springbootbackend:
build: ./my-api
ports:
- 8080:8080
networks:
default:
external:
name: netDev
Here is ā€œmy-react-appā€ Dockerfile to build nginx server
### STAGE 1: Build ###
FROM node:9.11.1 as build
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
ENV PATH /usr/src/app/node_modules/.bin:$PATH
COPY package.json /usr/src/app/package.json
RUN npm install --silent
RUN npm install react-scripts -g --silent
COPY . /usr/src/app
RUN npm run build
### STAGE 2: Production Environment ###
FROM nginx:1.13.12-alpine
COPY fullchain.pem /etc/nginx/fullchain.pem
COPY privkey.pem /etc/nginx/privkey.pem
COPY default.conf /etc/nginx/conf.d/default.conf
COPY htpasswd /etc/nginx/conf.d/htpasswd
COPY --from=build /usr/src/app/build /usr/share/nginx/html
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
Here is the default.conf file for nginx
server {
#To redirect http traffic to ssl
listen 80;
return 301 https://myPublicHostname$request_uri;
}
server{
listen 443 ssl;
server_name myPublicHostname;
#root containing react app files
root /usr/share/nginx/html;
#Basic authentication enabling
auth_basic "Restricted Access!";
auth_basic_user_file /etc/nginx/conf.d/htpasswd;
#SSL Settings
ssl_certificate /etc/nginx/fullchain.pem;
ssl_certificate_key /etc/nginx/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_ecdh_curve secp384r1;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA";
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
ssl_stapling on;
ssl_stapling_verify on;
#Location for springboot api
location /rest {
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forward-Proto http;
proxy_set_header X-Nginx-Proxy true;
proxy_redirect off;
proxy_pass http://192.168.1.125:8080;
}
}
Here is the Dockerfile for the springboot backend
FROM openjdk:8-jdk-alpine
COPY my-api-0.0.1-SNAPSHOT.jar /opt/my-api/my-api.jar
ENTRYPOINT ["/usr/bin/java"]
CMD ["-jar", "/opt/my-api/my-api.jar", "/opt/my-api/public","/opt/my-api/temp", "/opt/my-api/uploads"]
VOLUME ["/opt/my-api/public","/opt/my-api/temp","/opt/my-api/uploads"]
EXPOSE 8080
edit :
nginx is the only entry point. everything that enter has to achieve the basic authentication. I don't activate it on http, because I don't want to allow this potential leak. But basic authentication is not the problem, because when I deactivate it, the problem alway occures.
More surprising, backend "GET" queries that get pictures work fine. The pictures are well displayed. They work into markup and into browser url field.
But the other GET queries that return zip or other content-type doesn't work. (doesn't work as well in markup as when typed into the browser).
edit 2 :
In fact, it seems to work. Because when I use a rest client and query my resource on backend, the result is well arriving. Also if I call the backend in code winthin react app, the result arrives.
But when I call the backend with a href on a like this :
<a
href={"https://myPublicHostname/rest/my-api/getZipFile?value=1,2,3,4,5"}
target="_blank"
>
then the backend doesn't receive the get query.
So myabe some header are missing!?
When I query my springboot backend it works fine. The password is asked then when Iā€™m authenticated, I receive the answer.
If the authentication is enabled on both nginx and backend , then you will need some way so that nginx can authenticate to backend.
When the nginx tries to access the backend , the backend will timeout for authentication. Maybe the auth info is encrypted and cant be taken out.
First test it with authentication on nginx only ( with SSL ) and turn of the auth on backend.
You can also try to turn off the SSL from nginx to backend.
If the above scenario is not the case , and backend has no auth and SSL then here is one answer with nginx SSL basic auth issue:
Nginx basic auth working on http but not on https
so you first need to make sure nginx is configured to ask for password on both http and https , then do the rest of work. You can just test it first on some simple page.
Problem solved like this:
<a
href="/rest/photo/getZipFile?value=1,2,3"
target="_blank"
rel="noopener noreferrer"
download="AnyCustomFileName.zip"
>
...button
</a>
This simple attribute that changes everything :
download="AnyCustomFileName.zip"
With it, the browser add different headers, then Nginx achieve to rout it at the right destination.
Works for Edge, Chrome, Samsung internet and Firefox... but Fireforx only works in private sessions.

How to deploy create react app on digital ocean?

Anyone please explain it.
I'm struggling with this.I followed this blogpost https://www.davidmeents.com/blog/how-to-simply-deploy-a-react-app-on-digital-ocean/
But all i got default page of nginx or now after some messing around with configuration i'm getting 404 not found error.
There are two floders inside nginx 1) sites-availble 2)sites-enabled
I'm not sure which one is relevant here.
my config is like this
server {
listen 80;
server_name 139.59.25.228;
root /www/mywebsite/app/build;
rewrite ^/(.*)/$ $1 permanent;
location / {
try_files $uri index.html;
}
}
Thanks -:)
It's not so complicated, you just need to:
1/ Start your react application as usual, maybe npm start, then maybe it will open port 3000 for you (or any number)
2/ Config nginx for port 80 pointing to that localhost:3000 (or your defined port):
server {
listen 80 default_server;
server_name YOURDOMAIN.HERE;
location / {
#auth_basic "Restricted Content";
#auth_basic_user_file /home/your/basic/auth/passwd_file;
proxy_pass http://localhost:3000; #or any port number here
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;
}
}
However, in order to keep the npm start - your localhost with port 3000 server always alive, I suggest you use pm2:
sudo npm install pm2 -g
Then, change directory (cd) to your reactjs app folder: (I assume you use npm start for starting you reactjs app)
pm2 start npm -- start
(if you use kind of npm run:start to start app, then it should be: pm2 start npm -- run:start)
After that, this command will be remembered by pm2!
Useful pm2 commands:
pm2 list all
pm2 stop all
pm2 start all
pm2 delete 0
(use delete 0 to delete the first command from pm2 list with ID 0)

Resources