Minimizing my selfhosted attack surface
I'm always fairly wary of opening my selfhosted services up to the internet, just how sure am I that the developer has done the right due-diligence? Thankfully it's relatively simple to at least limit parts of a service accessible to the open internet with Nginx and allow
and deny
options.
Update
Note: If you want a docker container to access a protected service you will have to set the subnet in your docker-compose file as below:
networks: node-red-network: ipam: config: - subnet: "172.16.0.0/24"
Update 2
A more generic change you can do is set the default address pools in docker's /etc/docker/daemon.json
file. You then just have to whitelist 172.16.0.0/16
subnets
{ "default-address-pools": [ {"base":"172.16.0.0/16","size":24} ] }
First you should store this in a file, that way you can then include it multiple times, this will make it trivial to update in the future. Create the file include_whitelist
in your nginx folder, adding your own allow options between satisfy any;
and deny all;
.
satisfy any; # allow localhost allow 127.0.0.1; # allow a single address # allow 000.000.000.000; # allow LAN network allow 192.168.0.0/24; # allow WLAN network allow 192.168.2.0/24; # allow VPN network allow 10.1.4.0/24; # drop rest of the world deny all;
You then have to include the file in your nginx config. Here I am using TT-RSS as an example, Note that I'm excluding the API and the public.php by having it in a separate location block without including the include_whitelist
. This allows me to keep accessing TT-RSS on my mobile phone through the mobile application.
location ^~ /tt-rss/ { include /etc/nginx/include_whitelist; access_log off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://127.0.0.1:8280/tt-rss/; } location ^~ /tt-rss/api { access_log off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://127.0.0.1:8280/tt-rss/api; } location ^~ /tt-rss/public.php { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://127.0.0.1:8280/tt-rss/public.php; }
For Node-Red I wanted an API endpoint for Tasker on my phone. Thankfully this is just as easy to define in Node-red as it is in nginx. In Node-Red open your GET node and just add another folder.
An example of the Node-Red nginx configuration. Again just like the TT-RSS example above, I have excluded an api subdirectory by having a separate location block.
location ^~ /node-red/ { include /etc/nginx/include_whitelist; 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_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_pass http://127.0.0.1:1880/node-red/; } location ^~ /node-red/api/ { 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_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_pass http://127.0.0.1:1880/node-red/api/; }
Now only your API endpoints are globally available. If like me you use a firewall, throwing a convenient geo-block up in front you can lower the exposure a bit more.
Comments