Block direct IP access with NGINX with site behind Cloudflare - nginx

I'm trying to block direct IP access with NGINX.
I added the following block
server {
listen 80 default_server;
server_name "";
return 444;
}
I have another server block
server {
listen 80;
server_name aaa.domain.com
...
}
The problem is that after adding the server block for refusing direct IP access, I can no longer access my website via aaa.domain.com
It seems the first server block is catching all requests.
Note, I'm using Cloudflare, and I wonder if it might be related? Perhaps NGINX detects the incoming request from Cloudflare as being of direct IP access and blocks it? If so, how could I solve this?
If it matters, the above server blocks are on different files located in sites-enabled dir.

Cloudflare give the list of IP and ranges. You deny all and you accept traffic from these IPs, and it will work -> https://serverfault.com/questions/601339/how-do-i-deny-all-requests-not-from-cloudflare

Related

NGINX reverse proxy not redirecting to HTTP. All traffic forced to HTTPS

I recently setup NGINX for the purpose of directing 2 domains I own to 2 different servers on my network, utilizing the same WAN address.
I currently have my firewall rules setup to simply pass port 80 traffic to the IP of my NGINX server.
Utilizing the following conf file with NGINX, ALL attempts to connect to any of my previously accessible sites now forces the URL typed into the browser to immediately change to HTTPS which is not what I want.
server {
listen 80;
server_name www.domain1.net domain1.net;
location /{
proxy_pass http://192.168.50.226:8080;
}
}
server {
listen 80;
server_name www.domain2.net domain2.net;
location /{
proxy_pass http://192.168.50.35:8080;
}
}
The good news is that both domains are resolving to my WAN address which addressed my first problem. I now want them to natively go to their respective HTTP address, rather than it's current behavior of switching to HTTPS.
For those that may run into a similar issue. If using pfsense or similar technologies for your router, I found the issue to be was that the router was using port 80 as well for it's web gui, which was then forcing http traffic to then use https. After change the router default GUI port to 8080, everything feel into place and started working.

Redirect to internal local ip and port without using /etc/hosts (nginx)

