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.
Related
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;
}
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;
}
}
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.
So I have a nodejs app running on port 8081:
http://mysite.com:8081/
I want to access it simply by going to http://mysite.com/ so I setup a virtual host with expressjs:
app.use(express.vhost('yugentext.com', app));
That seems too easy, and it doesn't work. Am I confused about how expressjs vhosts work?
if you want to do these via express well, the problem comes from your dns setup, not from the express code.
Add an A entry to your domain like these:
127.0.0.1 localhost *.mysite.com *.www.mysite.com
You should wait to the DNS propagation. (from seconds to hours).
If apache or other web server is running any vhost on port 80 there will be conflicts.
And the other way:
nodejs and express are far away from the performance offered by apache and nginx (vhost/proxy stuff).
Nginx>Apache (fits better with nodejs)
Creates a proxy from mysite.com to mysite.com:8080
On these way nodejs and express handles the ui, methods, httpserver etc, and Nginx or Apache the proxy , vhost, and managing your static assets sooo fast.
check these config here: Trouble with Nginx and Multiple Meteor/Nodejs Apps
I think you're doing app.listen(8081). You should be doing app.listen(80). I have no experience with express vhosts, but you don't need them for this simple use case.
upstream node-apps {
server host_ip_1:3000;
server host_ip_2:3000;
}
server {
listen 80;
server_name localhost;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://node-apps/;
proxy_redirect off;
}
}
this is my nginx config, proxy pass multiple servers, good luck :p
am running varnish on EC2 in front of nginx which routes to node.js.
What I would like is to serve specific static HTML pages from certain routes (like, / for index.html) via nginx, but have all other routes be handled by node.js.
As an example, / would be sent by nginx in the form of a static HTML page, while anything not matching, say /dynamic_stuff or /dynamic_stuff2, would be processed by node.js.
In other threads online, other people were putting node.js in a separate dir entirely, like /node/dynamic_stuff but I didn't want to have a separate dir for my routing.
Right now I have / served up by node.js like everything else but if I'm just testing my node.js server and I take it down, I'd like / to fallback to an nginx version of index.html. In this case, if my node.js server is taken down, then I get a 502 Bad Gateway.
I'm not too worried about performance from serving up files via nginx vs. node.js, I just figure that I want to have nginx handling basic pages if node.js goes down for whatever reason.
Relevant script:
location = / {
index index.html
root /path/to/public
try_files $uri $uri/ index.html;
}
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass node_js;
}
If I use this above code, all requests still get sent to node.js, including /.
I think the simplest thing to do if it's just the index.html is to set index to
index index.html
root /path/to/public
All files in your public directory should now be served from nginx.
Now put this index.html in the public directory of your node app. The rest will be proxied from nginx to the node instance.
Of course you can simply put other static html in subdirectories if you want:
public/about(index.html
public/faq/index.html
...