«

Nginx只允许域名访问网站

冰城心无泪 发布于 阅读:2765 Linux应用


缘由

当我们部署完Nginx后,默认情况下,用Nginx服务器IP及解析到此IP的域名都可以访问本服务器,这里面就包括我们自己已备案的域名以及未备案恶意解析到我们服务器IP的域名, 网监大队在巡查的时候,发现非正常域名解析,将会封禁被解析的IP。为啥不封禁域名解析?域名注册商在国外的咋封,所以只能是封我们的IP。这个时候,我们就需要做一些策略,只允许指定的域名访问,防止恶意绑定的域名来访问我们服务器。

方式一 在server段里面加上一段if正则表达式

只允许单一域名访问,其他方式访问返回444(非标准状态码444,表示关闭连接且不给客户端发响应头),配置如下

user  root;
worker_processes  2;

events {
    worker_connections  1024;
}

http {
   include       mime.types;
   default_type  application/octet-stream;
   server_tokens off;
   sendfile       on;
   gzip on;
   keepalive_timeout  65;
   client_max_body_size 2048m;

    server {
        listen 80;
        server_name www.domain_name.com;

        if ($host != 'www.domain_name.com'){
            return 444;
        }

        location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm index.php;
    }
}

如果你的网站还开启了SSL,完整的配置文件可以配置如下

user  root;
worker_processes  2;

events {
    worker_connections  1024;
}

