Nginx proxy pass directive: Invalid port in upstream error - nginx

I am doing load balancing with Nginx. Here is my config
upstream web_backend {
least_conn;
server localhost:8001 max_fails=3 fail_timeout=60s;
server localhost:8002 max_fails=3 fail_timeout=60s;
}
server {
listen 8545;
server_name _;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://web_backend;
}
}
server {
listen 8001;
server_name localhost;
location / {
proxy_pass https://some_other_url/v3/cxnmcdinwrtyf93vcwdiyfx8q6xqwxv9qg7c93fgcb;
}
}
server {
listen 8002;
server_name localhost;
location / {
proxy_pass 'https://chipdunk-dude:gorgeous-serpents-clubbed-orphans#nd-657-555-555-777.dogify.com';
}
}
as you can see the url at port 8002 is weird (dont even know what this kind of urls are called)
because it has ":" in the url, Nginx gives me this error
nginx: [emerg] invalid port in upstream "chipdunk-dude:gorgeous-serpents-clubbed-orphans#nd-657-555-555-777.dogify.com" in /etc/nginx/sites-enabled/default:60
The url at port 8001 works fine.

Everything before the # is userinfo which should be encoded by the browser and included as a separate request header according to RFC 7617.
Nginx is not a browser and cannot do it for you.
You could probably convert that into Base64 and use a proxy_set_header to set the Authorization header.
For example:
proxy_set_header Authorization "Basic Y2hpcGR1bmstZHVkZTpnb3JnZW91cy1zZXJwZW50cy1jbHViYmVkLW9ycGhhbnM=";
proxy_pass https://nd-657...;

Related

Why Nginx may pass incorrect ssl sertificate?

I've got two domains hosted per single nginx server, ex. a.com and b.com. Nginx used as reverse proxy and must pass https requests to backend as http. You can find bellow my config for a.com (b.com has the same structure but linked to another ssl files):
upstream webservers {
....
}
server {
listen 443 ssl;
server_name a.com;
ssl_certificate /etc/nginx/ssl/a.crt;
ssl_certificate_key /etc/nginx/ssl/a.key;
ssl_dhparam /etc/nginx/ssl/default.dh;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://webservers;
}
}
Unfortunately, when I test curl https://b.com it fails with curl: (60) SSL: no alternative certificate subject name matches target host name b.com. When I try to open it from browser it fails with NET::ERR_CERT_COMMON_NAME_INVALID and it shows that it use a.com certificate.
Where is my mistake?
Upd#1
I have to allow HTTP to solve issue temporary.
openssl s_client -connect b.com:443 -prexit
140648924489024:error:2008F002:BIO routines:BIO_lookup_ex:system lib:../crypto/bio/b_addr.c:726:Name or service not known
connect:errno=22
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 0 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
Configurations:
# configuration file /etc/nginx/sites-enabled/a.com:
upstream a-webservers {
server 192.168.0.252 max_fails=3 fail_timeout=30s;
server 192.168.0.252 max_fails=3 fail_timeout=30s;
}
server {
listen 443 ssl;
server_name a.com;
error_log /var/log/nginx/a.com-error.log;
access_log off;
ssl_certificate /etc/nginx/ssl/a.crt;
ssl_certificate_key /etc/nginx/ssl/a.key;
ssl_dhparam /etc/nginx/ssl/default.dh;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://a-webservers;
}
}
# configuration file /etc/nginx/sites-enabled/b.com:
upstream b-webservers {
server 192.168.0.252 max_fails=3 fail_timeout=30s;
server 192.168.0.252 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
listen 443 ssl;
server_name b.com;
error_log /var/log/nginx/b.com-error.log;
access_log off;
ssl_certificate /etc/nginx/ssl/b.crt;
ssl_certificate_key /etc/nginx/ssl/b.key;
ssl_dhparam /etc/nginx/ssl/default.dh;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://b-webservers;
}
}

Nginx conf to manage traffic between 2 ssl'd endpoints

