Catch specific server on nginx - http

My nginx file looks like:
server {
listen 443 ssl;
server_name local.awesome.com;
ssl_certificate /opt/certs/local.awesome.com.crt;
ssl_certificate_key /opt/certs/local.awesome.com.key;
location / {
root /var/www/awesome.com/public_html/;
index index.html;
}
}
server {
listen 443 ssl;
server_name api.local.awesome.com;
ssl_certificate /opt/certs/local.awesome.com.crt;
ssl_certificate_key /opt/certs/local.awesome.com.key;
root /var/www/api.awesome.com/public_html/;
# Known locations for static resources
location /resources/ {
}
# Process all other requests via JS in index.html
location / {
rewrite .* /index.html;
break;
}
location /api {
rewrite "^/api/(.*)$" /$1 break;
proxy_pass http://api:8001;
}
}
If I query something similar to:
GET https://api.local.awesome.com/api/
This works fine.
I decided to make this accessible globally to share some data.
I'm trying to request:
GET https://192.168.1.3:443/api/
But this doesn't work. It returns HTTP/1.1 404 Not Found.
This request returns 403 Forbidden:
GET https://192.168.1.3:443/
It looks like everything is with authorization here, but I hope that previous request should return something different from Not Found.
What is wrong here and how to replace:
GET https://api.local.awesome.com/api/
with
GET http://192.168.1.3:443/api/
If schema or port are different it's not critical for me.
Any suggestions?
UPDATE:
curl -v http://192.168.1.3/api/
* Trying 192.168.1.3...
* TCP_NODELAY set
* Connected to 192.168.1.3 (192.168.1.3) port 80 (#0)
> GET /api/ HTTP/1.1
> Host: 192.168.1.3
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.13.3
< Date: Fri, 01 Sep 2017 18:55:05 GMT
< Content-Type: text/html
< Content-Length: 185
< Connection: keep-alive
< Location: https://192.168.1.3/api/
<
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.13.3</center>
</body>
</html>
* Connection #0 to host 192.168.1.3 left intact

Change below
listen 443 ssl;
server_name api.local.awesome.com;
to
listen 443 ssl;
listen 80;
server_name api.local.awesome.com _;
or
listen 443 ssl;
listen 80;
server_name api.local.awesome.com 192.168.1.3;
This would allow you to access it using http://192.168.1.3/api/

Related

Location directive doesn't seem to be working for some reason

A few days ago I stumbled upon Nginx inside k8s deployment. As I'm relatively new to Nginx I want to understand how it works - so I made my own dev deployment.
The thing is I can't get my nginx.conf to work as I intended:
When you access the /healthz endpoint, return 200 (health check for the k8s)
Redirect any other http trafic to https
Here's my current nginx.conf:
server {
listen 80;
listen [::]:80;
server_name _;
location /healthz {
return 200 "healthy";
}
return 301 https://$host$request_uri;
access_log off;
error_log /usr/share/nginx/web/logs/http_error.log error;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name company.com;
root /usr/share/nginx/web;
index index.html;
access_log off;
error_log /usr/share/nginx/web/logs/ssl_error.log error;
ssl_certificate /usr/share/nginx/web/cert/company.crt;
ssl_certificate_key /usr/share/nginx/web/cert/company.key;
}
Response I'm getting (I've removed the IP adresses):
[error] 28#28: *2 open() "/usr/share/nginx/web/healthz" failed (2: No such file or directory), client: xx.xx.xx.xx, server: company.com, request: "GET /healthz HTTP/2.0", host: "xx.xx.xx.xx", referrer: "http://xx.xx.xx.xx:80/healthz"
Request is on port 80 to /healthz but instead of returning 200, it gets redirected to the https server where it fails
At this point I really don't know why it doesn't work, so please, even if it's some dumb mistake, please feel free to point it out!
What am I doing wrong here?
All the directives processed by ngx_http_rewrite_module from the server context (including return one) are executed before the same directives from location context. You should define two locations to achieve desired behavior:
server {
listen 80;
listen [::]:80;
server_name _;
access_log off;
error_log /usr/share/nginx/web/logs/http_error.log error;
location / {
return 301 https://$host$request_uri;
}
location /healthz {
return 200 "healthy";
}
}

Nginx - Reverse proxy - 404

