NGINX默认站点及自签名SSL证书

发布于2019/12/02更新于2024/7/5

这篇日志记录一些配置NGINX和SSL证书的杂项。主要涉及NGINX的默认站点和SSL自签名证书生成,自己做个备份好查找。

这种情况应当是很常见的,即一台配置了HTTP服务的服务器同时伺服了多个域名(或多个IP)的网站。有时就需要有一个所谓可以catch-all的站点,来为以下这种访问来服务:

  • 所有指向这台服务器的访问;
  • 该访问不在已有提供HTTP服务范围内。

因此,面对各种IP的直接HTTP访问,如果该IP本身没有已部署的服务,则应有一个“默认HTTP站点”响应其请求;面对各种指向该服务器的域名的HTTP访问,如果这些域名没有部署响应的HTTP服务,则应至少有一个“默认HTTP站点”响应其请求。加上现在已是HTTPS的天下,也应使配置兼容通过https://的访问。当然我们可以把这个默认HTTP站点做的很像模像样,但还是考虑到这个默认HTTP站点所响应的页面并不是什么十分正规的页面,甚至根本不希望有人能访问到,所以这个站点的SSL证书就不用大费周章,直接在服务器上生成一个自签名证书就好了。下面的内容,就记录这两点吧。

注意:这篇日志为我记录与获取方便而发布;内容中有很多处未涉及严格的考究和对选择的充分讨论,代码部分亦有存在纰漏的可能;请酌情参考,小心使用!

针对NGINX的默认站点

嗯,搜索一下实际上有很多现成的配置。假设SSL证书和密钥位于:

  • 证书:/etc/nginx/ssl/nginx-selfsigned.crt.pem
  • 密钥:/etc/nginx/ssl/nginx-selfsigned.key.pem

那么,将NGINX默认站点的配置(参考了[Setting Nginx to catch all unhandled vhosts])写在下面:

server {
    # 监听本机所有IPv4地址和IPv6地址的80端口和443端口
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    # 这个叫什么来着?看后面的解释好了。
    server_name _;

    # 通用SSL配置
    include /etc/nginx/ssl/ssl.conf;

    # 证书及密钥配置
    ssl_certificate     /etc/nginx/ssl/nginx-selfsigned.crt.pem;
    ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key.pem;

    # 禁用单独的访问记录
    #access_log /var/log/nginx/host.access.log main;
    #error_log /var/log/nginx/host.log error;

    # 常规配置,亦可直接返回404
    #return 404;
    location / {
        try_files $uri $uri/ =404;
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    # 指定HTTP错误页面
    #error_page  404              /404.html;
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # 常规配置,禁用静态文件的记录等
    location ~* .(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        access_log off;
        log_not_found off;
    }

    # 禁止对以“.ht”开头的文件的访问,兼容Apache目录根,也可算作常规配置
    location ~ /.ht {
        deny all;
    }
}

在上面Server names的文档里有这么一段:

In catch-all server examples the strange name “_” can be seen:

(…)

There is nothing special about this name, it is just one of a myriad of invalid domain names which never intersect with any real name. Other invalid names like “--” and “!@#” may equally be used.

Chapter: Miscellaneous names

大概意思是:像--(连续的2个连字符)、_!@#等字符是永远都不会出现在域名当中的(参考[WikiRFC1035]:所谓LDH即letters字母、digits数字和hyphen连字符;未列出编码Unicode字符的国际化域名的参考),所以这个server块永远不会被真正的域名/IP访问所捕获到,因此也就可以作为一个所谓catch-all的默认站点了。

通用SSL配置/etc/nginx/ssl/ssl.conf,里面的内容大部分复制自Certbot为NGINX生成的配置:

    ssl_session_cache shared:le_nginx_SSL:1m;
    ssl_session_timeout 1440m;
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_stapling on;
    ssl_stapling_verify on;

这儿有一点需要注意的,这个所谓catch-all站点的SSL配置会覆盖其它站点的SSL配置。比如,如果为该catch-all站点设置了仅启用TLS v1.2协议(TLSv1.2),那么其它站点可用的SSL协议也就只有TLS v1.2,即使在其它站点配置中再使用ssl_protocols指定其它协议,也不会起任何作用。这可算作NGINX的一个bug吧,至少到nginx/1.18.0(当前版本)还是存在这个问题的。

自签名SSL证书

这部分所做的记录就更简单了,直接参考了Digital Ocean上的文档[1],在Ubuntu中生成自签名SSL证书(需要有openssl库及软件包支持):

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx-selfsigned.key.pem -out /etc/nginx/ssl/nginx-selfsigned.crt.pem

命令参数可参考上面链接的文档,生成证书及私钥文件的位置:

  • 证书:/etc/nginx/ssl/nginx-selfsigned.crt.pem
  • 密钥:/etc/nginx/ssl/nginx-selfsigned.key.pem

此外,还需要为HTTP服务器生成一个Diffie-Hellman参数(DH参数),解释见[2]:

sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

该命令在/etc/nginx/ssl/dhparam.pem生成了长度为2048bit的DH参数。


OK,到这里基本上就写完了。以前比较完整的记录有:NGINX配置Let’s Encrypt SSL证书申请和配置

Leave a Reply

Your email address will not be published. Required fields are marked *