Here's the setup:
fowarding_proxy -> server_1, server_2
server_1 -> app1.domain.com, app2.domain.com
server_2 -> app3.domain.com, app4.domain.com
Where each server is running a docker daemon with an nginx reverse-proxy based on the jwilder/nginx-proxy + letsencrypt setup.
Both servers sit behind the same router and I need a way to route traffic correctly to each one based on the host name. I've been trying to use the nginx stream module since I don't want the forwarding proxy to handle any ssl termination, but the $ssl_preread_name directive doesn't (seem) to capture the host name on http traffic and I can't do a 301 on server directives in the stream module. What's the best way to approach this?
I've included an example of the config I'm currently working with and I've tried multiple iterations. Open to any suggestions.
(Also, as an aside, nothing logs to access.log)
Forward_proxy nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
stream {
# bare bones content, still nothing written to the log.
log_format main '[$time_local] $remote_addr'
access_log /var/log/nginx/access.log main;
map $ssl_preread_server_name $name {
app1.domain.com server1;
app2.domain.com server1;
app3.domain.com server2;
app4.domain.com server2;
}
upstream server1 {
server server1:80;
}
upstream server2 {
server server1:80;
}
upstream server1_ssl {
server server1:443;
}
upstream server2_ssl {
server server1:443;
}
server {
listen 80;
proxy_pass $name;
ssl_preread on;
}
server {
listen 443;
proxy_pass "${name}_ssl";
ssl_preread on;
}
}
Came up with a solution, happy to hear of better ones.
Instead of a single forwarding-proxy, I created two new nginx containers: One for HTTP traffic and the other for HTTPS traffic and put them both in a single docker-compose file for easier management.
HTTP-forwarding-proxy
http {
map $host $name {
default server1;
app3.strangedreamsinc.com server2;
app4.strangedreamsinc.com server2;
}
upstream server1 {
server server1_ip:8080;
}
upstream server2 {
server server2:8080;
}
server {
listen 80 default_server;
server_name _;
location / {
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_pass http://$name;
}
}
}
HTTPS-forwarding-proxy
stream {
map $ssl_preread_server_name $name {
default server1;
app1.strangedreamsinc.com server1;
app2.strangedreamsinc.com server1;
}
upstream server1 {
server server1_ip:8443;
}
upstream server2 {
server server2_ip:8443;
}
server {
listen 443;
proxy_pass $name;
ssl_preread on;
}
}
I'm not convinced there isn't a better way and there's probably something I'm overlooking, but this allows me to transparently route traffic to the correct reverse-proxy and still supports the letsencrypt protocols to apply SSL to my servers.

Nginx upstream with http & https

I have some problem about nginx with http and https bypass, In upstream block
upstream block:
upstream bypass{
server 192.168.99.1:80; #http
server 192.168.99.2:443 backup; #https
}
When http 80 have a problem (server down, etc), I want to redirect to https 443,
This block does not work for me.
location block:
location / {
proxy_pass https://bypass;
proxy_redirect off;
}
How can I resolve this?
This works well: Create server config section for each backend on different port and forward to both ports internally without ssl.
In this example, you can see how the first server acts as main server with cached content (available via https) and if cache content is not available, use the second server (via http).
(using nginx 1.19.6, just for reference)
upstream backends {
server 127.0.0.1:8082;
server 127.0.0.1:8081 backup;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# ssl certs etc here
location / {
proxy_pass http://backends;
proxy_next_upstream error timeout http_404 http_403;
}
access_log /var/log/nginx/access.log upstreamlog;
}
server {
listen 8081;
location / {
add_header X-Cache MISS;
proxy_pass http://server1;
proxy_set_header Host server1;
}
}
server {
listen 8082;
location / {
add_header X-Cache HIT;
proxy_pass https://server2;
proxy_set_header Host server2;
}
}
Taking a shot in the dark. Assuming you were having issues mixing HTTP and HTTPS in the upstream, you could try this in the location block:
location {
try_files #bypass-http #bypass-https =404;
location #bypass-http {
proxy_pass http://bypass;
proxy_redirect off;
}
location #bypass-https {
proxy_pass https://bypass;
proxy_redirect off;
}
}
And if that didn't work, split the bypass upstream block into bypass1 and bypass2 and reference them accordingly in their corresponding location blocks:
upstream bypass1{
server 192.168.99.1:80; #http
}
upstream bypass2{
server 192.168.99.2:443; #https
}
location {
try_files #bypass-http #bypass-https =404;
location #bypass-http {
proxy_pass http://bypass1;
proxy_redirect off;
}
location #bypass-https {
proxy_pass https://bypass2;
proxy_redirect off;
}
}
A third option would be reference them both on port 80, and ensure the second upstream server redirects HTTP requests to HTTPS.

