So I am trying to have a Node/React setup on Ubuntu, inside an Nginx server.
The React app works fine, however when I try to have API endpoints (in Node) for the React app to call, those endpoints don't work - neither for the app, nor for going to those endpoints from a browser.
This is what some of the code looks like:
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'client/build')));
app.use(express.json());
app.get('/api/contactinfo', async (req, res) => {
let contactinfo = await Information.findAll({
plain: true,
attributes: ["phone", "email", "address"],
});
res.json(contactinfo);
});
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/client/build/index.html'));
});
const port = process.env.PORT || 5000;
app.listen(port);
So for example, in this part, I might go to the React app's contact page (example.com/contact), and that loads fine. But the API call that the React app makes to the node server fails. So it seems like the React routing is working, but not the Node routing.
Likewise, if I go to just the Node API directly (example.com/api/contactinfo), that fails with a 502 bad gateway.
My Nginx setup looks like this:
location / {
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 also got some SSL cert setup stuff as well, though I'm not sure if that is relevant.
When I look at the Nginx error.log, this is what I see:
2020/09/02 15:36:54 [error] 1424#1424: *325 upstream prematurely closed connection while reading response header from upstream, client: 35.3.25.220, server: exampledomain.com, request: "GET /api/contactinfo HTTP/1.1", upstream: "http://127.0.0.1:5000/api/contactinfo", host: "exampledomain.com"
What exactly is causing my Node app API endpoints to fail? I've tried increasing the timeout, and several other things and nothing seems to be working - I've been trying to fix this problem for hours, but for some reason, despite the fact that I can successfully get React to load, I can't get any Node endpoints to do so.
How do I fix this?
I don't know the error in your implementation but here how I would do it.
// Nginx
server {
charset utf-8;
listen 80 default_server;
server_name _;
# front-end files
location / {
root /opt/front-end;
try_files $uri /index.html;
}
# node api reverse proxy
location /api/ {
proxy_pass http://localhost:5000/;
}
}
// folder structure
.
opt
+-- front-end
| +-- react app build
+-- back-end
+-- node app
// Node app
...
app.listen(5000);
Based on the article How to Deploy a MEAN Stack App to Amazon EC2
The “problem” is the certbot. If you have a self sign certificate it means that .... depending on how you configúrate certbot, basically now everything runs under port 443 not 80. So if on yow request you have some like `http://www domain com/api/endpoint. You’ll get the error you are getting. What you need to do is to use the https module from node.
import bodyParser from "body-parser";
import express from "express";
import fs from "fs";
import path from "path";
// import https
import https from "https";
import { routes } from "./routes";
import { logger } from "./utils/logger";
// The paths of those files keys will depend on where certbot stored them
const servOptions = {
cert: fs.readFileSync("/etc/letsencrypt/live/feikdomain.com/fullchain.pem"),
key: fs.readFileSync("/etc/letsencrypt/live/feikdomain.com/privkey.pem"),
ca: fs.readFileSync("/etc/letsencrypt/live/feikdomain.com/chain.pem"),
};
/**
* Createas an instance of the framework `fsexpress`.
*
* #returns {import("Express").Express} `express` instance.
*/
logger.info("express::expressApp");
const app: Express = express();
const build = path.join(__dirname, "../html");
app.use(express.static(build));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true, limit: "5m" }));
app.use("/static", express.static(build));
app.use(`${process.env.ENETO_CURRENT}`, routes());
app.use("*", function (req, res) {
return res.status(200).sendFile(`${build}/index.html`);
})
const secure = https.createServer(servOptions, app);
secure.listen(Number(process.env.PORT), () => {
console.log("servOptions: ", servOptions);
logger.info("APP RUNNING");
});
The issue was that I had a misunderstanding of how Node logging worked under Nginx.
I thought any problems or console logs with the Node setup would be logged to the nginx/error.log.
This was not in fact the case.
The Node setup had another problem, which made trying to access my endpoints crash.
The solution here is better logging that is not dependent on any sort of Nginx logs.
Solution
I just got this problem, and there are a couple of things you need.
First
you still need this
import bodyParser from "body-parser";
import express from "express";
import fs from "fs";
import path from "path";
// import https
import https from "https";
import { routes } from "./routes";
import { logger } from "./utils/logger";
// The paths of those files keys will depend on where certbot stored them
const servOptions = {
cert: fs.readFileSync("/etc/letsencrypt/live/feikdomain.com/fullchain.pem"),
key: fs.readFileSync("/etc/letsencrypt/live/feikdomain.com/privkey.pem"),
ca: fs.readFileSync("/etc/letsencrypt/live/feikdomain.com/chain.pem"),
};
/**
* Createas an instance of the framework `fsexpress`.
*
* #returns {import("Express").Express} `express` instance.
*/
logger.info("express::expressApp");
const app: Express = express();
const build = path.join(__dirname, "../html");
app.use(express.static(build));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true, limit: "5m" }));
app.use("/static", express.static(build));
app.use(`${process.env.ENETO_CURRENT}`, routes());
app.use("*", function (req, res) {
return res.status(200).sendFile(`${build}/index.html`);
})
const secure = https.createServer(servOptions, app);
secure.listen(Number(process.env.PORT), () => {
console.log("servOptions: ", servOptions);
logger.info("APP RUNNING");
});
Second
on yow location
location / {
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;
}
more specific on the proxy_pass http://localhost:5000;
change the http or add an s at the end like this
proxy_pass https://localhost:5000;
location / {
proxy_pass https://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;
}
Express.js version 4.17
my setup:
proxy(nginx) -> express.js-server (localhost:3000)
my url is: https://example.com/server/xy
Proxy send to express.js-server: localhost:3000/xy
server.get('/data.js', async (req, res, next) => {
console.log("req2", req.host, req.port, req.originalUrl, req.get('host'), req.path);
res.json({"done":"1"})
})
results in this log msg:
req2 example.com undefined /data.js example.com:443 /data.js
nginx conf:
http {
proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
server {
set $server http://localhost:3000;
location /server{
rewrite ^/server/(.*) /$1 break;
proxy_pass $server;
proxy_redirect $server https://$host:$server_port/server/;
}
}
An idea how to get that basepath that seems to be lost between proxy and express.js?
I have a node application running on a service with Apache and Nginx as a reverse proxy.
On the same server also a Node REST API is running.
The JavaScript code looks as follows:
api.js
// Express
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
// Express App
const app = express();
// Env
const PORT = process.env.PORT || 3000;
const NODE_ENV = process.env.NODE_ENV || 'development';
// Config
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
// Routes
const users = require('./routes/users');
// Angular Http content type for POST etc defaults to text/plain at
app.use(bodyParser.text(), function ngHttpFix(req, res, next) {
try {
req.body = JSON.parse(req.body);
next();
} catch(e) {
next();
}
});
app.use('/api', users);
app.listen(PORT, function() {
console.log('Listen on http://localhost:' + PORT + ' in ' + NODE_ENV);
});
/routes/users.js
var models = require('../models');
var express = require('express');
var router = express.Router();
// get all users
router.get('/users', function(req, res) {
models.Beekeeper.findAll({}).then(function(users) {
res.json(users);
});
});
module.exports = router;
The Nginx configuration looks as follows:
index index.html index.htm;
upstream api {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443;
root /var/www;
ssl on;
ssl_prefer_server_ciphers On;
ssl_protocols TLSv1.2;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
ssl_certificate /etc/letsencrypt/live/example.com/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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_set_header X-Forwarded-Proto $scheme;
}
location /api {
proxy_pass http://api;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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_set_header X-Forwarded-Proto $scheme;
rewrite ^/api/?(.*) /$1 break;
proxy_redirect off;
}
}
The problem is that if I make an API call on my development server, for example, localhost:3000/api/users, it works as expected.
However, if I make an API call on my production server, for example, https://example.com/api/users, I get Cannot GET /users and 404 NOT FOUND, respectively.
I suppose that there is something wrong with my Nginx configuration, however, although I already read numerous other posts about similar problems here on Stackoverflow, I could not solve the problem.
Notice that you're requesting this:
https://example.com/api/users
But the error says this:
Cannot GET /users
So the /api prefix is being stripped off the request path before being passed to your Node server.
Which is done by this line:
rewrite ^/api/?(.*) /$1 break;
Solution: remove that line.
I´ve got a Nginx server with following config
and an node.js Server.
server.js
app = express(),
cookieSession = require('cookie-session'),
app.use(cookieSession({
secret: config.session_secret,
resave: true,
saveUninitialized: true,
store: new Redis({
port: config.redis_port
}),
cookie: { max_age: 43200000, domain:"localhost"}
}));
nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
upstream app {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name localhost;
client_max_body_size 32m;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://app/;
proxy_redirect off;
}
}
server {
listen 80;
server_name sub.localhost;
client_max_body_size 32m;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://app/;
proxy_redirect off;
}
}
}
I´ve tried adding domain:".localhost" or even domain:"*.localhost" also i tried adding
app.use(function(req, res, next){
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', req.headers.host)
// 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');
// 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);
next();
});
to the server.js
The problem is, when i authenticate on the localhost im not authenticated on sub.localhost.
From Login session across subdomains:
You can use: domain: ".app.localhost" and it will work. The 'domain' parameter needs 1 or more dots in the domain name for setting cookies.
hello i have to config multiple apps of nodejs using nginx...
this is my actual configuration
upstream domain.com.ar {
server 127.0.0.1:9000;
}
server {
listen 80;
server_name www.domain.com.ar;
rewrite ^/(.*) http://domain.com.ar/$1 permanent;
}
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name domain.com.ar;
#access_log /var/log/nginx/domain.com/access.log;
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://domain.com.ar;
proxy_redirect off;
}
}
when i use the ip 190.213.125.17:9000 (its just an example of my ip) the app works fine
but when i try to use the domain.com.ar nginx redirect to this page
http://domain.com.ar/cgi-sys/defaultwebpage.cgi
so the app respond with a 404 error configured by me in my app.js like a middleware
app.use(function(req, res, next){
res.render('404.jade',
{
title: "404 - Page Not Found",
showFullNav: false,
status: 404,
url: req.url
});
});
there is something wrong in the nginx config???