Unable to serve expressjs app from subfolder - express

I am new to express and nginx.
I have made a simple express app and configure nginx:
location /exapi {
proxy_pass http://localhost:8010;
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;
}
My expressjs app is:
var express = require('express')
var app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
app.listen(8010, function () {
console.log('Example app listening on port 8010!')
})
When I access my vps VPS_IP/exapi, I get response Cannot GET /exapi, but when I use http://VPS_IP:8010 it is working as expected.
How can I access my express app from VPS_IP/exapi?

Try rewrite in nginx:
location ~* ^/exapi {
rewrite ^/exapi/(.*) /$1 break;
subfilter /exapi /;
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass http://localhost:8010;
}

Related

How to run .Net 6 API with NGINX reverse proxy

I try to run a .Net 6 API with NGINX on a Raspberry PI 3B, according to this documentation:
https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-6.0
I configured my API as described in the article, the API is reachable under localhost.
I installed NGINX, the landing page is only locally reachable under http://192.168.178.51/index.nginx-debian.html not from other clients.
Also http://192.168.178.51/swagger does not work, nether locally or from clients.
One question for me is, where to locate the ForwardHeadersOptions?
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseAuthentication();
The article says “Invoke the UseForwardedHeaders method at the top of Startup.Configure before calling other middleware.”
I have no Startup.Configure in my project. Does this description not fit for .Net 6?
This is my program.cs:
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
if (app.Environment.IsDevelopment())
{
app.UseHttpsRedirection();
}
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Is it correct?
This is my default NGINX file:
server {
listen 80;
server_name test.abc *.test.abc;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80 default_server;
# listen [::]:80 default_server deferred;
return 444;
}
Whats wrong in my configuration?
BTW: No access from the internet possible, currently I’ll run it only in my local network.
I posted a minimal project here: https://github.com/Christoph1972/API_NGINX_Demo
I got it.
server {
listen 80 default_server;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Any doubts for this solution?
Next I’ll figure out how to create a server name for a private network, like test.abc.

Using socket.io with ejs on Express/Nginx

I'm working on a app with socket.io, ejs, express & nginx on a Node JS server.
I have managed to get the socket.io working withthout use of ejs.
But when I try to implement it with ejs I get error 400 on client.js.
Here is my code for server.js :
var express = require('express');
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var ejs = require('ejs');
// WITHOUT EJS : WORKS FINE
app.get('/', function(req, res) {
res.sendFile(index.html');
});
// WITH EJS : GET HTTP ERR 400 IN CLIENT.JS CONSOLE
app.set('view engine', 'ejs');
app.get('/', function(req, res) {
res.render('pages/index');
});
io.on('connection', function(socket) {
console.log('a user connected');
socket.on('chat message', function(msg){
console.log('message: ' + msg);
});
});
server.listen(process.env.PORT || 8080, function(){
console.log('app running');
});
My nginx code looks like this :
# HTTP — redirect all traffic to HTTPS
server {
listen 80;
listen [::]:80 default_server ipv6only=on;
return 301 https://$host$request_uri;
}
# HTTPS — proxy all requests to the Node app
server {
# Enable HTTP/2
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# Use the Let’s Encrypt certificates
ssl_certificate /.../;
ssl_certificate_key /.../;
location ~* \.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://example.com:8080;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Here is my client.js :
var socket = io();
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
What could be the issue here ?

Nginx reverse proxy using auth_request module and external authentication API - error 404

I am trying to configure nginx as a reverse proxy to protect another server (kibana) using an external authentication API.
This is the url that should log me into kibana dashboard - http://127.0.0.1/kibana_proxy?username=my.user&password=test67
Once the authentication done (i.e. https status 200), nginx is throwing a 404 error. But the error log has this -
2018/10/18 13:33:52 [error] 10718#0: *19 open()
"/usr/share/nginx/html/app/kibana" failed (2: No such file or
directory), client: 127.0.0.1, server: _, request: "GET /app/kibana
HTTP/1.1", host: "127.0.0.1", referrer:
"http://127.0.0.1/kibana_proxy/?username=my.user&password=test67"
This is my nginx conf file -
server {
listen *:80;
server_name _;
location = /auth {
set $query '';
if ($request_uri ~* "[^\?]+\?(.*)$") {
set $query $1;
}
proxy_pass http://127.0.0.1:8080/auth?$query;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
location /kibana_proxy/ {
proxy_pass http://127.0.0.1:5601/;
auth_request /auth;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
Whenever you are using Restricting Access with HTTP Basic Authentication then you should use the following url pattern to access the restricted url
http://username:password#example.com/
It is not possible to pass username and password via query parameters in standard HTTP auth.
Update:
I feel your nginx settings needs some update. You should rewrite the url to remove the /kibana_proxy/:
location /kibana_proxy/
{
rewrite ^/kibana_proxy/(.*) /$1 break;
proxy_pass http://localhost:5200;
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-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
For those seeking answer - here's the nginx server conf that solved the issue for me -
server {
listen *:80;
server_name 127.0.0.1;
location = /auth {
set $query '';
if ($request_uri ~* "[^\?]+\?(.*)$") {
set $query $1;
}
# add_header X-debug-message "Parameters being passed $is_args$args" always;
proxy_pass http://127.0.0.1:8080/auth?$query;
}
location /kibana/ {
rewrite ^/kibana/(.*) /$1 break;
proxy_pass http://127.0.0.1:5601;
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-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
auth_request /auth;
}
location ~ (/app/|/app/kibana|/bundles/|/kibana4|/status|/plugins|/ui/|/api/|/monitoring/|/elasticsearch/) {
proxy_pass http://127.0.0.1:5601;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
rewrite /kibana4/(.*)$ /$1 break;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

SocketIO over Nginx with SSL

I'm trying to setup socketio with ssl through nginx. The issue is that I can get the client to connect but then I'm not seeing the other events which I expect to come over the socket. (note: this does work locally just not on my production server)
the client code is here:
import openSocket from "socket.io-client";
const socket = openSocket(`${SOCKET}`);
function subscribeToTimer(callBack) {
socket.on("timer", timestamp => callBack(null, timestamp));
socket.emit("subscribeToTimer", 1000);
}
export class App extends Component {
constructor(props) {
super(props);
this.store = this.configureStore();
subscribeToTimer((err, action) => this.store.dispatch(action));
}
and the server:
const port = 8000
const io = require('socket.io')()
io.on("connection", (client) => {
console.log("a user connected")
client.on("subscribeToTimer", (interval) => {
console.log("a user is subscribing to timer with interval: ", interval)
setInterval(() => {
timestamp = new Date()
client.emit('timer', { type: 'SET_TIME', payload: timestamp });
}, interval);
});
})
io.listen(port)
console.log('listening on port ', port)
which is managed by nginx /etc/nginx/sites-enabled/default:
server {
<snip>
location /socket.io {
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;
}
}
When I start the server, I get:
listening on port 8000
a user connected
So, the client is connecting to the server but I'm not seeing the subscribeToTImer event.
Any insights here?
The issue is probably because of two reasons. One is using the Host headers and one is using localhost instead of 127.0.0.1
server {
<snip>
location /socket.io {
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_cache_bypass $http_upgrade;
}
}
I am not 100% sure of the root cause but I have seen removing Host and using 127.0.0.1 instead of localhost has helped in other issues with socket.io in past
The problem turned out to be in the proxy_pass line of the config. You need to create an upstream section with a named group of servers and then reference that in proxy_pass (not http://localhost... the way I had it).
The working config /etc/nginx/sites-enabled/default:
upstream socket_nodes {
ip_hash;
server 127.0.0.1:8000;
}
server {
<-- snip -->
location /socket.io {
proxy_pass http://socket_nodes;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
}
}

express and nginx - loads html file but can't serve assets

I'm trying to run an express server at port 3000. When I visit my server's IP, I'm able to get the html page to load, however it doesn't seem to be able to find the assets (have a .js and .css file that I link to - this is in the same directory as the index.html inside of public). Am I missing something in my configs?
express setup
const express = require('express');
const path = require('path');
const app = express();
const PORT = 3000;
app.use('*',
express.static(path.join(__dirname, '..', 'public', 'index.html')));
app.get('*', (req, res) => {
res.sendFile((path.join(__dirname, '..', 'public', 'index.html')));
});
app.listen(PORT, () => {
console.log(`Listening on http://localhost:${PORT}...`)
});
nginx setup
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/my_site/public;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ =404;
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 Host $host;
proxy_cache_bypass $http_upgrade;
}
}
In your nginx configuration,
try_files $uri $uri/ =404;
Means nginx will try to find a static resource in your root folder, then try it with a / at the end, if it hasn't found anything yet will give out a 404 (Not Found).
It never reaches the proxy_pass.
The proper way to configure it would be like this:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/my_site/public;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ #nodejs;
}
location #nodejs {
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 Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Now, it will look for static files in your root folder, then pass it on to the node server.