快乐的春饼

Nginx 常用配置和解释

配置文件位置

在 Linux 上,对于作为系统服务的 Nginx,主配置文件路径为/etc/nginx/nginx.conf。为了避免在同一个配置文件里塞入太多内容,我们可以在/etc/nginx/conf.d/中创建不同的 conf 文件,然后在主配置文件中include /etc/nginx/conf.d/*.conf;

配置多个 HTTP 服务

HTTP 的情况

当客户端向服务器发起请求时,会在 HTTP 头部加入 Host 字段,用来向服务器给出所访问的域名。比如在浏览器地址栏中输入 http://example.com 时,Host 的值就为 example.com。这点可以通过浏览器自带的分析工具轻松验证。

因为 HTTP 是明文的,所以 Nginx 直接根据不同 Host 字段区分用户想要访问的服务。配置示例:

server {
    listen 80 default_server; # 设置此服务为默认服务
    server_name _; # 表示不匹配任何域名
    return 444; # Nginx 特有的状态码,直接关闭连接
}

server {
    listen 80; 
    server_name a.example.com;
    return 200 "Server A";
}

server {
    listen 80; 
    server_name b.example.com;
    return 200 "Server B";
}

注意配置中的 default_server,如果我们没有配置一个 default_server,那么 Nginx 默认会使用第一个监听该端口的服务,此例中是 a.example.com。为了安全,当配置多个 HTTP 服务时,应该显式写出 default_server,防止某个服务被意外发现。

HTTPS 的情况

HTTPS 要复杂一点。HTTPS 其实是 HTTP + TLS,TLS 负责加密 HTTP 请求。简单来说,加密原理是非对称加密,在实际传输 HTTP 数据之前,浏览器生成一个临时密钥用于和服务器建立TLS 连接,服务器则返回域名对应的 TLS 证书(包括公钥)。关键在于,服务器必须在和客户端传输实际数据之前,给客户端返回域名对应的 TLS 证书。

从 HTTP 请求方法开始的整个 HTTP 请求都会被加密,所以,Host 参数也会被加密。也就是说,直到客户端和 Nginx 建立 TLS 连接之后,服务器才能看到客户端发送的 Host 请求头。如果仍采用 HTTP 时的方法,服务器在和客户端建立 TLS 连接之后才知道客户端要访问哪个域名,但是建立 TLS 连接时服务器就必须发送域名对应的网站证书给客户端,所以服务器必须在建立 TLS 连接的时候就知道客户端想要访问的域名,否则无法找到正确的证书,TLS 连接无法继续。

好家伙,死锁了。

不过解决方法肯定是有的:客户端在请求和服务器建立 TLS 连接的时候就可以顺带把主机名发送给服务器,这就是 TLS 的 Server Name Indication (SNI) 扩展,RFC 6066 定义。大家可以使用 Wireshark 抓一下 TLS 包试试,能看到其中有 SNI,并且包括了我们请求的域名。

当然,凡事都有代价,使用 SNI 的代价就是主机名是明文的,我们不能悄无声息地在服务器上藏一个有独立域名的 HTTPS 服务了。

那么,不论客户端使用 HTTP 还是 HTTPS 访问,Nginx 都能在第一时间知道客户端访问的具体主机名了。因此,HTTPS 的情况配置起来和 HTTP 的也差不多。

server {
    listen 443 ssl default_server;
    # 如果通过 SNI 发现的域名不匹配,直接关闭连接。该配置项始于 Nginx 1.19.4
    ssl_reject_handshake on;
    server_name _;
    return 444;
}

server {
    listen 443 ssl;
    server_name a.example.com;
    ssl_certificate     A证书路径;
    ssl_certificate_key A私钥路径;
    return 200 "Server A";
}

server {
    listen 443 ssl;
    server_name b.example.com;
    ssl_certificate     B证书路径;
    ssl_certificate_key B私钥路径;
    return 200 "Server B";
}

参考

持续更新中……