Nginx server name issue

In my Nginx configuration, I would like to keep one service to be accessible with http, while all the others should be accessed through https, and forced to ssl when trying to connect with http. This is my config:
server{
server_name localhost;
listen 80;
proxy_http_version 1.1;
location /services/ {
proxy_pass http://localhost:47440/;
}
listen / {
rewrite ^ https://$server_name$request_uri? permanent;
}
server{
server_name localhost_ssl;
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/mycert.crt;
ssl_certificate_key /etc/nginx/ssl/mycert.key;
proxy_http_version 1.1;
location /db/ {
proxy_pass http://localhost_ssl:8084/;
}
}
My problem is that when trying to reload I get this error:
host not found in upstream "localhost_ssl" in /etc/nginx/nginx.conf:46
Any idea of why this happens?
It seems your DNS resolver is failing for some reason.
Try adding:
options single-request
to /etc/resolv.conf
This causes IPv6/v4 lookups to be done sequentially.
You got this error because nginx can't find the host "localhost_ssl". Indeed it doesn't exist unless you specify it with upstream directive (or in the hosts file I think).
You should set it to proxy_pass http://localhost:8084/; assuming your service is really listening on 127.0.0.1:8084.
Furthermore you may want to replace listen / { with location / {.
UPDATE : If you access your server with your IP (you don't have a domain name), then you can remove server_name directive :
server {
listen 80;
proxy_http_version 1.1;
location /services {
proxy_pass http://localhost:47440/;
proxy_set_header Host $host;
}
location / {
return 301 https://$host$request_uri?; # Replace $server_name by $host
}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/mycert.crt;
ssl_certificate_key /etc/nginx/ssl/mycert.key;
proxy_http_version 1.1;
location /db {
proxy_pass http://localhost:8084/;
proxy_set_header Host $host;
}
}
That config redirects requests received on port 80 to 443 if they don't match location /services. Requests received on port 443 are proxied if they match location /db.
But is this what you really want to achieve ? I mean a request on port 443 for /test would not match any location as there is only /db.

NGinx config for redirecting domain

I have 2 servers on my network:
one linux machine (192.168.0.2) with a website listening on port 8181 for service1.domain.com
one windows machine (192.168.0.3) with a website listening on port 8080 for service2.domain.com
I want to set up an nginx reverse proxy so that I can route requests like so:
service1.domain.com --> 192.168.0.2:8181 with host header service1.domain.com
service2.domain.com --> 192.168.0.3:8080 with host header service2.domain.com
I have tried with the following config:
### General Server Settings ###
worker_processes 1;
events {
worker_connections 1024;
}
### Reverse Proxy Listener Definition ###
http {
server {
listen 80;
server_name service1.domain.com;
location / {
proxy_pass http://192.168.0.2:8181;
proxy_set_header host service1.domain.com;
}
}
server {
listen 80;
server_name service2.domain.com;
location / {
proxy_pass http://192.168.0.3:8080;
proxy_set_header host service2.domain.com;
}
}
}
But that doesn't seem to work?
Is there anything blindingly obvious that I might be doing wrong here?
this works fine for me:
http {
server {
listen 80;
server_name service1.domain.com;
location / {
proxy_pass http://192.168.0.2:8181;
proxy_set_header host service1.domain.com
}
}
server {
listen 80;
server_name service2.domain.com;
location / {
proxy_pass http://192.168.0.3:8080;
proxy_set_header host service2.domain.com;
}
}
}
have a try?

Resources