发布于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;
}
}- 关于
default_server的用法,可参考NGINX文档[ngx_http_core_module.html#listen]。 - 关于
server_name的用法,可参考NGINX文档[ngx_http_core_module.html#server_name,Server names]。
在上面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 “
Chapter: Miscellaneous names--” and “!@#” may equally be used.
大概意思是:像--(连续的2个连字符)、_、!、@、#等字符是永远都不会出现在域名当中的(参考[Wiki,RFC1035]:所谓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证书申请和配置。