Configure nginx to send back index.html for a 404 - node.js

I'm trying to send back my index.html to the client when my nginx (acting as reverse proxy for my express application servers and to serve static assets) gets back a 404 from the API that it's proxying for.
This is the relevant server block for my nginx configuration:
server {
listen 80;
root /var/www/dist;
index index.html index.htm;
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 1d;
}
location #proxy {
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-NginX-Proxy true;
proxy_http_version 1.1;
proxy_redirect off;
proxy_pass http://node-app;
proxy_cache_bypass $http_upgrade;
}
location / {
try_files $uri $uri/ #proxy;
}
error_page 404 = /;
}
Just to specify, the use case here is I'm using React Router with HistoryLocation enabled, so right now if I try to refresh on one of my routes (like example.com/signup), I get back a 404.

When using an express server (including via nginx), send back index.html as a catch-all, after handling other file types:
app.get( /\.(js|css|png|jpg|svg)$/, function(req, res) {
var uri = url.parse( req.url, true, false );
sendFile( res, uri.pathname );
} );
//------------- return index.html for everything else so routing works
app.get( '*', function(req, res) {
sendFile( res, `${htmlPath}index.html` );
} );
If just using nginx directly (without express), return index.html for 404 errors:
error_page 404 /index.html;
location = /40x.html {
}

Related

Passing All Directories To Express Using Nginx

