简体   繁体   English

在反向代理下仅允许 Nginx 上的单个特定 IP 地址

[英]Allow only a single specific IP address on Nginx under reverse proxy

I have an api running on localhost.我有一个在本地主机上运行的 api。 To allow external access to the API under a specific domain path I've set a reverse proxy.为了允许外部访问特定域路径下的 API,我设置了一个反向代理。 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.现在我正在尝试过滤访问并只允许一个 IP 连接到 API,换句话说,拒绝除特定 IP 之外的所有 IP 连接。

With the configuration bellow all IPs are being blocked successfully, but it's also blocking the one IP I want to allow.通过下面的配置,所有 IP 都被成功阻止,但它也阻止了我想要允许的一个 IP。 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.我已经研究并尝试了几个修复程序,我怀疑我需要在反向代理下获取 real_IP,但还没有设法使其适用于我的特定情况。 All help is appreciated.感谢所有帮助。 Here's the code for my nginx config file inside sites-available:这是我在站点可用的 nginx 配置文件的代码:

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. XX.XX.XX.XX 是我想要允许的 IP,它实际上是服务器的实际 IP。 But I don't think it makes a difference.但我不认为这有什么不同。 I've also tried adding the following inside "location /{ }" scope, but no luck:我还尝试在“location /{ }”范围内添加以下内容,但没有运气:

set_real_ip_from XX.XX.XX.XX;
real_ip_header    X-Forwarded-For;
real_ip_recursive on;

I don't think it's good idea to put that control to web server level.我认为将该控制置于 Web 服务器级别并不是一个好主意。

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. 1) 将防火墙放在 app 或 nginx 前面。 You may use ufw你可以使用ufw

2) Put access control to app level. 2)将访问控制置于应用程序级别。 If it's nodejs app write middleware:如果是 nodejs 应用程序编写中间件:

middlewares/allowByIp.js : 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 :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.我已经检查了您的 nginx 示例,它按预期工作。

So I suspect that nginx gets different ip.所以我怀疑nginx得到了不同的ip。 Check /var/log/nginx/access.log for real ip address that Your nginx gets when source part does request to destination.检查/var/log/nginx/access.log以获取当源部分请求目标时您的 nginx 获得的真实 IP 地址。

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:但是,如果你想在内部限制访问,告诉服务器在对foo.com请求中使用环回接口,然后在/etc/hosts文件中添加这样的行:

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.它会告诉您的服务器不要请求 DNS 服务器来解析该主机名,这将提供全局 ip 并导致来自外部的请求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM