Node.js api not working when deploying to AWS - node.js

I have one Node.js app and the frontend is using React. When I develope it on my local, I put the project under http://localhost/app subdirectory and api is under /api, the port I use is 5000. It's all working. Here is the way I set:
For Node.js, I use this to set the Frontend directory and router:
const indexRouter = require('./routers')
app.use('/api', indexRouter) //to set API path
app.use('/app', express.static('public'))
the server is listen on 5000.
For React, I update the package.json to:
"homepage": "/app",
"proxy": "http://localhost:5000/"
and with the Axios request, I add the base varible at the beginning of the request path and set it to '/api'
This is all good on my localhost. However, when I deploy it to AWS with Nginx, I couldn't make the API request success.
With Nginx, I update the original location block from
location / {
try_files $uri $uri/ = 404;
}
to
location /app {
proxy_pass http://localhost:5000;
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;
}
When I go to /root/app, I can see the homepage of the React (I copied the React build files into the Node js public folder). However, it cannot get the request success. I can see on my localhost, the request path is http://localhost:3050/api/login, but the live sever request path is http://domain_name/login, I don't know why the server cannot go to /api for request.
I hope someone can help me for this.

Since you built the React app using yarn build, you would not be able to use the proxy that you were using in the development. That method is for testing in development only, and not in production. You can read more about it here.

Related

Failed to load resource: net::ERR_CONNECTION_REFUSED http://127.0.0.1:3000/api/categories

I have my node.js backend running on port 5000 and my react client running on port 3000 (http://localhost:3000). The react client has the following url in the package.json proxy: http://localhost:5000 (backend url)
I used to make api requests from the client to the backend using axios at baseurl http://localhost:3000. The proxy performed its function and there were no problems with cors.
On the backend in app.js there is the following block of code:
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000')
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE')
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization')
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true)
// Pass to next layer of middleware
next()
})
Now I decided to move my site to a VPS server. I installed nginx there and this is what I wrote in /etc/nginx/sites-available/default in the location block.
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
proxy_pass http://localhost:3000; #whatever port your app runs on
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;
}
With pm2 I ran my node.js backend and react client. They are running on the same ports as before.
My server is now available at my-site.com for example. When you go to the url it opens my client. So far everything is going as it should. However, when my client accesses my backend I get an error like this:
GET http://127.0.0.1:3000/api/categories net::ERR_CONNECTION_REFUSED
Can you tell me how to fix it and make my api requests to be executed?
Your React proxy is probably not running on the VPS. Either way, it would be better to use Nginx instead, as the React proxy is designed for development use only.
You can configure Nginx to forward requests for the /api path to the Node.js app the same way as you configured the root path for the React app.
location /api {
proxy_pass http://localhost:5000;
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;
}

How do I connect Vue application to server (Node, MongoDB)?

I've been learning frontend development only and just recently went over basics of Nodejs. I know that I would connect to certain port number when developing in Nodejs alone. However, I'm confused about how I would connect Vue application (built with Vue CLI) to backend since npm run serve will automatically connect to port 8080 by default.
My ultimate goal is to connect MongoDB to my application. Current error I'm getting is Error: Can't resolve 'dns'.
TLDR: Could someone please explain in newbie term how I can connect Vue application with MongoDB?
In my opinion, you have two ways of solving this:
First, there is a field called devServer through which you can tweak the configuration of the dev server that starts up when you run npm run serve. Specifically, you want to pay attention to proxy field, using which you can ask the dev server to route certain requests to your node backend.
Second, depending on your setup, you could use a different host altogether to handle backend calls. For example, as you mentioned, the dev server runs on 8080 by default. You could set up your node backend to run on, say, 8081 and all backend requests that you make in your VueJS app will explicitly use the host of <host>:8081. When you decide to move your code into production, and get SSL certificates, you can have a reverse-proxy server like Nginx redirect all requests from say, api.example.com to port 8081.
As for connections to MongoDB, IMO, here's a question you should be asking yourself:
Is it safe to provide clients direct access to the database?
If the answer is yes, then by all means, ensure the mongoDB server starts with its HTTP interface enabled, set up some access restrictions, update the proxy and/or nginx and you're good to go.
If the answer is no, then you're going to have to write light-weight API endpoints in your NodeJS app. For example, instead of allowing users to directly talk to the database to get their list of privileges, you instead make a request to your NodeJS app via GET /api/privileges, and your NodeJS app will in turn communicate with your database to get this data and return it to the client.
Another added benefit to having the backend talk to your database rather than the client, is that your database instance's details are never exposed to malicious clients.
Here's a sample vue.config.js setup that I have on one of my websites:
const proxyPath = 'https://api.example.com'
module.exports = {
devServer: {
port: 8115, // Change the port from 8080
public: 'dev.example.com',
proxy: {
'/api/': {
target: proxyPath
},
'/auth/': {
target: proxyPath
},
'/socket.io': {
target: proxyPath,
ws: true
},
'^/websocket': {
target: proxyPath,
ws: true
}
}
}
}
Here's the nginx config for the same dev server. I quickly pulled what I could from our production config and obscured certain fields for safety. Consider this as pseudo-code (pseudo-config?).
server {
listen 443 ssl;
server_name dev.example.com;
root "/home/www/workspace/app-dev";
set $APP_PORT "8115";
location / {
# Don't allow robots to access the dev server
if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|Googlebot") {
return 404;
}
# Redirect all requests to the vue dev server #localhost:$APP_PORT
proxy_pass $scheme://127.0.0.1:$APP_PORT$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 443 ssl;
server_name api.example.com;
set $APP_PORT "8240";
location / {
# Don't allow robots to access the dev server
if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|Googlebot") {
return 404;
}
# Redirect all requests to NodeJS backend #localhost:$APP_PORT
proxy_pass $scheme://127.0.0.1:$APP_PORT$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

Host Angular application on raspberry pi using nginx, socket.io and nodejs

I can't find a configuration to make this work. I want to host an angular app (a board game) and a nodejs server (which communicates with the board game) on a raspberry pi via nginx (also already tried apache).
I start to get the feeling it's not a problem with the nginx configuration, but something fundamental I am missing.
Working:
Running the Angular app (via ng serve) and the nodejs server (via
ts-node ./src/app.ts) locally
Running the Angular app (via ng serve) local and the nodejs server on the raspberry
Not working
hosting angular app via nginx (putting the content of dist folder (generated by ng build --prod) into var/www/html) and running nodejs server on raspberry --> resulting in Error during WebSocket handshake: Unexpected response code: 400
Code
Nodejs Server
const Express = require('express')();
const Http = require('http').Server(Express);
const Socketio = require('socket.io')(Http);
Http.listen(3333, () => {
console.log('Listening at :3333...');
});
Angular App Client
import { SocketIoConfig, SocketIoModule } from 'ngx-socket-io';
const config: SocketIoConfig = { url: 'http://192.xxx.xxx.xx:3333', options: { transports: ['websocket'] } };
#NgModule({
imports: [CommonModule, SocketIoModule.forRoot(config)],
exports: [SocketIoModule]
})
export class DataAccessModule {}
nginx config
server {
location ~* \.io {
proxy_pass http://localhost:3333;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
add_header X-location contains-io always;
}
}
EDIT: If I remove my nginx config additions I get the same results. Is there a way to test if the config is used?
Some other weird thing I discovered is, that I only see a blank page and not a single console.log when running the angular app via ng serve on the raspberry and go to localhost:4200
You better use ng build instead of ng serve, and direct your Nginx to your dest folder, like this:
location / {
root /var/www/angular-deploy; // move your dest into here
index index.html index.htm;
}
You can read this for more details, hope it will help
Turns out the only thing I needed was a dyndns, instead of localhost or a static ip.
So the client code looks like this:
private socketUrl = 'http://example.ddns.net';
// also switched to the plain socket.io-client package instead of ngx-socket-io, but I don't think this is necessary
socket: SocketIOClient.Socket = io(this.socketUrl);
and the nginx conf:
server {
listen 80;
server_name example.ddns.net;
root /var/www/app;
location ^~ /socket.io/ {
proxy_pass http://127.0.0.1:3333;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / {
try_files $uri $uri/ /index.html;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
index index.html index.htm;
}
}

