Reputation: 808
I have an api running on localhost. To allow external access to the API under a specific domain path I've set a reverse proxy. This part works fine. Now I'm trying to filter access and allow only a single IP to connect to the API, in other words, deny all IP's connections except from a specific one.
With the configuration bellow all IPs are being blocked successfully, but it's also blocking the one IP I want to allow. I've researched and tried several fixes and I suspect I need to get the real_IP under the reverse proxy, but haven't manage to make it work for my specific situation. All help is appreciated. Here's the code for my nginx config file inside sites-available:
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name foo.com www.foo.com;
location / {
allow XX.XX.XX.XX;
#allow 127.0.0.1;
deny all;
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
listen [::]:443 ssl; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/foo.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/foo.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
}
XX.XX.XX.XX is the ip I want to allow which is actually the server's actual IP. But I don't think it makes a difference. I've also tried adding the following inside "location /{ }" scope, but no luck:
set_real_ip_from XX.XX.XX.XX;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Upvotes: 3
Views: 7379
Reputation: 19372
I don't think it's good idea to put that control to web server level.
Giving access is more firewallish task.
But in some conditions when You want to give access to registered host dynamically without restarting or configuring somethings - it's better to make guard method on app level.
For now I can recommend one of these:
1) Put firewall in front of app or nginx. You may use ufw
2) Put access control to app level. If it's nodejs app write middleware:
middlewares/allowByIp.js
:
'use strict';
cons db = require('../database'); // mongoose models abstraction
const AllowedHosts = db.model('AllowedHost');
module.exports = async (req, res, next) => {
const isAllowed = await AllowedHosts.findOne({ip: req.ip});
if (!isAllowed) {
res.status(403).send('Forbidden');
}
next();
};
or :
'use strict';
cons allowedHosts = [... ip listing ...]; // take care of graceful restarting of Your app when You'll modify this array
module.exports = async (req, res, next) => {
const isAllowed = allowedHosts.includes(req.ip);
if (!isAllowed) {
res.status(403).send('Forbidden');
}
next();
};
in app.js
:
const express = require('express');
const app = express();
const ipFirewall = require('middlewares/allowByIp');
app.use(ipFirewall);
...
app.listen(3000);
I've checked Your nginx example it works as expected.
So I suspect that nginx gets different ip. Check /var/log/nginx/access.log
for real ip address that Your nginx gets when source part does request to destination.
But, if You want to limit access internally, to tell server to use loopback interface in requests to foo.com
then add such line in /etc/hosts
file:
127.0.0.1 foo.com www.foo.com
it will tell Your server to not request DNS server to resolve that hostname which will give global ip and result with request from outside.
Upvotes: 1