Nginx `stream` for multiple type of traffic - nginx-reverse-proxy

Is there a way to use the Nginx stream block for multiple types of traffic going to the same upstream server?
This works
http {
map $http_host $upstream {
example.com 1100;
www.example.com 1100;
}
upstream 1100 {
server 127.0.0.1:1100;
}
server {
listen 80;
location / {
proxy_pass http://$upstream;
proxy_set_header Host $host:80;
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;
}
}
}
stream {
map $ssl_preread_server_name $upstream {
example.com 1101;
www.example.com 1101;
}
upstream 1101 {
server 127.0.0.1:1101;
}
server {
listen 443;
proxy_pass $upstream;
ssl_preread on;
}
}
The Goal
Use the reverse proxy function to stream traffic to a background service. I do NOT want the traffic decrypted as it transits the reverse proxy. The certificates for the service reside on the upstream server; not the reverse proxy.
I will not list all the articles I have read trying to figure this out, but something along this line is what I am aiming for...
This is NOT a valid code block.
stream {
## ssl_preread_server_name does not work for for non-ssl traffic
map $ssl_preread_server_name $upstream {
example.com
## If unencrypted HTTP on port 80, route to upstream 1100
if ( unecrypted on port 80 ) { 1100;}
## If encrypted HTTPS on port 443, route to upstream 1101
if ( encrypted on port 443 ) { 1101;}
## If encrypted SSH on port 22, route to upstream 1102
if ( encrypted on port 22 ) { 1102;}
somethingelse.com
## If unencrypted HTTP on port 80, route to upstream 1200
if ( unecrypted on port 80 ) { 1200;}
## If encrypted HTTPS on port 443, route to upstream 1201
if ( encrypted on port 443 ) { 1201;}
## If encrypted SSH on port 22, route to upstream 1202
if ( encrypted on port 22 ) { 1202;}
}
upstream 1100 {
server 127.0.0.1:1100;
}
upstream 1101 {
server 127.0.0.1:1101;
}
upstream 1102 {
server 127.0.0.1:1102;
}
upstream 1200 {
server 127.0.0.1:1200;
}
upstream 1201 {
server 127.0.0.1:1201;
}
upstream 1202 {
server 127.0.0.1:1202;
}
server {
listen 80;
## Should route to 1100 or 1200 depending on domain
proxy_pass $upstream;
}
server {
listen 443;
## Should route to 1101 or 1201 depending on domain
proxy_pass $upstream;
ssl_preread on;
}
server {
listen 22;
## Should route to 1102 or 1202 depending on domain
proxy_pass $upstream;
}
}
There are two problems with that...
It obviously does not work.
If is evil - I really want to stay away from if
If there is a better way to tackle this problem, I am open to it.

Related

ASP.NET Core behind NGINX Reverse Proxy

I have a problem trying to run my ASP.NET Core 3 App behind a NGINX reverse proxy.
I am following this guide:
https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-3.1
I am using Let's Encrypt for my SSL Certificate and proxy pass to a different machine in my local network. I do not really know how to fix this problem. I already tried to secure the connection between the reverse proxy and the Kestrel Server with SSL, but this still does not work. Any Help would be greatly appreciated.
My NGINX Site.conf file is the following:
upstream dotnet {
zone dotnet 64k;
server 192.168.3.222:5000;
}
server {
server_name MyDomain.net *.MyDomain.net;
location / {
proxy_pass http://dotnet;
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;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
access_log /var/log/nginx/MyDomain.access.log;
error_log /var/log/nginx/MyDomain.error.log;
}
location = /favicon.ico {
log_not_found off;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/mydomain.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/mydomain.net/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 = MyDomain.net) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name MyDomain.net;
return 404; # managed by Certbot
}
The ASP.NET Core App is running on a different machine (Local Ip: 192.168.3.222) than the NGINX reverse proxy (Local Ip: 192.168.3.111).
If I set up a NGINX reverse proxy on the machine the ASP.NET Core App is running and proxy pass to 127.0.0.1:5000 I can access it over the local network without problems.
I also configured the Startup.cs to accept my reverse proxy:
public void ConfigureServices(IServiceCollection services)
{
// Configure Headers. Required by Nginx RProxy
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownProxies.Add(IPAddress.Parse("192.168.3.111"));
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("192.168.3.0"),24));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
{
// Forward Headers required by Nginx RProxy
app.UseForwardedHeaders();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
}
If I try to access MyDomain.net I get a 502 Bad Gateway. So the Reverse Proxy cannot connect to the App. The Example in the Documentation uses a Reverse Proxy on the same Machine as the Kestrel Server.
The NGINX Error Log is the following:
failed (111: Connection refused) while connecting to upstream, client: 0.0.0.0.1, server: mydomain.net, request: "GET / HTTP/1.1", upstream: "http://192.168.3.222:5000/$
, host: "mydomain.net"
The Machine with the Kestrel Server allows incoming traffic for Port 5000 and 5001.

