Nginx

FreeBSD 上的 Nginx SNI 和 Letsencrypt;錯誤的證書?

  • September 5, 2016

我有一個有 14 個域的 VPS,我設置了letskencrypt 來自動為每個域檢索一個單獨的證書,其中包括所有子域。所以,我有 14 個證書。顯然,將所有域放在一個證書中不是一種選擇,因為很快我將達到 Letsencrypt 的每個證書的最大 100 個域/子域。

所以,我高興了一個月,直到我發現 nginx 為除一個域之外的所有域提供了錯誤的證書(它會自動選擇 - 或者,我將設置 - 作為埠 443 的預設伺服器)。經過一番頭疼後,我發現每個 SSL 證書都必須有自己的 IP,而不是共享 IP。然後我還發現有 SNI 作為解決此問題的方法。

$ nginx -V
TLS SNI support enabled

所以長話短說;問題是無論我做什麼 nginx 頑固地提供錯誤的證書:

$ curl --insecure -v https://babaei.net 2>&1 | awk 'BEGIN { cert=0 } /^\* Server certificate:/ { cert=1 } /^\*/ { if (cert) print }'
* Server certificate:
*  subject: CN=babaei.net
*  start date: Aug 28 13:30:00 2016 GMT
*  expire date: Nov 26 13:30:00 2016 GMT
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Connection #0 to host babaei.net left intact

$ curl --insecure -v https://learnmyway.net 2>&1 | awk 'BEGIN { cert=0 } /^\* Server certificate:/ { cert=1 } /^\*/ { if (cert) print }'
* Server certificate:
*  subject: CN=babaei.net
*  start date: Aug 28 13:30:00 2016 GMT
*  expire date: Nov 26 13:30:00 2016 GMT
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Connection #0 to host learnmyway.net left intact

$ curl --insecure -v https://3rr0r.org 2>&1 | awk 'BEGIN { cert=0 } /^\* Server certificate:/ { cert=1 } /^\*/ { if (cert) print }'
* Server certificate:
*  subject: CN=babaei.net
*  start date: Aug 28 13:30:00 2016 GMT
*  expire date: Nov 26 13:30:00 2016 GMT
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Connection #0 to host 3rr0r.org left intact

而且,不要誤會我的意思,實際的證書應該是:

$ openssl x509 -noout -subject -in /path/to/certs/babaei.net.pem
subject= /CN=babaei.net

$ openssl x509 -noout -subject -in /path/to/certs/learnmyway.net.pem
subject= /CN=learnmyway.net

$ openssl x509 -noout -subject -in /path/to/certs/3rr0r.org.pem
subject= /CN=3rr0r.org

因此,假設我們有兩個域 alpha.com 和 omega.com。您將如何配置啟用 SNI 的 nginx 來為每個伺服器提供正確的 SSL 證書?

server {
 server_tokens  off;

 listen  443 ssl http2;
 listen  [::]:443 ssl http2;
 server_name  www.alpha.com;

 ssl  on;
 ssl_certificate  /path/to/alpha.com/cert.pem;
 ssl_certificate_key /path/to/alpha.com/key.pem;
}

server {
 server_tokens  off;

 listen  443 ssl http2;
 listen  [::]:443 ssl http2;
 server_name  www.omega.com;

 ssl  on;
 ssl_certificate  /path/to/omega.com/cert.pem;
 ssl_certificate_key /path/to/omega.com/key.pem;
}

謝謝

更新:這是原始配置:

server {
   server_tokens   off;

   listen          80;
   listen          [::]:80;
   server_name     learnmyway.net;

   location / {
       return 301 https://www.$server_name$request_uri;  # enforce https / www
   }

   # Error Pages
   include /path/to/snippets/error;

   # Anti-DDoS
   include /path/to/snippets/anti-ddos;

   # letsencrypt acme challenges
   include /path/to/snippets/letsencrypt-acme-challenge;
}

server {
   server_tokens   off;

   listen          80;
   listen          [::]:80;
   server_name     *.learnmyway.net;

   location / {
       return 301 https://$host$request_uri;  # enforce https
   }

   # Error Pages
   include /path/to/snippets/error;

   # Anti-DDoS
   include /path/to/snippets/anti-ddos;

   # letsencrypt acme challenges
   include /path/to/snippets/letsencrypt-acme-challenge;
}


server {
   server_tokens   off;

   listen          443 ssl http2;
   listen          [::]:443 ssl http2;
   server_name     www.learnmyway.net;

   # Hardened SSL
   include                 /path/to/snippets/hardened-ssl;
   ssl_certificate         /path/to/certs/learnmyway.net.pem;
   ssl_certificate_key     /path/to/keys/learnmyway.net.pem;
   ssl_trusted_certificate /path/to/certs/learnmyway.net.pem;

   #error_log      /path/to/learnmyway.net/log/www_error_log;
   #access_log     /path/to/learnmyway.net/log/www_access_log;

   root            /path/to/learnmyway.net/www/;
   index           index.html;

   # Error Pages
   include         /path/to/snippets/error;

   # Anti-DDoS
   include         /path/to/snippets/anti-ddos;

   # letsencrypt acme challenges
   include /path/to/snippets/letsencrypt-acme-challenge;

   # Compression
   include         /path/to/snippets/compression;

   # Static Resource Caching
   include         /path/to/snippets/static-resource-caching;
}

看起來@AlexeyTen 是對的。添加以下伺服器塊解決了該問題:

server {
   server_tokens   off;

   listen          443 ssl http2;
   listen          [::]:443 ssl http2;
   server_name     learnmyway.net;

   # Hardened SSL
   include                 /path/to/snippets/hardened-ssl;
   ssl_certificate         /path/to/certs/learnmyway.net.pem;
   ssl_certificate_key     /path/to/keys/learnmyway.net.pem;
   ssl_trusted_certificate /path/to/certs/learnmyway.net.pem;

   return 301 https://www.$server_name$request_uri;  # enforce www
}

我的錯誤:由於 * 是萬用字元,我認為 *.learnmyway.net 也會解析 learnmyway.net。看來我錯了。

引用自:https://serverfault.com/questions/799696