I have a diy (poor man's) NAS and I can access the file-browser in my home-network by using the ip: 192.168.0.2:1111
I could modify the /etc/hosts in each of my devices to redirect my-fancy-filebrowser-url.com to 192.168.0.2:1111.
However, I want to find an alternative that does not involve modifying the /etc/hosts of each device in my network. I do not want to set up a local dns server either as it will probably slow down the resolution of internet domains, I am using 8.8.8.8 or 1.1.1.1 to resolve domain names quicker.
One of those alternatives I found out, is by using nginx. I have purchased a domain name, let's call it mydomain.com and I have an ipv6 VPS server. I have used cloudflare to redirect a url to my server ipv6 address and I have installed nginx to my VPS and I have created this config file:
http {
# redirect to my router page
server {
listen [d6b6:8760:97ec:ea7a:562c:c954:bb8d:6e41]:80;
return 302 http://192.168.0.1;
}
# redirect to filebrowser
server {
listen [d6b6:8760:97ec:ea7a:562c:c954:bb8d:6e42]:80;
return 302 http://192.168.0.2:1111;
}
}
The redirect to my router admin page is working perfectly as expected (for anyone interested I pointed cloudflare subdomain.mydomain.com to the ipv6 address). But the filebrowser one is not. I suspect it is because I am trying to specify a port to redirect to. Is it possible to do something like this with nginx? Or is there any better alternative that does not involve modifying /etc/hosts or setting your own dns server?
Edit: my bad, I was actually inputting the ipv6 address incorrectly in cloudflare. It was missing 1 digit so it was never going to work. I corrected the ip and it works good. The accepted answer does it more cleverly with urls instead of hardcoding the ipv6 which is a good idea! Just note that if you are using a ipv6 server then you are going to listen in the [::]:80 port
Remove the IPv6 addresses in the listen directive and add server_name directives instead:
http {
# redirect to my router page
server {
listen 80;
server_name router.mydomain.com;
return 302 http://192.168.0.1;
}
# redirect to filebrowser
server {
listen 80;
server_name filebrowser.mydomain.com;
return 302 http://192.168.0.2:1111;
}
}
I do not want to set up a local dns server either as it will probably slow down the resolution of internet domains
This is probably a wrong assumption. Something like dnsmasq is able to resolve local names and forward all other DNS queries to upstream servers (like 8.8.8.8 or 1.1.1.1), caching the results. So when setup properly you wouldn't need a domain or a VPS in this case.

How to prevent nginx from responding on a specific subdomain

I have a website (with a slightly naughty name), and I'd like to have a dedicated ssh subdomain, in which there would be no website, but I can use for ssh.
How do I prevent nginx from serving my website on this domain?
As a side question, how do I deny ssh access to the base domain?
How do I prevent nginx from serving my website on this domain?
I typically set up the default server to be IP-based and return 404, then add vhosts for the specific domains I want:
server {
listen *:80 default_server;
return 404;
}
server {
listen *:80;
server_name bar.com;
...
}
Then, even if you have other subdomains pointing to the same IP, no web pages will be served for them.
As a side question, how do I deny ssh access to the base domain?
Unless you have two different IP addresses, putting your SSH on a subdomain isn't going to accomplish much because SSH doesn't have the concept of vhosts. I.e., the two domains will point to the same IP and the SSH service will listen for all connections on that IP.

Allow access from one domain with NGINX

I'm looking for a solution to prevent hot-linking with NGINX for JWPlayer. Say I have a NGINX server configured as a reverse proxy at http://mydomain1.com, I'll get the url http://mydomain1.com/file.mp4 to put on my website hosted on another VPS at http://mydomain2.com. How do I restrict the file so it can be played on http://mydomain2.com only and nowhere else?
I tried allow & deny directives but then I realized this is a HTML5 streaming so the directives will block the stream to users.
On nginx of mydomain1.com. Make sure you have one additional block which listens to default host and deny all traffic. Then in the existing listen block we add a rule to allow only www.mydomain2.com
map $http_referer $not_allowed {
default 0;
"~www.mydomain2.com" 1;
}
server {
listen 80 default_server;
server_name _;
deny all;
}
server {
listen 80;
server_name www.mydomain1.com
location / {
if ($not_allowed)
{
return 404 "Not sure its there";
}
}
}
Because the mp4 url will be put in a HTML5 player, this means the remote address (user's machine) will always communicate directly with the reverse proxy. So that's impossible to restrict the access using other methods except nginx secure link module. With this module I'm now able to restrict the access basing on the user's ip, expiration time, url and a secret word.

Nginx: Can I `deny some-port` (not an IP) in a location?

In Nginx, can one somehow block or allow access from certain ports, in a location? Looking at the allow & deny docs it seems to me that they cannot be used for this purpose. Right? But is there no other way to do this?
Background:
In an Nginx virtual host, I'm allowing only a certain IP to publish websocket events:
server {
listen 80;
location /websocket/publish {
allow 192.168.0.123;
deny all;
}
However, soon the IP address of the appserver will we unknown, because everything will run inside Docker and I think I'll have no idea which ip a certain container will have.
So I'm thinking I could do this instead:
server {
listen 80;
listen 81;
location /websocket/publish {
# Let the appserver publish via port 81.
allow :81; # <–– "invalid parameter" error
# Block everything else, so browsers cannot publish via port 80.
deny all;
}
... other locations, accessible via port 80
And then have the firewall block traffic to port 81 from the outside world. But allow :81 doesn't work. Is there no other way? Or am I on the wrong track; are there better ways to do all this?
(As far as I've understood from the docs about the websocket Nginx plugin I use (namely Nchan) I cannot add the /websocket/publish endpoint in another server { } block that listens on port 81 only. Edit: Turns out I can just use different server blocks, because Nchan apparently ignores in which server block I place the config stuff, see: https://github.com/slact/nchan/issues/157. So I did that, works fine for me now. However would still be interesting to know if Nginx supports blocking a port in a location { ... }. )

Resources