Not Sure How to Start and Deploy ReactJS App on Production Server with ExpressJS - node.js

Locally, I use ExpressJS on port 3001 and then start my react app with npm start which runs the development server on port 3000. This allows me to route requests as a proxy from 3000 to 3001.
For production, I installed Ubuntu NodeJS 6.12.13 on 16.04 on a DigitalOcean Droplet and then installed Nginx and PM2.
In my Nginx default file I have set the following:
location / {
proxy_pass http://localhost: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;
}
I've moved over my Express and React setup and added the Express server to the PM2 startup. Nginx is being used as a reverse proxy server to use Express on port 3001. Here is the PM2 startup (www is the name of the server file which runs Express).
When I load my domain, I receive the Express default page:
Now I'm not sure how to start the react app, because it doesn't seem logical to start it using npm start and keep the terminal open for a production server. I need to see my React app when I visit the domain instead of the Express message.
I've found articles which mention to use npm run build but they don't explain how to then run the React app. Sorry I'm new to this, but any help would be appreciated. Thank you.

You won't run the React app because there is no such a thing :) After building your app all your files bundled in a single Javascript file. You are using start for your React app in development for development purposes.
After doing:
npm run build
you will have a build directory in your app directory. Just copy all the files and directories from this build directory to your server where your Nginx's default directory points.
If you don't want to open your regular app codes in developer tools of browsers, delete build/static/js/some_file.js.map and build/static/css/some_file.css.map before uploading your files to server. Those are source map files which are for debugging purposes. If you include them, in developer tools everyone can see you files directly. Your code actually open to world, to anybody right now but with a bundled, uglified and minified way. If you include source map files, they will be opened as they are.
This is how you run a static app. Without a backend, means here without Express, just using a web server.
But, since your question involves Express I assume you are using a backend server. So, one method is copying all your project to your server again with all backend and frontend code as you are using in development. Build your React app. But this time instead of starting both an Express server and React development server, on your server you will only run Express. Express will be the one serving your frontend. You should have already configured this in your development and done some production tests.
So, if you don't use a backend server you don't need Express or any other thing apart from a single web server. If you use a backend server then you need something like Express to serve both your backend requests (like to API's) and your React app. In addition you will need something like PM2 to run Express and optionally Express to use proxies for different apps.

Related

Running react/node on ec2 with nginx not working

I have a react and node application I'm trying to put on ec2. I have nginx installed and copied the application to root/testing-123. The application has a client folder for the react app and a server folder for the node app which uses
app.use(express.static(path.resolve(__dirname, '../client/build')));
to show the react app.
I'm trying to set it up and have it run publicly. When I go to the Public IPv4 address I get the default nginx page. How can I get it to show the application?
(Many tutorials were saying to change the sites-available/default file, but I don't have that folder, instead I have nginx.conf, but I don't know what to edit in that file.)

nginx.conf for NodeJS/React App returning 502 and 405

Trying to setup a staging environment on Amazon LINUX EC2 instance and migrate from Heroku.
My repository has two folders:
Web
API
Our frontend and backend are running on the same port in deployment
In dev, these are run on separate ports and all requests from WEB and proxied to API
(for ex. WEB runs on PORT 3000 and API runs on PORT 3001. Have a proxy set up in the package.json file in WEB/)
Currently the application deployment works like this:
Build Web/ for distribution
Copy build/ to API folder
Deploy to Heroku with web npm start
In prod, we only deploy API folder with the WEB build/
Current nginx.conf looks like this
Commented out all other attempts
Also using PM2 to run the thread like so
$ sudo pm2 bin/www
Current thread running like so:
pm2 log
This is running on PORT 3000 on the EC2 instance
Going to the public IPv4 DNS for instance brings me to the login, which it's getting from the /build folder but none of the login methods (or any API calls) are working.
502 response example
I have tried a lot of different configurations. Set up the proxy_pass to port 3000 since thats where the Node process is running.
The only response codes I get are 405 Not Allowed and 502 Bad Gateway
Please let me know if there is any other information I can provide to find the solution.
It looks like you don't have an upstream block in your configuration. Looks like you're trying to use proxy-pass to send to a named server and port instead of a defined upstream. There's is an example on this page that shows how you define the upstream and then send traffic to it. https://nginx.org/en/docs/http/ngx_http_upstream_module.html
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
server {
location / {
proxy_pass http://backend;
}
}````
Turns out there was an issue with express-sessions being stored in Postgres.
This led me to retest the connection strings and I found out that I kept receiving the following error:
connect ECONNREFUSED 127.0.0.1:5432
I did have a .env file holding the env variables and they were not being read by pm2.
So I added this line to app.js:
const path = require("path");
require('dotenv').config({ path: path.join(__dirname, '.env') });
then restarted the app with pm2 with the following command:
$ pm2 restart /bin/www --update-env

ReactDOM not rendering anything from separate js file

I used "npx create-react-app testreact" to create a react project. When testing from browser on my PC, the server returns a blank page, other than the expected words —— "Learn React".
What's happening here? how to fix it?
Cmd Sequnce
npx create-react-app testreact
npm install
npm start
Env Info
nodejs: v13.2.0
npm: 6.13.1
system: 18.04.1-Ubuntu
reverse proxy server: nginx
Code Info
repo: https://github.com/nautilusshell/testreact.git
there is folder called node_modules which was created by "npm install", I didn't put into above repo because it is too big and not necessary to upload.
by the way, actually I didn't change anything.
Err Info
visit http://52.130.83.55/image_editing
from browser I got:
the .js files whose status equal 404 all locates at http://52.130.83.55/static/js/xxx.js. This path was told by my chrome browser, but I searched my server, by command
find / -name "0.chunk.js" 2>/dev/null, only to find that there are no such files.
For example, http://52.130.83.55/static/js/0.chunk.js was not found anywhere on my server.
Nginx Config
repo: https://github.com/nautilusshell/nginx_config.git
Your nginx configuration has the following block:
location /image_editing {
proxy_set_header Host $host;
proxy_set_header x-forwarded-for $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
client_max_body_size 1000M;
proxy_pass http://image_editing;
}
This block presumably points anyone who visits [hostname]/image_editing is shown your React App, however it does not rewrite the path. This means that if you visit localhost/image_editing, the path is still /image_editing in the browser.
Any paths to assets, such as /static/js/bundle.js (note the leading slash), which is used by default by CRA, will not go to the webserver hosted by Create React App but instead will hit Nginx itself. You have no configuration to forward requests to /static to the same server as /image_editing, so all of those requests will fail.
In other words, when you visit yourdomain/image_editing, the index.html of your React app is sent back declaring that all of the assets are located at http://yourdomain/static. This request hits Nginx and Nginx correctly serves 404 because it does not know about those assets. You need to configure your React App such that it 'thinks' that the assets are actually located at http://yourdomain/image_editing/static/.
To solve this, you need to modify the publicPath property of the webpack configuration of your project. Unfortunately, this will require ejecting your Create React App configuration using npm eject.
You could also resolve this on the Nginx side using subdomains. For example, you could host your image editing app at image-editing.yourdomain.com and all of the URLs with leading slashes would resolve correctly.

NGINX setup for separate Vue Frontend and Express Backend

I am wondering about the proper nginx setup when deploying a vue frontend separately from an express backend - not separately in terms of servers or domains, but in terms of how they are served.
During development, I use npm serve in the vue directory, and to build a production build, it is generated via npm run build. The resulting dist folder should be served, and my question is how this is done when the backend is on the same server.
Let's say for the backend, express is exposing routes. Should nginx be in front of express here?
The vue front end is calling those routes, but the static files need to be served. According to the docs this can be done using serve. Is this intended for production? And then again, should nginx be in front of this?
I am wondering, because the route would then be:
Browser Request -> Nginx to Vue Frontend -> Vue Frontend -> Nginx to
Backend
Is this a suitable approach or am I misunderstanding this?
Should nginx be in front of express here?
Yes, it is a very good idea.
You have to use a distinct set of URLs for Vue and Express, so Nginx, while looking at request URL, will be able to understand what to do: give a Vue file or proxy to Express. Nginx has a variety of options how to classify incoming requests: by different hostnames, by paths, by combination of both, etc.
For example, prepend all your Express routes with /api/ path prefix. Then configure nginx like this:
This is not production ready configuration, I'm just trying to give a hint what you should look for in nginx docs
server {
listen 80;
server_name mydomainname.com;
location /api {
proxy_pass http://localhost:8000; # port that Express serves,
# better change to UNIX domain socket
}
location / {
root /vue_root/dist;
}
}

How to run Node Express server and Angular on the same port?

I am new to Node and Angular. I need to know whether is it possible to run a Node Express app serving as a backend and an Angular frontend on the same port. I followed Angular Quickstart tips on angular.io and created a Node todo application but both are running on different port which raises the issue of Cross Origin Request Blocked Issue.
To have Node.js serve the Angular app on the same port, your Angular app must be deployed under your Node's directory where the static resources are deployed. But in dev mode, it's more productive to serve your Angular bundles (so they auto-rebuild in memory as you code) from the dev server, e.g. on port 4200, while the Node server runs on another port, e.g. 8080.
To avoid cross-origin issues, you need to configure a simple proxy file in your Angular app to redirect all data requests to your Node server. For example, create a file proxy-conf.json in the root dir of your Angular project:
{
"/api": {
"target": "http://localhost:8080",
"secure": false
}
}
This will redirect all requests that have /api in the URL to your Node server, assuming that it runs on port 8080. Then start your Angular app using the following command:
ng serve --proxy-config proxy-conf.json
An HTTP request in your Angular App can look like this:
http.get('/api/products');
Of course, you need to configure the /api/products endpoint for GET requests on your Node server.
To get Angular and Express running on the same port I've always served my Angular build files by the Express app itself. You should be able to tell Express to serve static content from an Angular build directory like this:
app.use(express.static('../accounting-client/dist'));
Which would work if you had a file structure like so and were running serve.js with Node:
-accounting-server
-serve.js
-accounting-client
-dist/*
You can customize as needed by configuring the Angular build folder to be wherever you need it, or use Grunt/Gulp to move files around to the folders you prefer with a build task.
As mentioned by Yakov this isn't ideal for development since it won't work with the Angular dev server's auto-refresh.
The fact that you need to have access to your client-side project from within Express project, as spacefozzy said, is true. but you still can keep your projects separated.
To do so, you can create a symlink from your client-side project directory in your Express project directory:
// while in Express directory
ln -s ~/path/tp/client-side/build name-in-espress-dir
This way you can maintain projects isolated.

Resources