How to run .Net 6 API with NGINX reverse proxy - asp.net-core

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.

Related

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;
}
}

Unable to serve expressjs app from subfolder

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;
}

Error HTTP 405 when Session Starts using load balancing NGINX

I implement Load Balancer using NGINX , but when I try to use some of the webapps developed in Java using Spring Security, when I try to login in one of the apps returns HTTP 405 - Request method 'POST' not supported.
My NGINX conf file like this:
upstream myapp {
server 172.16.80.49:8095;
server 172.16.53.31:8091;
}
server {
listen 80;
location / {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://172.16.80.49:8092;
}
location /docentes {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://myapp;
}
location /gerentes {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://myapp;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
how i can solve this, I suppose the app the problem would be csrf token
Change my cof to:
upstream myapp {
ip_hash;
server 172.16.80.49:8095;
server 172.16.53.31:8091;
}
server {
listen 80;
location / {
proxy_pass http://172.16.80.49:8092;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
}
location /docentes {
proxy_pass http://myapp;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /gerentes {
proxy_pass http://myapp;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /dashboard {
proxy_pass http://myapp;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

nginx won't restart with my config file

Restarting nginx :
# service nginx start
Starting nginx: nginx: [emerg] duplicate upstream "api" in /etc/nginx/sites-enabled/default:1
nginx: configuration file /etc/nginx/nginx.conf test failed
This is the config file :
upstream api{
least_conn;
server 127.0.0.1:5001 max_fails=2 fail_timeout=15s;
server 127.0.0.1:5002 max_fails=2 fail_timeout=15s;
server 127.0.0.1:5003 max_fails=2 fail_timeout=15s;
server 127.0.0.1:5004 max_fails=2 fail_timeout=15s;
}
server {
listen 192.168.10.33:80;
allow 192.168.0.0/20;
allow 127.0.0.1/32;
deny all;
server_name api api.my.intranet;
location ^~ (/images/|/css/|/javascripts/) {
root /var/www/myapi/public/;
expires 30m;
}
# serve all other stuff from appserver
location / {
if ($http_origin ~ (.*\.my\.intranet|.*\.my\.com) ) {
add_header 'Access-Control-Allow-Origin' $http_origin;
}
# add_header 'Access-Control-Allow-Origin' '*';
expires off;
proxy_pass http://api/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
}
}
server {
listen 175.30.33.14:80;
server_name api.my.com;
return 301 https://api.my.com$request_uri;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/certs/my.com.2014.chain;
ssl_certificate_key /etc/ssl/private/my.com.2014.key;
server_tokens off;
server_name api api.my.com api.my.intranet;
location ^~ (/images/|/css/|/javascripts/) {
root /var/www/myapi/public/;
expires 30d;
}
# serve all other stuff from appserver
location / {
if ($http_origin ~ (.*\.my\.intranet|.*\.my\.com) ) {
add_header 'Access-Control-Allow-Origin' $http_origin;
}
# add_header 'Access-Control-Allow-Origin' '*';
expires off;
proxy_pass http://api/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
}
location /v2 {
rewrite ^/v2/(.*) /$1 break;
if ($http_origin ~ (.*\.my\.intranet|.*\.my\.com) ) {
add_header 'Access-Control-Allow-Origin' $http_origin;
}
# add_header 'Access-Control-Allow-Origin' '*';
expires off;
proxy_pass http://192.168.10.8:3000/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Do you see any problem ?
a backup file: defuault.backup was in the same folder which created a conflict !