'conflicting server name' with two default/catchall locations for nginx - one with default_server, one without? - nginx

I'm at my wit's end here. I've been fighting an nginx configuration for hours. Here are the two blocks I'm trying to use:
server {
listen 80 default_server;
location /health-check {
default_type 'text/plain';
access_log off;
return 200;
}
}
server {
listen 80;
location / {
return 301 https://$http_host$request_uri;
}
}
# other application servers/upstreams follow -- one is provided here for completeness,
# although the issue is almost certainly above
upstream quinoa-icehouse {
server 172.17.8.100:49153;
}
server {
server_name ~^quinoa-icehouse\.(?<domain>.+)$;
server_name_in_redirect off;
port_in_redirect off;
listen 443 ssl spdy;
listen 80;
ssl_certificate /etc/ssl/deis.cert;
ssl_certificate_key /etc/ssl/deis.key;
location / {
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_connect_timeout 30s;
proxy_send_timeout 1200s;
proxy_read_timeout 1200s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_next_upstream error timeout http_502 http_503 http_504;
add_header X-Deis-Upstream $upstream_addr;
proxy_pass http://quinoa-icehouse;
}
}
Note that I want the /health-check endpoint to work only when other server names aren't matched, but I want the 301 to occur whenever a server name is matched.
I seem to have tried every combination of these directives, only to get:
[INFO] - 2014/12/30 01:26:34 [warn] 39#0: conflicting server name "" on 0.0.0.0:80, ignored
Is there a way for me to accomplish what I seek? Thank you!!

Essentially, you are going outside the Nginx' defined parameters. You cannot have two default server blocks sitting on each other so to speak.
You can however achieve what you need by defining:
A catch all block listening on Port 80 to redirect all requests to Port 443
A catch all block listening on Port 443 for all unmatched domains
You then need to ensure the following:
Drop the "default_server" directive and rely on the position of the server blocks as in the example answer
Ensure other application servers/upstreams only listen on Port 443.
So your config should be something along these lines:
http {
[ ... ]
# Default to redirect from Port 80 to Port 443
server {
listen 80;
return 301 https://$host$request_uri;
}
# Default for unmatched domains on Port 443
server {
listen 443 ssl spdy;
ssl_certificate /etc/ssl/someCert.cert;
ssl_certificate_key /etc/ssl/someKey.key;
# Return 403, 404 or 444
return 403;
}
# Other servers.
# 1. These must be below this for this configuration to work.
# 2. None should listen on Port 80
server {
server_name ABC
listen 443 ssl spdy;
ssl_certificate /etc/ssl/someCert.cert;
ssl_certificate_key /etc/ssl/someKey.key;
[ ... ]
}
server {
server_name XYZ
listen 443 ssl spdy;
ssl_certificate /etc/ssl/someCert.cert;
ssl_certificate_key /etc/ssl/someKey.key;
[ ... ]
}
}
Refer to: Why is nginx responding to any domain name?
Note also that for simple server blocks that will just return simple responses, you don't need to have location blocks.

Related

Redirect HTTP to HTTPS nginx with SSL

After a lot of tries, I succeed to add proper SSL from namecheap,
that will secure my domain (with multiple ports).
I have some apps - that run on NGINX. My droplet is of Digital Ocean.
So I have a few blocks with this configuration:
#this is the default 80 port
server {
#listen 80; # - will cause nginx complain on already in use.
listen 443;
ssl on;
ssl_certificate /my/folder/forssl/my-domain_com_chain.crt;
ssl_certificate_key /home/projects/ssl-files/my-domain.com.key;
root /var/www/my-domain.com/so-ev;
server_name my-domain.com;
#all those tries didn't help
# return 301 https://so-ev-qa.shop$request_uri;
#return 301 https://$server_name$request_uri;
#rewrite ^(.*) https://so-ev-qa.shop$1 permanent;
}
server {
listen 26;
ssl on;
ssl_certificate /my/folder/forssl/my-domain_com_chain.crt;
ssl_certificate_key /home/projects/ssl-files/my-domain.com.key;
root /var/www/my-domain.com/html;
server_name my-domain.com;
}
server {
listen 3000 ;
ssl on;
ssl_certificate /my/folder/forssl/my-domain_com_chain.crt;
ssl_certificate_key /home/projects/ssl-files/my-domain.com.key;
root /var/www/my-domain.com/html2;
server_name my-domain.com;
}
server {
listen 27;
ssl on;
ssl_certificate /my/folder/forssl/my-domain_com_chain.crt;
ssl_certificate_key /home/projects/ssl-files/my-domain.com.key;
server_name my-domain.com;
index index.html index.htm;
access_log /var/log/nginx/bmiapp.log;
error_log /var/log/nginx/bmiapp-error.log error;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:26;
proxy_redirect off;
}
}
Currently the problem is that it's not doing redirect from http to https.
While https://example.com is secured,
http://example.com isn't.
I am trying to do the simple redirecting action.
All my tries ended unsuccessfully.
If I'm trying to add block for listen 80, it's complain about
All my other tries didn't work.
Help will be appreciated, I have spent on this SSL issues a lot of hours.
I found the problem.
There was an old-client service that was running on the background.
We can use
udo lsof -i:80
To get a clue

nginx: [emerg] host not found in upstream with local IPs