Nodejs express application on nginx linux server

I have created my first nodejs application with nodejs express.
The server is
var express = require("express");
global.app = express();
require("src/app-modules/common/yamaha/yamaha.controller.api");
app.listen(8080, function() {
console.log("Listening on http://127.0.0.1:8080");
});
On windows development machine Is working.
Now I try to publish this app on a Synology NAS.
I access this application on url: //192.168.1.151/YamahaCtrl
and I have a 404 error.
Update 2: I discover what is realy the problem: how to configure the nginx server fromn
Routes are defined on yamaha.controller.api like this one:
app.get("/api/yamaha/getBasicInfo", function (req, res) {
//do something
});
I found a nodejs 8 beta package to install on NAS, and now I have nodejs version 8. But the error still remain.
So the nodejs app server is open on localhost:8080, but url access is http://192.168.1.151/YamahaCtrl, on 80.
That mean the problem is how to configure Virtual Host on NAS, and which port on node server I should use.
Update: The problem is: need to configure a redirect port on nginx server installed on Synology. I found this article:
https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-14-04
and I create configuration file /etc/nginx/sites-available/default:
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
And still not working: the html files are accessible , but api is available on port 8080 only.
I figured out what the problem was: nodejs server is serving static files too, but my config for static files was wrong. For development was working, and that why I didn't know that is wrong.
So it's no need to configure something on NAS :). To start nodejs application is enough.

node.js angular jade client and node.js rest api

Are there any good examples or guidance anyone can provide for structuring an app like this?
Client (client.company.com)
Node.js
Angular
Jade
ExpressJS
Server (private) (server.company.com)
node.js
"rest" api (express)
The api is private right now, only accessible from the hosted servers.
If there is a page which creates recipes for example, is this right?
client
- angular form with router that posts to client.company.com/recipe
- express would need route to handle that /recipe
- that route would then post to api server server.company.com/recipe
- then response would be propagated through the layers back to the ui.
Is that right having the client duplicate the api routes? Is there anything that can be done to simplify and make things with less duplication?
angular forms should just post directly to the api server. Express is used just to serve the angular html/javascript/static files. The less layers in between the html and api the better. I don't see any good reasons why you need the client to duplicate the api routes.
Since your api is behind the hosted server, you can setup nginx server to routes all your api calls from the hosted server to the api server. The below is a sample nginx configuration to do the routing:
upstream clientServer {
server client.company.com:80;
}
upstream apiServer {
server server.company.com:80;
}
server {
location / {
root html;
index index.html index.htm;
proxy_pass http://clientServer;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /api {
proxy_pass http://apiServer;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Note the above is a snippet of the nginx.conf.
Nginx will look at your URL path.
requests accessing / path will go to client server (where you can host express js and angular files)
requests accessing /api/* path will be forwarded to the apiserver
Your angular form can then call the api directly to /api/*
Hope that helps.

Resources