how to deploy an express/react to apache - reactjs

I have a project that has a react app inside the express server. I would like to deploy it to my own CentOS/Apache server. How i can i do this? I've done some google and seen AWS things, and i just doesn't seem like it needs to be that complicated. I really just want it to run on my server so i can show other people and do testing. I do have a spare computer to create another nginx server if needed (or whatever else you guys reccomend).
Ive also added this code to my server.js file. which aparently isnt enough. Thanks for all help!
if(process.env.NODE_ENV === 'production'){
//SET STATIC FOLDER
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(_dirname, 'client', 'build', 'index.html'));
})
}

Related

Page reload or pasting url gives 404 with MERN stack

I am building a simple website that uses MERN stack running on apache.
There is a proxy (& reverse proxy) settings on /api to route to ip:port/api
At some point in the last couple of months, any page refresh or pasting urls causes a 404. I cannot identify what causes this.
It is using client side routing (based and it was working. It is still working on localhost only breaks on the server.
Now when I put the old code that used to work on the server, it breaks the same way. This suggests that a change in the environment is causing/contributing.
One developer I was working added this piece of code to try to address it.
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use(express.static("client/build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
It doesn't seem to have any effect even if I remove the if condition. I did a little test.
I added an image with name 'register'
If I go to my website and click on register it works
If I visit domain/register, it is showing the image, so even with the code snippet above it is treating it as a request for static file and not letting it pass on and resolve to the index.html
About the server
Ubuntu with Apache with proxy on /api to node server
Uses a self signed certificate but it breaks on http or https.
This seems to be a common problem. If anyone has seen this before or can give pointers on where to debug this, I would appreciate it.
Trying this code worked for me. And refer this for the difference between path.resolve and path.join
if (process.env.NODE_ENV === 'production') {
const root = path.join(__dirname, 'client', 'build');
app.use(express.static(root));
app.get('*', (req, res) => {
res.sendFile('index.html', { root });
})
}

live reload when running express with CRA

I have my create react app setup similar to this setup. https://www.newline.co/fullstack-react/articles/using-create-react-app-with-a-server/
All is working great so far.
when I'm running on localhost:3000 i'm seeing hot reloading as CRA dev server is taking care of that for me.
Now when I run my app using my express server localhost:8081 i'm loading my html file and assets from CRA build folder which obviously means I'm only going to get the built files.
What i'd like to do is when running in port localhost:8081 I can get a reload of development changed files and not just the static build files.
The reason for this is let's say I'm using an authentication setup where I need to check if user is logged in before I allow the * route to proceed otherwise redirect to another route in express. I want to be able to check for this when working in development.
If I run the dev server localhost:3000 then I no longer get the route change loading my html files from express. Only the api call would work from express.
Here is my setup in express:
const express = require("express");
const path = require("path");
const PORT = process.env.PORT || "8081";
const app = express();
const indexPath = path.join(__dirname, "../build/index.html");
app.use(express.static(path.resolve(__dirname, "../build"), { index: false }));
app.get("/test", (req, res) => {
res.json({ message: "welcome to backend" });
});
app.get("*", (req, res) => {
console.log("sending index.html");
res.sendFile(indexPath);
});
app.listen(PORT, () => console.log(`listing on port ${PORT}`));
This express route will only work when using in localhost:8081 which is getting the build files.
app.get("*", (req, res) => {
console.log("sending index.html");
res.sendFile(indexPath);
});
But this never runs when working in dev server localhost:3000 so I can not do any authentication on this route when working in development mode. This would mean to test this I would have to keep rebuilding the build folder which is crazy.
I'm running my client in one terminal and my server in another. I also restarted both multiple times. The proxy as I said works in my package file for the /test route when called using fetch .
This a similar unanswered question I found:
create-react-app + nodejs (express) server

Shopify App Proxy - How to include my asset files in the request response | React / JS / Heroku

I'm building a Shopify App with React & Express, deployed via Heroku, which I'm trying to embed into my storefront using an Application Proxy.
When I finally load the proxied URL on my store - I get a blank screen and a bunch of 404's in the console for my .css and .js chunk files. The request was sent, authenticated, and my API's response is (200) - it just won't render anything.
Finally, after much research, I realized that Shopify has changed the path to these CSS and JS files to be my-store.myshopify.com/hash.chunk.js etc. instead of the reference to my Heroku server.
It appears this problem has been encountered before in this thread: Shopify app - how to include assets using an app-proxy with ruby on rails However, I can't seem to find a node/react/heroku equivalent to the Ruby solution presented here.
Any guidance or help would be greatly appreciated!
I begin by serving my React App through express with:
app.use(express.static(path.join(__dirname, 'client/build')));
and then when my proxy URL is hit I send back the index file within the client/build folder:
router.get('/proxy', (req, res) => {
res.set('Content-Type', 'application/liquid').sendFile(path.join(__dirname, '../client/build/index.html'));
});
I've managed to find a working solution to my problem after much trial and error.
The homepage in package.json is important. I had it set to just my Heroku address when it should actually be set to herokuaddress.com/YOURPROXYROUTE (i.e. /app/my-app)
Some additional middleware is required as well - for those interested I have the following routes set up to field requests from Shopify's app proxy.
This is set up above any of my route imports in server.js:
app.use(express.static(path.join(__dirname, 'client/build')));
and these routes are imported below that from a /shopify-routes.js file:
router.get('/proxy', (req, res) => {
res.set('Content-Type', 'application/liquid').sendFile(path.join(__dirname, '../client/build/index.html'));
});
router.get('/proxy/static/css/:file', (req, res) => {
res.set('Content-Type', 'text/css').sendFile(path.join(__dirname, `../client/build/static/css/${req.params.file}`));
});
router.get('/proxy/static/js/:file', (req, res) => {
res.set('Content-Type', 'text/javascript').sendFile(path.join(__dirname, `../client/build/static/js/${req.params.file}`));
});
Though this may be a bit heavy-handed, it has solved the problem and the app is loading within the Shopify storefront now.

Simple password-protection for React app on Heroku

I have a simple React app, created with create-react-app, that I'd like to deploy to Heroku (or somewhere easy) and password-protect. The protection can be really simple—just a single password is fine.
I started looking into HTTP basic auth but didn't find an easy answer. The closest I found was in this post, but (a) I don't love the idea of having to eject my app, and (b) I couldn't get it working. I was hoping I could find a Heroku plugin, but no luck there either.
It wouldn't be too hard to write a component that wraps my app and requests a password before showing it. The problem is that it executes client-side. I want to store the correct password server-side (or a hash thereof), and have the app send password attempts up to the server.
Since create-react-app operates on top of Node, I'm hoping there's an easy way to tell it to execute and store certain things on the server, but maybe I'm wrong. Any suggestions?
This create-react-app buildpack seems to support http basic auth:
https://github.com/substantial/create-react-app-buildpack
https://elements.heroku.com/buildpacks/substantial/heroku-buildpack-static
I am assuming your intentions are wanting to protect the config vars in heroku so other people cannot access you database with your credentials.
The way I password protected my deployment to heroku, is to make a keys_prod.js file containing the Heroku config vars of my mLab database in my backend using express and mongoDB:
keys_prod.js file:
module.exports = {
mongoURI: process.env.MONGO_URI,
secretOrKey: process.env.SECRET_OR_KEY
};
keys.js file:
if (process.env.NODE_ENV === 'production') {
module.exports = require('./keys_prod');
} else {
module.exports = require('./keys_dev');
}
in my server.js file I added:
// DB Config
const db = require('./config/keys').mongoURI;
// Server static assets if in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
This allows you to request the config vars you filled in heroku without including it in your repo.
If you use Node in backend you can use Passport Basic Auth
app.get('*', passport.authenticate('basic', { session: false }), (req, res) => {
res.sendFile(path.join(`${__dirname}/../build/index.html`))
})
Every time you access the page in browser, a popup will appear, asking you username and password.

adding ssl to my react-app to my heroku server

I am trying to add ssl to my heroku server using certbot.
However, the issue I am finding is that I need to create a url to verify my domain -- which is the issue as I cannot seem to add both my server code as well as my client side code to the same heroku server (and get them to both run at the same time which I need to verify the domain..)
Try this:
Begin a certbot manual certificate: sudo certbot certonly --manual
Follow the prompts until you get to the part that says to make a file available at a specific like like yourdomain.tld/.well-known/acme-challenge/longstring123 Do not press Enter to Continue! Take note of both the URL and the "file" data it gives you.
In your server.js, add something like the following:
app.get('/.well-known/acme-challenge/your-long-url-string', function(req, res) {
res.status(200);
res.send('your-long-verification-file-data');
});
Make sure that this Express route handler is above the one you use for React.
I had a similar problem and spent hours trying to figure this out today. My problem was I kept getting a 404 error when trying to access .well-known/acme-challenge/{verification_file}.
The problem wasn't React or Heroku, the problem was that I was using serve -s build (package serve-handler) to serve my app, this is an static server and it won't let you fetch files without an extension. There might be a way to configure it, but I don't know how. Maybe setting headers... Anyhow, I tried files with .txt and it works, but without an extension it redirects to 404.
So instead removed my static server and added ExpressJS to serve the app instead.
To accomplish this:
Step 1
In your project folder run:
npm i express path
Step 2
Create a file in your project folder called server.js and add this code to it. This code will initialize and serve your project.
const express = require("express");
const path = require("path");
const app = express();
app.use(express.static(path.join(__dirname, "build")));
app.get("/*", function (req, res) {
res.sendFile(path.join(__dirname, "build", "index.html"));
});
app.listen(process.env.PORT || 80);
Step 3
If your package.json file under scripts make sure Heroku will initialize your project correctly when deployed:
"scripts": {
...
"start": "node server.js",
...
}
This should do it. Now your project is served by a dynamic server and it will delivery files without an extension. You can remove your serve package now if you aren't going to use it anymore.
Reading
Couple links that might be useful:
https://create-react-app.dev/docs/deployment/
https://expressjs.com/en/starter/hello-world.html

Resources