I've read similar questions with same error, but nothing matches my problem, because my upstream servers have local IPs.
The server is a proxmox machine with some different vms.
One is for nginx reverse gateway/proxy, the other are vms with several docker containers.
I want to setup a fallback (backup) for one container.
The config of the nginx reverse gateway/proxy containing these machines is:
server {
listen 80;
server_name my-web.page;
return 301 http://www.my-web.page$request_uri;
}
server {
listen 80;
listen [::]:80;
server_name www.my-web.page;
location / {
return 301 https://www.my-web.page$request_uri;
}
}
server {
listen 443 ssl;
server_name my-web.page;
return 301 https://www.my-web.page$request_uri;
ssl_certificate /etc/ssl/my/my-web.page.chained.crt;
ssl_certificate_key /etc/ssl/my/my-web.page.key.pem;
}
upstream backend {
server 192.168.200.210:8030 max_fails=1 fail_timeout=600s;
server 192.168.200.211:8031 backup;
}
server {
listen 443 ssl;
ssl_certificate /etc/ssl/my/my-web.page.chained.crt;
ssl_certificate_key /etc/ssl/my/my-web.page.key.pem;
server_name www.my-web.page;
location ~ ^/$ {
# rewrite only the root page, other urls see next rule
return 301 https://www.my-web-page-microsite.de/;
}
location / {
resolver 127.0.0.1 valid=30s;
# pass to backend-client, failover to second container for the next 5 minutes
proxy_pass http://backend;
proxy_set_header Host $http_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_set_header X-Server-Address $server_addr;
proxy_ssl_verify off;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
If something is wrong with my backend-client-servers, nginx won't start.
Isn't there a possibilty to override the check on starting/restarting nginx?

Nginx configuration like Synology reverse proxy

I am trying configuring nginx (based on bitname/nginx:latest) as equivalent of Synology reverse proxy. This is due to missing wild-card redirect at Synology. While doing so, I face many issues; therfore I am requesting help for proper nginx configuration.
requirements
HTTPS upgrade
Redirect any wild-card subdomain (443) to a port 30'000
Hide the redirect port from user visibility
WebSockets must be supported (At Synology following header: Upgrade $http_upgrade AND Connection $connection_upgrade)
Example
Browser calls http://app1.my-example.com/
re-direct to https://app1.my-example.com:30000/
Browser displays: https://app1.my-example.com/, resolving via Port 30000
Current Code (not working so far)
# Test
server {
listen 8080;
server_name ~^(.*)\.my\-example.com$;
access_log /opt/bitnami/nginx/logs/yourapp_access.log;
error_log /opt/bitnami/nginx/logs/yourapp_error.log;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass https://$host:30000$request_uri/;
proxy_redirect off;
}
}
# Catch malicious requests
server {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
return 444;
}
I was able to solve my issue and would like to share the results. The only thing I do not get is, why redirect.my-example is OK as proxy_pass. It would hit the very same route (probably an endless-loop). Feedback/Improvement would be apreciated!
# custom code for hop by hop headers
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Upgrade connection
server {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
return 301 https://$host$request_uri;
}
# Redirect Subdomains (incl. Web-Socket)
server {
listen 8443 ssl;
ssl_certificate /certs/server.crt;
ssl_certificate_key /certs/server.key;
server_name my-example.de portal.my-example.de;
access_log /opt/bitnami/nginx/logs/yourapp_access.log;
error_log /opt/bitnami/nginx/logs/yourapp_error.log;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass https://redirect.my-example.de:30000;
proxy_redirect off;
}
}
# Catch malicious requests
server {
listen 8443 default_server;
listen [::]:8443 default_server;
ssl_certificate /certs/server.crt;
ssl_certificate_key /certs/server.key;
server_name _;
return 444;
}

Nginx: WebSocket wildcard location

I use a nginx instance in front of a Go service.
I want to redirect anything on port 80 to https. [done]
All (non-websocket) https requests at /* should go to https://localhost:8443/* [done]
All websocket https requests at /ws/* should go to https://localhost:8443/ws/* [missing]
My current config:
ssl_certificate ...
ssl_certificate_key ...
ssl_ciphers ...
ssl_prefer_server_ciphers on;
server {
listen 80;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name www.mydomain.com mydomain.com;
add_header Strict-Transport-Security "max-age=31536000";
location /ws { <--- This only works for /ws but not /ws/app1
proxy_pass http://localhost:8443/ws;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / { <--- Catches anything, even without wildcard ?!
proxy_pass http://localhost:8443;
}
}
server {
listen 443 ssl;
server_name *.mydomain.com;
return 444;
}
Why is this necessary ? Well, as I understand, you have to set the upgrade headers explicitly, so I guess you have to specify another location.
Ideally, I would just use one location, but then websockets are blocked (because upgrade headers never make it to the Go service...)
I'm not a nginx expert, so bear with me =).
[EDIT]
I got it working now. I'm not sure if its ok to always set_header Upgrade/Connection, even if it's not a websocket request, but my Go service doesn't give a ****, so it works for me =]
ssl_certificate ...
ssl_certificate_key ...
ssl_ciphers ...
ssl_prefer_server_ciphers on;
server {
listen 80;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name www.mydomain.com mydomain.com;
add_header Strict-Transport-Security "max-age=31536000";
location / { <--- Catches anything, even without wildcard ?!
proxy_pass http://localhost:8443;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
server {
listen 443 ssl;
server_name *.mydomain.com;
return 444;
}
Check out the article at https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms
You are not using any location_match, so the match is a prefix match.
Use ~ as the location match modifier to have it interpreted as a regular expression.
The line location /ws should match every query starting with /ws.

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.

Resources