Receive 404 error while calling URL - http://10.240.0.133/swagger. Below is the snippet of nginx.conf file, I need to append index.html at end of the URI, so I placed a rewrite rule.
server {
listen 80;
listen [::]:80;
server_name localhost;
server_name 10.240.0.133;
server_name 127.0.0.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
access_log /var/log/nginx/resources-reverse-access.log;
error_log /var/log/nginx/resources-reverse-error.log;
location /swagger {
rewrite ^/swagger/index.html break;
proxy_pass http://52.177.131.103:8082/;
}
}
When I visited the URL - curl -v http://10.240.0.133/swagger
404 is thrown:-
* Trying 10.240.0.133...
* TCP_NODELAY set
* Connected to 10.240.0.133 (10.240.0.133) port 80 (#0)
> GET /swagger HTTP/1.1
> Host: 10.240.0.133
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Server: nginx/1.14.0 (Ubuntu)
< Date: Wed, 18 Mar 2020 14:41:50 GMT
< Content-Length: 0
< Connection: keep-alive
<
* Connection #0 to host 10.240.0.133 left intact
I believe your rewrite rule is incorrect. It should look more like this.
location /swagger {
rewrite ^\/swagger\/?.*?$ /swagger/index.html break;
proxy_pass http://52.177.131.103:8082/;
}
but I believe this still not correct since you have not a set a root directive for this server.

Not allow insecure connections on nginx

I installed certbot certificate for nginx:
sudo certbot --nginx -d example.com
and redirect all http to https:
# Redirect non-https traffic to https
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
It is working from browser, but I still can make insecure connection via
curl --insecure example.com
Here are the main configurations in nginx.conf:
server {
listen 80;
server_name example.com;
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
location / {
root /www/html/;
...
proxy_pass http://127.0.0.1:80;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by
Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/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
proxy_ssl_trusted_certificate /etc/letsencrypt/live/example.com/cert.pem;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
}
When I issue
curl -iI https://example.com, it returns:
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 04 Jul 2018 09:19:35 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 1218
Connection: keep-alive
X-Powered-By: Express
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Last-Modified: Tue, 01 Jul 2018 12:10:25 GMT
ETag: W/"Zwtf1TTMBhoSbg9LZvHbCg=="
Strict-Transport-Security: max-age=31536000; includeSubDomains
it should return HTTP/1.1 301 Moved Permanently, in which user agent may or may not redirect to new location.
use -L or --location switch in your curl command to automatically follow the redirections.
Edit 2018-07-05:
Here are the main configurations in nginx.conf:
Though that's not a bad config, if directive usage is discouraged.
You'd better split the config into two separate server block, one for http, and other for https.
Something like:
server {
listen 80;
server_name example.com;
# log your http request if you need to
error_log /var/log/nginx/example-com_error.log notice;
access_log /var/log/nginx/example-com_access.log combined;
# certbot endpoint
location ~ ^/\.well-known/ {
root /var/www/certbot/;
access_log off;
}
# other requests should end up here
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name example.com;
# log your http request if you need to
error_log /var/log/nginx/example-com_error.log notice;
access_log /var/log/nginx/example-com_access.log combined;
# default document root and document index
root /var/www/html;
index index.html;
# SSL cert, private key, and configurations.
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# https configurations
location / {
proxy_pass http://127.0.0.1:80; # why would you proxy_pass back to nginx again?
# you only need this if your proxy_pass uses https, not http like this example.
proxy_ssl_trusted_certificate /etc/letsencrypt/live/example.com/cert.pem;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
}
}
should suffice.
When I issue curl -iI https://example.com, it returns:
yes, why it wouldn't return a HTTP/1.1 200 OK?
The insecure part of --insecure flag in cURL only disables HTTPS certificate validation, i.e. you can use invalid SSL certificate in your HTTPS request (bad CN, bad SAN, bad expiry date, bad CA, self signed, etc) and cURL will still satisfy your request instead of failing hard.

Nginx resolving wrong host when upgrading to HTTPS

I have 3 NGINX hosts, that I only want to serve on HTTPS. Two of them work correctly, however, one of them resolves the wrong host. Here's all of the info
Nginx virtual hosts
# cat alpha.domain-a.tld
server {
listen 80;
server_name alpha.domain-a.tld;
return 301 https://alpha.domain-a.tld$request_uri;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/nginx/certs/alpha.domain-a.tld.pem;
ssl_certificate_key /etc/nginx/certs/alpha.domain-a.tld.key;
ssl_client_certificate /etc/nginx/certs/cloudflare.crt;
ssl_verify_client on;
root /var/www/alpha.domain-a.tld/;
index index.html;
server_name alpha.domain-a.tld;
location / {
try_files $uri $uri/ $uri.html =404;
}
}
# cat mike.domain-a.tld
server {
listen 80;
server_name mike.domain-a.tld;
return 301 https://mike.domain-a.tld$request_uri;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/nginx/certs/domain-a.tld.pem;
ssl_certificate_key /etc/nginx/certs/domain-a.tld.key;
ssl_client_certificate /etc/nginx/certs/cloudflare.crt;
ssl_verify_client on;
root /var/www/mike.domain-a.tld/;
index index.html;
server_name mike.domain-a.tld;
location / {
try_files $uri $uri/ $uri.html =404;
}
}
# cat juliet.domain-b.tld
server {
listen 80;
server_name juliet.dommain-b.tld;
return 301 https://juliet.domain-b.tld$request_uri;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/nginx/certs/domain-b.tld.pem;
ssl_certificate_key /etc/nginx/certs/domain-b.tld.key;
ssl_client_certificate /etc/nginx/certs/cloudflare.crt;
ssl_verify_client on;
root /var/www/juliet.domain-b.tld;
index index.html;
server_name juliet.domain-b.tld;
location / {
try_files $uri $uri/ $uri.html =404;
}
}
Alpha and mike resolve correctly, however, when i try to access http://juliet, it redirects me to alpha rather than https://juliet, as shown below:
# curl -I --resolve alpha.domain-a.tld:80:127.0.0.1 http://alpha.domain-a.tld/
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: #OMMITED
Content-Type: text/html
Content-Length: #OMMITED
Connection: keep-alive
Location: https://alpha.domain-a.tld/
# curl -I --resolve mike.domain-a.tld:80:127.0.0.1 http://mike.domain-a.tld/
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: #OMMITED
Content-Type: text/html
Content-Length: #OMMITED
Connection: keep-alive
Location: https://mike.domain-a.tld/
# curl -I --resolve juliet.domain-b.tld:80:127.0.0.1 http://juliet.domain-b.tld/
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: #OMMITED
Content-Type: text/html
Content-Length: #OMMITED
Connection: keep-alive
Location: https://alpha.domain-a.tld/
Could anyone help me find out why juliet is resolving the first alphanumeric host (alpha) rather than juliet?
Look at the server_name of juliet:
# cat juliet.domain-b.tld
server {
listen 80;
server_name juliet.dommain-b.tld;
return 301 https://juliet.dommain-b.tld$request_uri;
}
juliet.dommain-b.tld probably doesn't exists? I think your curl-command is correct (with the correct url) but in your nginx config you wrote the wrong name. Your nginx server doesn't know the domain but the dns request resolves correctly to your server and so your server returns the first entry of your nginx config.

Nginx - is it possible to redirect to different https servers based on the servername?

Currently , I am redirecting http request this way :
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name emberhub.me www.emberhub.me test.emberhub.me;
return 301 https://$host$request_uri;
}
# HTTPS server static html
#
server {
listen 443 ssl;
server_name emberhub.me www.emberhub.me;
root html;
index index.html index.htm;
ssl on;
....
location / {
try_files $uri $uri/ =404;
# HTTPS server proxy Node.js app
#
server {
listen 444 ssl;
server_name test.emberhub.me;
ssl on;
...
location / {
proxy_pass http://127.0.0.1:8080;
When user request :
http://emberhub.me or http://www.emberhub.me , he is correctly redirected to https://emberhub.me or https://www.emberhub.me ( on default port 443 )
But when user request:
http://test.emberhub.me , he is redirected ALSO to port 443 and get the static html page, not to the node.js app
If the user request it with the port 444
http://test.emberhub.me:444, then he is correctly proxied to the node.js app...
Is there a way to filter the request based on the server_name and redirect it with the correct SSL port ? or is there another better way to perform these redirections ?
thanks for feedback
UPDATE 1 :
I tried to change the server declaratives , as following, but I still get the same issue ... http://test.emberhub.me , is always redirected to port 443
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name emberhub.me;
return 301 https://$host$request_uri;
}
server {
listen 80;
# listen [::]:80 ipv6only=on;
server_name www.emberhub.me;
return 301 https://$host:443$request_uri;
}
server {
listen 80;
# listen [::]:80 ipv6only=on;
server_name test.emberhub.me;
return 301 https://$host:444$request_uri;
}
UPDATE 2
I updated the default config to
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name test.emberhub.me;
return 301 https://$host:444$request_uri;
}
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name emberhub.me www.emberhub.me;
return 301 https://$host$request_uri;
}
using curl -v everything runs fine ...
$ curl -v http://emberhub.me
* Rebuilt URL to: http://emberhub.me/
...
< Connection: keep-alive
< Location: https://emberhub.me/
...
Connection #0 to host emberhub.me left intact
$ curl -v http://www.emberhub.me
...
< Connection: keep-alive
< Location: https://www.emberhub.me/
Connection #0 to host www.emberhub.me left intact
curl -v http://test.emberhub.me
Rebuilt URL to: http://test.emberhub.me/
...
< Location: https://test.emberhub.me:444/
Connection #0 to host test.emberhub.me left intact
BUT requesting http://test.emberhub.me in the browser display https://test.emberhub.me on port 443 ...
If you need different behavior on that server then make a separate config for it:
server {
listen 80;
server_name test.emberhub.me;
return 301 https://$host:444$request_uri;
}

Resources