How to configure Websocket secure (wss) on a Nginx node server?

I tried to configure a Websocket proxy on my Nginx server, but unfortunately, I don't get it working. I have read various forms but cannot get out of it. I think it has something to do between the client connection to the server. Local om my pc is everything working fine
client code:
var port = new osc.WebSocketPort({
url: "wss://circusfamilyprojects.nl/"
});
server code:
var wss = new WebSocket.Server({
port: 8083
});
This is my configuration in Nginx
# custom code for hop by hop headers
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
#custom code for connection with websocket this is the port on the server
upstream websocket {
server 178.62.209.37:8083;
}
server {
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/circusfamilyprojects.nl/fullchain.pem; # managed by Cert$
ssl_certificate_key /etc/letsencrypt/live/circusfamilyprojects.nl/privkey.pem; # managed by Ce$
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
root /var/www/html/vue/cfdomotica/server/public;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name circusfamilyprojects.nl www.circusfmailyprojects.nl; # managed by Certbot
location / {
proxy_pass http://websocket;
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;
proxy_pass_request_headers on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
server {
if ($host = www.circusfamilyprojects.nl) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = circusfamilyprojects.nl) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 8080 ;
listen [::]:8080 ;
server_name circusfamilyprojects.nl;
return 404; # managed by Certbot
}
In my browser I get the message "Status Code: 426 Upgrade Required" I hope someone can help me, thanks in advance!
I solved it my self by separating a server block for port 443 and a server block for the WebSocket client. I did the server block for the client on port 8086.

Is it possible to redirect TCP connection with SSL Passthrough in nginx

With the stream block in nginx, TCP proxy is not available in nginx. With SSL passthrough configuration it can pass the client certificate all the way to the backend service for verification.
I want to redirect this TCP connection from nginx with all the certificates to https endpoint of same service
Updated question:
So request is coming for http://demo.local which need to be redirected to https://demo.local then do SSL passthrough after redirect for https request
----> Nginx configuration
http {
server {
listen 80;
server_name demo.local;
location / {
return 302 https://demo.local$request_uri
}
}
}
stream {
# main log compatible format
log_format stream '$remote_addr - - [$time_local] "$ssl_preread_server_name -> $name ($protocol)" '
'$status $bytes_sent "" "" "" ';
map $ssl_preread_server_name $name {
demo.local pt-up-demo.local;
}
upstream pt-up-demo.local {
server 127.0.0.1:5000;
}
upstream proxy-up-demo.local {
server x.x.x.x:8080;
}
server {
listen 5000 proxy_protocol;
proxy_pass proxy-up-demo.local'
}
server {
listen 443;
proxy_pass $name;
proxy_protocol on;
ssl_preread on;
access_log /dev/stdout stream;
}
}```
A HTTP redirect is done at the HTTP level not at the HTTPS level. In order to let nginx issue this redirect the TLS connection needs to be terminated by nginx - which conflicts with the SSL passthrough you want.

nginx: subdomains, map to 2nd host with multiple ports

I have been looking for an nginx reverse proxy config that can:
receive incoming traffic from my router on port 80, from mydomain.com;
from subdomains, say sd01, sd02, sd03.
i.e. sd01.mydomain.com - then must go via the nginx reverse proxy (host1), and point the request to host2 (all RPi's) behind my router, and be routed to a different port on this host2.
On host2 (ip address say 192.168.1.33), I have docker running several instances of node-red, each container pointing to a different port on host2:
- sd01.mydomain.com to point to 192.168.1.33:1101
- sd02.mydomain.com to point to 192.168.1.33:1102
- sd03.mydomain.com to point to 192.168.1.33:1103
I have seen so many options of doing this on the web, from using
map $subdomain $subdomain_port {
to others, but I cannot get it working. Could someone point me in the right direction please?
And yes, I have added the wildcard * directive on godaddy for the sub domains to point to the fixed ip of my router.
You should use the upstream directive in association with a proxy_pass in the location directive for this.
ie.
upstream sd01 {
server 192.168.1.33:1101;
}
upstream sd02 {
server 192.168.1.33:1102;
}
upstream sd03 {
server 192.168.1.33:1103;
}
server {
listen 80;
listen [::]:80;
root /var/www;
server_name sd01.mydomain.com;
location / {
proxy_pass http://sd01/;
}
}
server {
listen 80;
listen [::]:80;
root /var/www;
server_name sd02.mydomain.com;
location / {
proxy_pass http://sd02/;
}
}
server {
listen 80;
listen [::]:80;
root /var/www;
server_name sd03.mydomain.com;
location / {
proxy_pass http://sd03/;
}
}
Note that if you are using sockets you will need to upgrade the connection for that path:
location /socket/ {
proxy_pass http://socketserverupstream;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
}
This is a similar configuration that I use for all of my servers. You can however refer to the NGINX documentation.
In your nginx configuration file(nginx.conf) do these changes:
server
{
listen 80;
server_name sd01;
location / {
proxy_pass http://127.0.0.1:1101;
}
}
server
{
listen 80;
server_name sd02;
location / {
proxy_pass http://127.0.0.1:1102;
}
}

Is possible to use SSL in Odoo with NginX avoiding the standard ports (80 and 443)?

Following this tutorial I configured my Nginx like this:
upstream odoo8 {
server 127.0.0.1:8069 weight=1 fail_timeout=0;
}
upstream odoo8-im {
server 127.0.0.1:8072 weight=1 fail_timeout=0;
}
server {
# server port and name (instead of 443 port)
listen 22443;
server_name _;
# Specifies the maximum accepted body size of a client request,
# as indicated by the request header Content-Length.
client_max_body_size 2000m;
# add ssl specific settings
keepalive_timeout 60;
ssl on;
ssl_certificate /etc/ssl/nginx/server.crt;
ssl_certificate_key /etc/ssl/nginx/server.key;
error_page 497 https://$host:22443$request_uri;
# limit ciphers
ssl_ciphers HIGH:!ADH:!MD5;
ssl_protocols SSLv3 TLSv1;
ssl_prefer_server_ciphers on;
# increase proxy buffer to handle some Odoo web requests
proxy_buffers 16 64k;
proxy_buffer_size 128k;
# general proxy settings
# force timeouts if the backend dies
proxy_connect_timeout 3600s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
# set headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
# Let the Odoo web service know that we’re using HTTPS, otherwise
# it will generate URL using http:// and not https://
proxy_set_header X-Forwarded-Proto https;
# by default, do not forward anything
proxy_redirect off;
proxy_buffering off;
location / {
proxy_pass http://odoo8;
}
location /longpolling {
proxy_pass http://odoo8-im;
}
# cache some static data in memory for 60mins.
# under heavy load this should relieve stress on the Odoo web interface a bit.
location /web/static/ {
proxy_cache_valid 200 60m;
proxy_buffering on;
expires 864000;
proxy_pass http://odoo8;
}
}
And I have this ports in my Odoo configuration
longpolling_port = 8072
xmlrpc_port = 8069
xmlrpcs_port = 22443
proxy_mode = True
When I load https://my_domain:22443/web/database/selector in the browser it loads well. But when I choose a database or I make any action, the address loses the https and the port, so it's loaded through the port 80. Then I would need to add this to the NginX configuration and the port 80 should be open
## http redirects to https ##
server {
listen 80;
server_name _;
# Strict Transport Security
add_header Strict-Transport-Security max-age=2592000;
rewrite ^/.*$ https://$host:22443$request_uri? permanent;
}
Is there a way to avoid this redirection? Like that I could keep the port 80 closed in order to avoid spoofing
Update
I can open the login screen with the address https://my_domain:22443/web/login?db=dabatase_name and I can work well inside, but if I log out in order to choose another database in the droplist, it loses again the port and the ssl
Please, try to use this construction:
## http redirects to https ##
server
{
listen 80;
server_name _;
if ($http_x_forwarded_proto = 'http')
{
return 301 https://my_domain.com$request_uri;
}
}