I'm trying to pass through all the directories in my app through to express, and in some cases directories that contain a dynamic 'key' which I'll :capture.
I can't get even a defined sub-directory, /pretest, to pass through to express. Despite copying the the same options for Location /, it serves me an Ngxin 404
Ideally, I want domain.com/prepop/{lookup_key} to pass to localhost:8080/prepop/{lookup_key}
Where {lookup_key} is a different value each time
Any ideas what I'm doing wrong here? Any/all help is much appreciated.
Code-
server.js
const path = require('path');
const express = require("express");
const mysql = require('mysql2');
const cors = require("cors")
const port = process.env.PORT || 8080;
const app = express();
app.use(cors())
app.get('/', (req, res) => {
res.send('hello');
});
app.get('/pretest', (req, res) => {
res.send('test');
});
app.get('/prepop/:lookup_key', (req, res) => {
let connection = mysql.createConnection({
//commented out for stackoverflow
});
connection.connect();
connection.query('SELECT * FROM table_incoming_leads WHERE leadid = '+req.params.send_key, (err, response, fields) => {
if (err) console.log(err);
res.json({
email: response[0].email,
first_name: response[0].first_name,
last_name: response[0].last_name
})
});
connection.end();
})
app.listen(port, () => console.log(`Server listening on port ${port}`));
/etc/nginx/sites-available/default
server {
root /var/www/html;
location / {
proxy_pass http://localhost: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;
try_files $uri $uri/ =404;
}
location /pretest {
proxy_pass http://localhost: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;
try_files $uri $uri/ =404;
}
location /prepop {
proxy_pass http://localhost: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;
try_files $uri $uri/ =404;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/subdomain.mydomain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/subdomain.mydomain.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = subdomain.mydomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 ;
listen [::]:80 ;
server_name subdomain.mydomain.com;
return 404; # managed by Certbot
}
You need to remove try_files directive from /prepop location because when nginx receives a request for let's say /prepop/somekey it looks for a file with that name (somekey) in your root directory. Since there is no such file it returns 404.

WebSocketClient.js:16 WebSocket connection to wss://mydomain.com:3000/ws failed: error on nginx

When I run my application on chrome, I get the error. Websocket doesn't work, but it works locally.
this is my nginx server setup. I have 2 server instances. I don't know if that is the problem. Anyone knows the best way to fix this??
server {
listen 80;
server_name mydomain + .com;
rewrite ^/(.*) https://mydomain + .com/$1 permanent;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name mydomain + .com;
ssl_certificate /home/chained.crt;
ssl_certificate_key /home/mykey.key;
// Frontend Setup
location / {
proxy_pass http://localhost:3000;
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;
}
// API SETUP
location /api {
proxy_pass http://localhost:8000;
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;
}
// SOCKET.IO SETUP
location /socket.io/ {
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 false;
proxy_pass http://localhost:8000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
this is my nodejs setup for backend.
const app = express()
const httpServer = https.createServer({}, app)
const io = require('socket.io')(httpServer, {
cors: {
origin: '*',
methods: ['GET, POST'],
credentials: true,
allowedHeaders: ['custom-header'],
},
})
httpServer.listen(port, () => {
console.log(`Server running on port ${port}`)
})
MY react setup looks like this
useEffect(() => {
if (!socket.current) {
socket.current = io(process.env.REACT_APP_API_APP)
console.log('SOCKET', socket.current)
}
if (socket.current) {
socket.current.emit('join', { userId: user._id })
socket.current.on('connectedUsers', ({ users }) => {
users.length > 0 &&
dispatch({
type: 'SET_CONNECTED_USERS',
payload: users,
})
// users.length > 0 && setConnectedUsers(users)
})
}
My application works locally. but on nginx, It doesn't work. I just get the error as shown in the image.
I am new to servers. Any help would be appreciated.

API Rest Nginx cannot get

I've been develop an API with Express and Node.js. I have a simple routes and need to setup Nginx as a reverse proxy (following this steps: https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-16-04#set-up-nginx-as-a-reverse-proxy-server) but when I create a GET request my browser says: "Cannot GET /video/GetVideo/some_id".
Node code:
_apiRoutes = express.Router();
_apiRoutes.get('/video/GetVideo/:VideoID', (req, res) => {
getVideo(req.params, (result) => {
res.json(result);
});
});
_apiRoutes.get('*', function (req, res) {
res.status(404).send('yay!, are you lost?');
});
app.use('/api', _apiRoutes);
last code generate a route like: http://some_url/api/video/GetVideo/:VideoID
Nginx code:
...
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
#try_files $uri $uri/ =404;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header x-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:3500;
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;

Handle Express Subdomain with nginx

I Wonder how can i handle subdomains in my project that based on Expressjs.
Here's My nginx configuration
server {
listen 80;
server_name bee.local;
access_log /var/log/nginx/bee.local.access.log;
error_log /var/log/nginx/bee.local.error.log;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $remote_addr;
}
}
server {
listen 80;
server_name api.bee.local;
access_log /var/log/nginx/bee.local.access.log;
error_log /var/log/nginx/bee.local.error.log;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $remote_addr;
}
}
and here's my router with subdomain support
router.get('/v1/', function(req, res, next) {
res.status(200).json({ title: "title" });
});
app.use(subdomain('api', router));
The problem is that it's rendering the index route
and for sure i setuped the hosts file
I've been searching for 3 hrs can you help me :)
There are several requirements:
Setup Host header in nginx with required domain or proxy if applicable
Use subdomain middleware before other middlewares that handle endpoints
Work example:
nginx configuration:
server {
listen 80;
server_name bee.local;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 80;
server_name api.bee.local;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
nginx configuration with hardcoded Host header values:
I believe that you did not setup Host header correctly. please try next configuration
server {
listen 80;
server_name bee.local;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# proxy_set_header Host $host;
proxy_set_header Host bee.local;
}
}
server {
listen 80;
server_name api.bee.local;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# proxy_set_header Host $host;
proxy_set_header Host api.bee.local;
}
}
express app:
var subdomain = require('express-subdomain');
var express = require('express');
var app = express();
var router = express.Router();
router.get('/', function(req, res) {
res.send('Welcome to our API!');
});
router.get('/users', function(req, res) {
res.json([
{ name: "Brian" }
]);
});
app.use(subdomain('api', router));
app.get('/', function(req, res) {
res.send('Homepage');
});
app.listen(3000);

Odd redirect to localhost instead of ip with node / express

I try to run a node server together with nginx. With passport modul I follow the local authentication strategy. My problem is that all express redirects like '/login' lead to 'localhost:3000/login' instead 'http://:3000/login'.
That an example function:
exports.ensureAuthenticated = function(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login');
}
Even res.redirect(server+'/login') makes no difference when server is the remote ip plus port.
Here is my nginx configuration (/etc/nginx/sites-available/default)
upstream node_app {
server **<ip>**:3000;
}
server {
listen 8080;
server_name **<ip>**;
root /home/nls/www2;
access_log /var/log/nginx/foo.access.log;
error_page 404 /404.html;
location /remote_data/ {
# Proxy request to node:
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-NginX-Proxy true;
proxy_pass http://node_app;
proxy_redirect off;
access_log /var/log/nginx/foo_nodeapp.access.log;
}
location / {
try_files $uri $uri/index.html 404;
}
}
The server code contains no reference to localhost redirects. Also on client side is redirect implemented without such redirects.
Edit: This the rout which makes trouble:
app.post('/login', passport.authenticate('local', { failureRedirect: 'http://<ip>:3000/login', failureFlash: true }), function(req, res) { res.redirect('http://**<ip>**:3000/vi-lab'); });

Resources