NGINX - 无法验证第一个证书

NGINX - Unable to verify the first certificate

我在没有 docker 的同一台服务器上安装了 Nextcloud (21.0.3) 和 Onlyoffice Documents Server (6.3.2.2)。我只使用 nginx 作为网络服务器。 SSL证书来自欧洲SSL。

Nextcloud 和 Document Server 它们有不同的域名 -> cloud.xxx.com 和 office.xxx.com。但是,如果我尝试通过 Nextcloud Onlyoffice 应用程序连接文档服务器,我会收到以下错误消息: 尝试连接时出错(文档服务出错:下载要转换的文档文件时出错。)(版本6.3.2.2)

如果我在网络浏览器上打开 cloud.xxx.com,则没有 ssl 问题。

来自 Onlyoffice 文档服务器的日志文件说:

[2021-08-18T07:56:40.881] [ERROR] nodeJS - error downloadFile:url=https://cloud.xxx.com/apps/onlyoffice/empty?doc=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhY3Rpb24iOiJlbXB0eSJ9.OYLklS-dJKtf0drJmWQgzxPrEWCQwir10jCIM5r_SMc;attempt=3;code:UNABLE_TO_VERIFY_LEAF_SIGNATURE;connect:null;(id=conv_check_363560041_docx)
Error: unable to verify the first certificate
    at TLSSocket.onConnectSecure (_tls_wrap.js:1088:34)
    at TLSSocket.emit (events.js:198:13)
    at TLSSocket._finishInit (_tls_wrap.js:666:8)

如果我运行 openssl s_client -connect cloud.xxx.com:443

CONNECTED(00000003)
depth=0 CN = *.xxx.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = *.xxx.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:CN = *.xxx.com
   i:C = DE, ST = Baden-W\C3\BCrttemberg, L = Durmersheim, O = EUNETIC GmbH, CN = EuropeanSSL Server CA 2
---
Server certificate
-----BEGIN CERTIFICATE-----
xxxxx
xxxxx
xxxxx
-----END CERTIFICATE-----
subject=CN = *.xxx.com

issuer=C = DE, ST = Baden-W\C3\BCrttemberg, L = Durmersheim, O = EUNETIC GmbH, CN = EuropeanSSL Server CA 2

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 2177 bytes and written 404 bytes
Verification error: unable to verify the first certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: xxxxxxxxxxxxx
    Session-ID-ctx:
    Master-Key: xxxxxxxxxxxxx
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    xxxxxxxxxxxxx

    Start Time: 1629275069
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
    Extended master secret: yes

运行 wget https://cloud.xxx.com:

--2021-08-18 08:28:05--  https://cloud.xxx.com/
Resolving cloud.xxx.com (cloud.xxx.com)... xx.xx.xx.xx
Connecting to cloud.xxx.com (cloud.xxx.com)|xx.xx.xx.xx|:443... connected.
ERROR: cannot verify cloud.xxx.com's certificate, issued by ‘CN=EuropeanSSL Server CA 2,O=EUNETIC GmbH,L=Durmersheim,ST=Baden-W\C3\BCrttemberg,C=DE’:
  Unable to locally verify the issuer's authority.
To connect to cloud.xxx.com insecurely, use `--no-check-certificate'.

Nextcloud 的 NGINX 配置:

 upstream php-handler {
      server 127.0.0.1:9000;
      # Depending on your used PHP version
      server unix:/var/run/php7.4-fpm.sock;
  }

  server {
      listen 80;
      server_name cloud.xxx.com;
      return 301 https://$server_name$request_uri;
  }

  server {
      listen 443 ssl;
      server_name cloud.xxx.com;

      ssl_certificate     /etc/nginx/ssl/xxx.com.crt;
          ssl_certificate_key /etc/nginx/ssl/xxx.com.key;
          ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
          ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AE>
          ssl_prefer_server_ciphers on;
          ssl_session_cache shared:SSL:10m;

      # Add headers to serve security related headers
      # The always parameter ensures that the header is set for all responses, including internally generated error responses.
      # Before enabling Strict-Transport-Security headers please read into this topic first.
      # https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/

      #add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" always;
      add_header Strict-Transport-Security max-age=63072000;
      add_header X-Content-Type-Options nosniff always;
      add_header X-Frame-Options "SAMEORIGIN" always;
      add_header X-XSS-Protection "1; mode=block" always;
      add_header X-Robots-Tag none always;
      add_header X-Download-Options noopen always;
      add_header X-Permitted-Cross-Domain-Policies none always;
      add_header Referrer-Policy 'no-referrer';

      # Path to the root of your installation
      root /var/www/nextcloud/;

      location = /robots.txt {
          allow all;
          log_not_found off;
          access_log off;
      }

      # The following 2 rules are only needed for the user_webfinger app.
      # Uncomment it if you're planning to use this app.

      #rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
      #rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;

      location = /.well-known/carddav {
          return 301 $scheme://$host/remote.php/dav;
      }
      location = /.well-known/caldav {
          return 301 $scheme://$host/remote.php/dav;
      }

      # set max upload size
      client_max_body_size 512M;
      fastcgi_buffers 8 4K;                     # Please see note 1
      fastcgi_ignore_headers X-Accel-Buffering; # Please see note 2

      # Disable gzip to avoid the removal of the ETag header
      # Enabling gzip would also make your server vulnerable to BREACH
      # if no additional measures are done. See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=773332
      gzip off;

我将 xxx.com.crt 文件保存到 /usr/local/share/ca-certificates/ 和 运行 sudo dpkg-reconfigure ca-certificates 之后 wget 没有显示任何错误。

但是在来自 Onlyoffice Documents Server 的日志文件中它仍然显示“错误:无法验证第一个证书

有人可以帮我解决这个问题吗?

很可能您在证书链中缺少中间证书。

nginx 不像 apache 那样支持提供多个证书,因此您必须自己链接证书。

cd /etc/nginx/ssl/
cat xxx.com.crt intermediate.crt > xxx.com-chain.crt

然后您可以 link ssl_certificate 中的链文件。如果需要,您的供应商应该已经向您发送了中间证书,或者在其网站上提供。

比如letsencrypt颁发的证书需要链中的两个中间证书,所以grep '--BEGIN CERTIFICATE--' xxx.com-chain.crt | wc -l会导致3...