http {
   include       mime.types;
   default_type  application/octet-stream;
   server_tokens off;
   sendfile       on;
   gzip on;
   keepalive_timeout  65;
   client_max_body_size 2048m;

    server {
        listen 80;
        server_name www.domain_name.com;
        rewrite ^(.*)$  https://$host$1 permanent;

        location / {
            root   /html;
            index  index.html index.htm index.php;
        }

    server {
        listen       443 ssl http2;
        server_name  www.domain_name.com;

        if ($host != 'www.domain_name.com'){
            return 444;
        }

        charset utf-8;
        #证书的目录及文件名称根据实际修改
        ssl_certificate /Nginx/ssl/www.domain_name.com_chain.crt;
        ssl_certificate_key /Nginx/ssl/www.domain_name.com_key.key;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 5m;
        #如果你是使用Openss 1.1.1*版本编译的Nginx,SSL协议可以支持TLSv1.3.
        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_ciphers ECDH:AESGCM:HIGH:!RC4:!DH:!MD5:!3DES:!aNULL:!eNULL;
        #如果你ssl协议只开启支持tlsv1.2 tlsv1.3新协议,建议使用以下加密套件
        #ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        #如果ssl协议只支持tlsv1.2 tlsv1.3新协议,设置为 off,如果ssl协议支持tlsv1 tls1.1这种老协议,设置为 on,默认为off,因为新协议不再采纳此参数
        ssl_prefer_server_ciphers on;
        add_header Strict-Transport-Security "max-age=63072000" always;

        location / {
            root   html;
            index  index.html index.htm;
            try_files $uri $uri/ @router;
        }
    }
}

方式二 允许多个域名访问

我们在备案的时候,默认是www.domain_name.com,但是我们在解析的时候,希望www.domain_name.com及domain_name.com都可以解析到我们服务器,这个时候用if正则表达式有点不妥,所以就换个方法,添加一个server段,记住是添加,不是在原server段里面改,配置如下

user  root;
worker_processes  2;

events {
    worker_connections  1024;
}

http {
   include       mime.types;
   default_type  application/octet-stream;
   server_tokens off;
   sendfile       on;
   gzip on;
   keepalive_timeout  65;
   client_max_body_size 2048m;

    #下面这段server是新加的
    server {
        listen       80  default_server;
        # 下面是无效域名的处理。所有无效域名,返回444
        server_name  _;
        return       444;
    }

    server {
        listen 80;
        server_name www.domain_name.com domain_name.com;

        location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm index.php;
    }
}

如果你的网站还开启了SSL,完整的配置文件可以配置如下

user  root;
worker_processes  2;

events {
    worker_connections  1024;
}

http {
   include       mime.types;
   default_type  application/octet-stream;
   server_tokens off;
   sendfile       on;
   gzip on;
   keepalive_timeout  65;
   client_max_body_size 2048m;

    #下面这段server是新加的
    server {
        listen       80  default_server;
        listen  443  ssl default_server;
        # 下面是无效域名的处理。所有无效域名,返回444
        server_name  _;
        return       444;
        #证书的目录及文件名称根据实际修改
        ssl_certificate /Nginx/ssl/www.domain_name.com_chain.crt;
        ssl_certificate_key /Nginx/ssl/www.domain_name.com_key.key;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 5m;
        #如果你是使用Openss 1.1.1*版本编译的Nginx,SSL协议可以支持TLSv1.3.
        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_ciphers ECDH:AESGCM:HIGH:!RC4:!DH:!MD5:!3DES:!aNULL:!eNULL;
        #如果你ssl协议只开启支持tlsv1.2 tlsv1.3新协议,建议使用以下加密套件
        #ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        #如果ssl协议只支持tlsv1.2 tlsv1.3新协议,设置为 off,如果ssl协议支持tlsv1 tls1.1这种老协议,设置为 on,默认为off,因为新协议不再采纳此参数
        ssl_prefer_server_ciphers on;
    }

    server {
        listen 80;
        #多个域名用空格隔开。
        server_name www.domain_name.com domain_name.com;
        rewrite ^(.*)$  https://$host$1 permanent;

        location / {
            root   /html;
            index  index.html index.htm index.php;
        }

    server {
        listen       443 ssl http2;
        #多个域名用空格隔开。
        server_name  www.domain_name.com domain_name.com;
        charset utf-8;
        #证书的目录及文件名称根据实际修改
        ssl_certificate /Nginx/ssl/www.domain_name.com_chain.crt;
        ssl_certificate_key /Nginx/ssl/www.domain_name.com_key.key;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_ciphers ECDH:AESGCM:HIGH:!RC4:!DH:!MD5:!3DES:!aNULL:!eNULL;
        #如果你ssl协议只开启支持tlsv1.2 tlsv1.3新协议,建议使用以下加密套件
        #ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        #如果ssl协议只支持tlsv1.2 tlsv1.3新协议,设置为 off,如果ssl协议支持tlsv1 tls1.1这种老协议,设置为 on,默认为off,因为新协议不再采纳此参数
        ssl_prefer_server_ciphers on;

        location / {
            root   html;
            index  index.html index.htm;
            try_files $uri $uri/ @router;
        }
    }
}

疑点解释

无效于域名处理"servername ;"中的“_”是啥意思

官网解释:这个名字并没有什么特别之处,它只是众多无效域名中的一个,这些域名从未与任何真实名称相交。也可以使用其他无效名称,如“-”和“!@#”。

其中,“众多无效域名”、“真实名称”是什么意思,什么是无效的,什么是真实的。除去我们配置了的server_name(www.domain_name.com及domain_name.com),其他的都是无效的,也就是说,只有我们配置的域名来访问网站的时候才能正常访问,其他“众多无效域名”、“不真实的域名”来访问我们网站的时候,都会按照我们配置的规则,返回444(关闭连接且不给客户端发响应头).下划线也可以用其他无效名称代替,如“-”和“!@#”或空字符“”。

关于在新加的server段配置SSL证书

Nginx上对于用到SSL协议的虚拟主机,在访问的时候会检查SSL协议及证书,不管你是有效域名还是无效域名,虽说是无效的域名都会返回444,但是毕竟开启了443端口,开启了SSL协议。如果你不配置证书,在启动服务的时候,会提示你“no "ssl_certificate" is defined”,服务启动不起来。解决方法就是,要么你自己随便再生成一个证书放进去,要么把你现有的证书放上去,我比较懒,放的自己原有的证书。当然也可以创建自签名证书,注意配置文件中证书的名称。

创建基本的自签名证书
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /Nginx/SSL/Nginx/default.key \
-out /Nginx/SSL/Nginx/default.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=domain_name.com"

或者创建更安全、性能更高的ECC自签名证书
1、生成EC椭圆曲线私钥
openssl ecparam -genkey -name prime256v1 -out /Nginx/SSL/default.key

2、指定使用第一步生成的私钥文件来生成自签名X.509证书
openssl req -x509 -nodes -days 3650 \
-key /Nginx/SSL/default.key \
-out /Nginx/SSL/default.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=domain_name.com"

参数说明
openssl req:用于创建 / 处理证书签名请求(CSR)的工具;
-x509:直接生成自签名证书(而非生成 CSR),适用于测试 / 内部场景;
-nodes:不对私钥加密(避免 Nginx 启动时需要手动输入私钥密码);
-days 3650:证书有效期为 10 年(3650 天);
-key:指定使用第一步生成的私钥文件;
-out:指定生成的证书文件保存路径;
-subj:证书的主题信息(无需交互式输入),各字段含义:
/C=CN:国家代码(中国);
/ST=Beijing:省份 / 州;
/L=Beijing:城市;
/O=MyCompany:组织 / 公司名称;
/OU=IT:部门;
/CN=domain_name.com:(证书绑定的域名 / IP,这里是domain_name.com,你自己本地测试也可以改为localhost,注意此字段规范只支持单个域名。

以上为个人理解,有错误之处,请指出,并邮件给我,本人会认真对待。