NGINX Unit

使用 Certbot 的 TLS§

若要设置Unit 中的 SSL/TLS 访问,您需要证书包。虽然可以使用自签名证书,但建议从证书颁发机构 (CA) 为您的网站获取证书。为此,您可以使用 EFF 的Certbot,它会签发由Let’s Encrypt(一家非营利性 CA)签名的免费证书。

生成证书§

  1. 在您网站的服务器上安装Unit

  2. 在同一服务器上安装Certbot,在 EFF 网站的软件下拉列表中选择以上都不是,在系统下拉列表中选择服务器的操作系统。

  3. 运行certbot实用程序并按照其说明创建证书包。系统会提示您输入网站的域名并验证域名所有权;后者可以通过不同的方式完成。也许最简单的方法是使用webroot方法,让 Certbot 本地存储某个文件,然后通过您的域名访问该文件。首先,使用 80 端口在 Unit 中配置一个临时路由

    {
        "listeners": {
            "*:80": {
                "pass": "routes/acme"
            }
        },
    
        "routes": {
            "acme": [
                {
                    "match": {
                        "uri": "/.well-known/acme-challenge/*"
                    },
    
                    "action": {
                        "share": "/var/www/www.example.com$uri/"
                    }
                }
            ]
        }
    }
    

    确保share目录对 Unit 的路由器进程用户帐户(通常为unit:unit)可访问。

    接下来,运行 certbot,提供 share 目录作为 webroot 路径

    # certbot certonly --webroot -w /var/www/www.example.com/ -d www.example.com
    

    如果您由于某种原因无法使用前一种方法,请尝试使用 DNS 记录来验证您的域名

    # certbot certonly --manual --preferred-challenges dns -d www.example.com
    

    Certbot 将提供有关更新 DNS 条目以证明域名所有权的说明。

    任何此类 certbot 命令都会将生成的 .pem 文件存储如下

    /etc/letsencrypt/
    └── live/
        └── www.example.com
            ├── cert.pem
            ├── chain.pem
            ├── fullchain.pem
            └── privkey.pem
    

    注意

    Certbot 也提供其他验证方法 (验证器),但为了简洁起见,此处省略了这些方法。

  4. 创建一个适合 Unit 的证书包,并将其上传到 Unit 的 控制 APIcertificates 部分

    # cat /etc/letsencrypt/live/www.example.com/fullchain.pem  \
          /etc/letsencrypt/live/www.example.com/privkey.pem > bundle1.pem
    
    # curl -X PUT --data-binary @bundle1.pem  \
           --unix-socket /path/to/control.unit.sock  \
           http://localhost/certificates/certbot1
    
           {
               "success": "Certificate chain uploaded."
           }
    
  5. 在 Unit 中创建或更新 监听器 以使用上传的包

    # curl -X PUT --data-binary  \
          '{"pass": "applications/ssl_app", "tls": {"certificate": "certbot1"}}'  \
          --unix-socket /path/to/control.unit.sock  \
          'http://localhost/config/listeners/*:443'
    
  6. 尝试通过 HTTPS 访问您的网站

    $ curl https://www.example.com -v
    
          ...
          * TLSv1.3 (OUT), TLS handshake, Client hello (1):
          * TLSv1.3 (IN), TLS handshake, Server hello (2):
          * TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (IN), TLS handshake, Unknown (8):
          * TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (IN), TLS handshake, Certificate (11):
          * TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (IN), TLS handshake, CERT verify (15):
          * TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (IN), TLS handshake, Finished (20):
          * TLSv1.3 (OUT), TLS change cipher, Client hello (1):
          * TLSv1.3 (OUT), TLS Unknown, Certificate Status (22):
          * TLSv1.3 (OUT), TLS handshake, Finished (20):
          * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
          * ALPN, server did not agree to a protocol
          * Server certificate:
          *  subject: CN=www.example.com
          *  start date: Sep 21 22:10:42 2020 GMT
          *  expire date: Dec 20 22:10:42 2020 GMT
          ...
    

续订证书§

Certbot 允许手动或 自动续订证书 手动。对于手动续订和更新

  1. 重复上述步骤以续订证书,并以不同的名称上传新包

    # certbot certonly --standalone
    
          What would you like to do?
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          1: Keep the existing certificate for now
          2: Renew & replace the cert (may be subject to CA rate limits)
    
    # cat /etc/letsencrypt/live/www.example.com/fullchain.pem  \
          /etc/letsencrypt/live/www.example.com/privkey.pem > bundle2.pem
    
    # curl -X PUT --data-binary @bundle2.pem  \
           --unix-socket /path/to/control.unit.sock  \
           http://localhost/certificates/certbot2
    
           {
               "success": "Certificate chain uploaded."
           }
    

    现在您已上传两个证书包;Unit 将它们识别为 certbot1certbot2。或者,查询 certificates 部分以查看常见详细信息,例如到期日期、主题或颁发者

    # curl --unix-socket /path/to/control.unit.sock  \
           http://localhost/certificates
    
  2. 更新 监听器,将其切换到续订的证书包

    # curl -X PUT --data-binary 'certbot2'  \
          --unix-socket /path/to/control.unit.sock  \
          'http://localhost/config/listeners/*:443/tls/certificate'
    

    注意

    无需关闭 Unit;您的服务器可以在更新期间保持在线状态。

  3. 删除已过期的包

    # curl -X DELETE --unix-socket /path/to/control.unit.sock  \
          'http://localhost/certificates/certbot1'
    
          {
              "success": "Certificate deleted."
          }
    
  4. 您还可以通过为监听器配置多个证书包来利用 Unit 的 SNI 支持。

    假设您已成功使用 Certbot 为两个域名(www.example.comcdn.example.com)获取 Let's Encrypt 证书。首先,使用与之前相同的步骤将它们上传到 Unit

    # cat /etc/letsencrypt/live/cdn.example.com/fullchain.pem  \
          /etc/letsencrypt/live/cdn.example.com/privkey.pem > cdn.example.com.pem
    
    # cat /etc/letsencrypt/live/www.example.com/fullchain.pem  \
          /etc/letsencrypt/live/www.example.com/privkey.pem > www.example.com.pem
    
    
    # curl -X PUT --data-binary @cdn.example.com.pem  \
           --unix-socket /path/to/control.unit.sock  \
           http://localhost/certificates/cdn.example.com
    
           {
               "success": "Certificate chain uploaded."
           }
    
    # curl -X PUT --data-binary @www.example.com.pem  \
           --unix-socket /path/to/control.unit.sock  \
           http://localhost/certificates/www.example.com
    
           {
               "success": "Certificate chain uploaded."
           }
    

    接下来,配置侦听器,为 tls/certificate 选项提供两个捆绑包作为数组值

    # curl -X PUT --data-binary '{"certificate": ["cdn.example.com", "www.example.com"]}'  \
          --unix-socket /path/to/control.unit.sock  \
          'http://localhost/config/listeners/*:443/tls'
    

    Unit 完成其余工作,自动找出为连接到两个域名中的每个传入连接生成哪个捆绑包。

注意

目前,Certbot 没有 安装程序插件,这些插件可以在 Unit 中启用自动证书更新。但是,你可以使用此处列出的命令设置 Certbot 的 挂钩,以达到相同的效果。