I run a few services on my Raspberry Pi, such as Mealie and Calibre-Web, which I want to be able to access when I’m away from home. I therefore use Nginx Proxy Manager to act as a reverse proxy, to make them available outside of my home network. However, in doing so, I’m also exposing them to the whole world wide web, including potential bad actors. So, as a security measure, I’m using an access list in Nginx Proxy Manager to restrict access to certain IP ranges.
The screenshot above shows what I’ve set up. Essentially, I’ve put in the IP ranges that I am likely to use on an ‘allow list’, and then all other IP ranges are blocked. These IP ranges include:
- My current ISP
- My mobile provider
- My workplace
- 192.168.x.x for local connections
Any other IP address will just receive a 403 error from Nginx when they try to connect, and the requests won’t be forwarded on to the underlying app (e.g. Mealie). In other words, Nginx acts like a web application firewall. This builds on Nginx Proxy Manager’s ‘block common exploits’ feature to protect the web services you have running on your system. It’s also much safer that simply opening a port on your router directly to the underlying app.
By using IP ranges, it means that I don’t have to manually specify lots of individual IP addresses, should the one I use change.
CIDR notation
You may have noticed the /16 on the end of each IP address. This is ‘Classless Inter-Domain Routing‘ notation, or CIDR, which is apparently pronounced ‘cider’. Take for example 192.168.x.x/24 – this means that I’m allowing anything from 192.168.0.0 to 192.168.255.255.
If I wanted to, I could narrow this down to 192.168.0.x by using 192.168.0.0/24. Using ‘/24’ rather than ‘/16’ specifies a narrower range of IP addresses. Getting my head around CIDR notation was probably the hardest part of this; I ended up asking ChatGPT to explain it to me as I couldn’t find an actual web site that explained it in simple enough terms. Annoyingly, we didn’t cover this sort of thing in my Computer Science degree.
How to set up an Access List in NPM
In Nginx Proxy Manager, go to the ‘Access Lists’ tab at the top, and click ‘Add Access List’. You’ll then be asked to give it a name – I’ve just called mine ‘Standard list’ but you do you. On the next tab, you can optionally set a username and password; this will mean users will have to authenticate using HTTP Basic access authentication in addition to any required login for your chosen web service.
The ‘Access’ tab is where you specify the IP addresses or ranges. As per the screenshot above, you need to list the IP addresses that you want to allow first, and then have the last line as ‘deny’ and ‘all’ to block all other IP address. Once you’re done adding, save the list.
Go back to your Proxy Hosts page, and edit each one in turn (if you have set up more than one proxy host). On the first tab, at the bottom, you should now be able to select your newly created access list. You can apply the same access list to multiple proxy hosts, if you want to apply the same restrictions to all of them.
Hopefully now, with huge swathes of the Internet blocked by nginx, I’ll be less at risk should someone find an exploitable vulnerability in Mealie or Calibre-web.
