最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

在Nginx上配置HTTPS證書的完整指南

 更新時間:2026年04月23日 08:54:51   作者:知遠漫談  
在當今互聯(lián)網(wǎng)環(huán)境中,HTTPS 已經(jīng)成為網(wǎng)站標配,無論是個人博客、企業(yè)官網(wǎng)還是 API 服務(wù),啟用 HTTPS 不僅能提升用戶信任度,還能增強數(shù)據(jù)安全性,甚至影響搜索引擎排名,本文將詳細介紹如何在 Nginx 中配置 HTTPS 證書,需要的朋友可以參考下

引言

在當今互聯(lián)網(wǎng)環(huán)境中,HTTPS 已經(jīng)成為網(wǎng)站標配。無論是個人博客、企業(yè)官網(wǎng)還是 API 服務(wù),啟用 HTTPS 不僅能提升用戶信任度,還能增強數(shù)據(jù)安全性,甚至影響搜索引擎排名。Nginx 作為高性能的 Web 服務(wù)器和反向代理,是部署 HTTPS 的理想選擇。本文將詳細介紹如何在 Nginx 中配置 HTTPS 證書,涵蓋自簽名證書、Let’s Encrypt 免費證書、商業(yè)證書等多種方案,并提供 Java 應(yīng)用集成示例。

為什么需要 HTTPS?

在深入配置之前,讓我們先理解為什么 HTTPS 如此重要:

  • 數(shù)據(jù)加密:防止中間人攻擊,保護用戶隱私
  • 身份驗證:確保用戶訪問的是真實的網(wǎng)站而非釣魚網(wǎng)站
  • 完整性保護:防止數(shù)據(jù)在傳輸過程中被篡改
  • SEO 優(yōu)勢:Google 等搜索引擎優(yōu)先收錄 HTTPS 網(wǎng)站
  • 現(xiàn)代瀏覽器要求:Chrome 等瀏覽器對 HTTP 網(wǎng)站標記為"不安全"
// Java 示例:檢測 HTTP/HTTPS 請求
import javax.servlet.http.HttpServletRequest;
public class SecurityUtils {
    public static boolean isSecureRequest(HttpServletRequest request) {
        // 檢查請求是否通過 HTTPS
        if ("https".equals(request.getScheme())) {
            return true;
        }
        // 檢查 X-Forwarded-Proto 頭(當使用反向代理時)
        String forwardedProto = request.getHeader("X-Forwarded-Proto");
        return "https".equals(forwardedProto);
    }
    public static String getSecureUrl(HttpServletRequest request) {
        if (isSecureRequest(request)) {
            return request.getRequestURL().toString();
        } else {
            // 將 HTTP URL 轉(zhuǎn)換為 HTTPS
            String url = request.getRequestURL().toString();
            return url.replaceFirst("http://", "https://");
        }
    }
}

準備工作

在配置 HTTPS 之前,確保你已準備好以下內(nèi)容:

  1. 域名:擁有一個已備案的域名(國內(nèi)服務(wù)器需要)
  2. 服務(wù)器:安裝了 Nginx 的 Linux 服務(wù)器
  3. SSH 訪問權(quán)限:能夠通過 SSH 連接到服務(wù)器
  4. 防火墻配置:開放 443 端口

檢查 Nginx 是否已安裝:

nginx -v

如果未安裝,可以使用以下命令安裝:

# Ubuntu/Debian
sudo apt update
sudo apt install nginx
# CentOS/RHEL
sudo yum install epel-release
sudo yum install nginx

方案一:自簽名證書(開發(fā)測試環(huán)境)

自簽名證書適合開發(fā)和測試環(huán)境,但在生產(chǎn)環(huán)境中瀏覽器會顯示安全警告。

生成自簽名證書

# 創(chuàng)建證書目錄
sudo mkdir -p /etc/nginx/ssl
# 生成私鑰和自簽名證書
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /etc/nginx/ssl/selfsigned.key \
    -out /etc/nginx/ssl/selfsigned.crt \
    -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=example.com"

配置 Nginx 使用自簽名證書

編輯 Nginx 配置文件:

sudo nano /etc/nginx/sites-available/example.com
server {
    listen 443 ssl;
    server_name example.com www.example.com;
    # SSL 配置
    ssl_certificate /etc/nginx/ssl/selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/selfsigned.key;
    # SSL 安全設(shè)置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    # 根目錄和索引文件
    root /var/www/html;
    index index.html index.htm;
    location / {
        try_files $uri $uri/ =404;
    }
}
# HTTP 到 HTTPS 重定向
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

啟用配置并重啟 Nginx

# 創(chuàng)建符號鏈接
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
# 測試配置
sudo nginx -t
# 重啟 Nginx
sudo systemctl restart nginx
// Java 示例:Spring Boot 應(yīng)用中強制 HTTPS
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .requiresChannel()
                .requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null)
                .requiresSecure()
            .and()
            .authorizeRequests()
                .anyRequest().permitAll();
    }
}

方案二:Let’s Encrypt 免費證書(生產(chǎn)環(huán)境推薦)

Let’s Encrypt 提供免費的 SSL/TLS 證書,有效期 90 天,支持自動續(xù)期。

安裝 Certbot

# Ubuntu/Debian
sudo apt update
sudo apt install certbot python3-certbot-nginx
# CentOS/RHEL 7
sudo yum install epel-release
sudo yum install certbot python3-certbot-nginx
# CentOS/RHEL 8+
sudo dnf install certbot python3-certbot-nginx

獲取證書

# 自動獲取并配置證書
sudo certbot --nginx -d example.com -d www.example.com
# 或者僅獲取證書(手動配置)
sudo certbot certonly --nginx -d example.com -d www.example.com

Certbot 會自動修改你的 Nginx 配置文件,添加 SSL 相關(guān)配置。

手動配置 Let’s Encrypt 證書

如果你選擇手動配置,證書文件通常位于:

  • 證書文件:/etc/letsencrypt/live/example.com/fullchain.pem
  • 私鑰文件:/etc/letsencrypt/live/example.com/privkey.pem
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;
    # Let's Encrypt 證書
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    # SSL 安全強化配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    # HSTS (HTTP Strict Transport Security)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    # 其他安全頭
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    # 根目錄
    root /var/www/html;
    index index.html index.htm;
    location / {
        try_files $uri $uri/ =404;
    }
}
# HTTP 到 HTTPS 重定向
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

自動續(xù)期配置

Let’s Encrypt 證書每 90 天需要續(xù)期一次。Certbot 可以自動處理:

# 測試續(xù)期(不會實際執(zhí)行)
sudo certbot renew --dry-run
# 設(shè)置定時任務(wù)自動續(xù)期
sudo crontab -e

添加以下行(每天凌晨 2 點檢查是否需要續(xù)期):

0 2 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
// Java 示例:Spring Boot 應(yīng)用中的 HTTPS 相關(guān)配置
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
@Configuration
public class HttpsConfig {
    @Value("${server.ssl.enabled:false}")
    private boolean sslEnabled;
    @Value("${server.ssl.key-store:}")
    private String keyStore;
    @Value("${server.ssl.key-store-password:}")
    private String keyStorePassword;
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> containerCustomizer() {
        return factory -> {
            if (sslEnabled && !keyStore.isEmpty()) {
                Ssl ssl = new Ssl();
                ssl.setKeyStore(keyStore);
                ssl.setKeyStorePassword(keyStorePassword);
                ssl.setKeyAlias("tomcat");
                factory.setSsl(ssl);
            }
        };
    }
}

方案三:商業(yè)證書(企業(yè)級應(yīng)用)

對于企業(yè)級應(yīng)用,可能需要購買商業(yè) SSL 證書,如 DigiCert、GeoTrust、Symantec 等。

申請商業(yè)證書流程

  1. 生成 CSR(Certificate Signing Request)
# 生成私鑰
openssl genrsa -out example.com.key 2048
# 生成 CSR
openssl req -new -key example.com.key -out example.com.csr
  1. 提交 CSR 到證書頒發(fā)機構(gòu)
  2. 驗證域名所有權(quán)
  3. 下載證書文件

配置商業(yè)證書

商業(yè)證書通常包含多個文件:

  • 主證書:example.com.crt
  • 中間證書:intermediate.crt
  • 根證書:root.crt

需要將它們合并成一個文件:

cat example.com.crt intermediate.crt root.crt > fullchain.crt
server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    # 商業(yè)證書配置
    ssl_certificate /etc/nginx/ssl/fullchain.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    # 高級 SSL 配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
    ssl_prefer_server_ciphers off;
    ssl_ecdh_curve secp384r1;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/nginx/ssl/fullchain.crt;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    # HSTS
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    # 安全頭
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Referrer-Policy "strict-origin-when-cross-origin";
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none';";
    # Gzip 壓縮
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    # 根目錄
    root /var/www/html;
    index index.html index.htm;
    location / {
        try_files $uri $uri/ =404;
    }
    # 靜態(tài)資源緩存
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

HTTP 到 HTTPS 重定向的最佳實踐

確保所有 HTTP 請求都被重定向到 HTTPS:

# 方法一:簡單的 301 重定向
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}
# 方法二:保留原始請求路徑和參數(shù)
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}
# 方法三:針對特定路徑的重定向
server {
    listen 80;
    server_name example.com www.example.com;
    location /admin {
        return 301 https://$server_name$request_uri;
    }
    location /api {
        return 301 https://$server_name$request_uri;
    }
    # 其他路徑可以保持 HTTP(不推薦)
    location / {
        # 繼續(xù)使用 HTTP
        root /var/www/html;
        index index.html;
    }
}
// Java 示例:Servlet Filter 強制 HTTPS
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HttpsEnforcementFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        // 檢查是否為 HTTPS 請求
        if (!"https".equals(httpRequest.getScheme()) && 
            !"https".equals(httpRequest.getHeader("X-Forwarded-Proto"))) {
            // 構(gòu)建 HTTPS URL
            StringBuilder httpsUrl = new StringBuilder("https://");
            httpsUrl.append(httpRequest.getServerName());
            // 添加端口(如果不是默認的 443)
            int port = httpRequest.getServerPort();
            if (port != 80 && port != 443) {
                httpsUrl.append(":").append(port);
            }
            httpsUrl.append(httpRequest.getRequestURI());
            // 添加查詢字符串
            String queryString = httpRequest.getQueryString();
            if (queryString != null) {
                httpsUrl.append("?").append(queryString);
            }
            // 重定向到 HTTPS
            httpResponse.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
            httpResponse.setHeader("Location", httpsUrl.toString());
            return;
        }
        chain.doFilter(request, response);
    }
}

SSL/TLS 性能優(yōu)化

啟用 HTTP/2

HTTP/2 可以顯著提升 HTTPS 網(wǎng)站性能:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    # ... 其他配置
}

Session 復用配置

# SSL Session 緩存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
ssl_session_tickets on;
ssl_session_ticket_key /etc/nginx/ssl/ticket.key;
# 生成 ticket key
openssl rand 48 > /etc/nginx/ssl/ticket.key

SSL 緩沖區(qū)優(yōu)化

# SSL 緩沖區(qū)大小
ssl_buffer_size 4k;

# SSL 預讀
ssl_preread on;

安全加固配置

SSL 協(xié)議和加密套件

# 推薦的安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers off;

HSTS (HTTP Strict Transport Security)

# 嚴格的 HSTS 配置
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

CSP (Content Security Policy)

# 嚴格的內(nèi)容安全策略
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.example.com; style-src 'self' 'unsafe-inline' https://cdn.example.com; img-src 'self' data: https://*.example.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; frame-src 'none'; object-src 'none';" always;
// Java 示例:Spring Security 中的 HTTPS 配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .requiresChannel(channel ->
                channel.anyRequest().requiresSecure()
            )
            .headers(headers ->
                headers
                    .httpStrictTransportSecurity(hsts ->
                        hsts
                            .maxAgeInSeconds(63072000)
                            .includeSubdomains(true)
                            .preload(true)
                    )
                    .frameOptions(frame -> frame.deny())
                    .contentTypeOptions(contentType -> contentType.disable())
                    .xssProtection(xss -> xss.block(false))
            )
            .authorizeHttpRequests(authz ->
                authz.anyRequest().permitAll()
            );
        return http.build();
    }
}

Docker 環(huán)境下的 HTTPS 配置

在 Docker 環(huán)境中配置 HTTPS 有其特殊性:

Docker Compose 配置

version: '3.8'
services:
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
      - ./html:/usr/share/nginx/html
    restart: unless-stopped
  app:
    image: my-java-app:latest
    expose:
      - "8080"
    environment:
      - SERVER_SSL_ENABLED=true
      - SERVER_PORT=8080
    restart: unless-stopped

Nginx 配置文件

events {
    worker_connections 1024;
}
http {
    upstream backend {
        server app:8080;
    }
    server {
        listen 443 ssl http2;
        server_name example.com;
        ssl_certificate /etc/nginx/ssl/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    server {
        listen 80;
        server_name example.com;
        return 301 https://$server_name$request_uri;
    }
}

Java 應(yīng)用配置

// Java 示例:Docker 環(huán)境中的 HTTPS 檢測
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@SpringBootApplication
public class DockerHttpsApplication {
    public static void main(String[] args) {
        SpringApplication.run(DockerHttpsApplication.class, args);
    }
}
@RestController
class HealthController {
    @GetMapping("/health")
    public HealthStatus healthCheck(HttpServletRequest request) {
        return new HealthStatus(
            "UP",
            request.getScheme(),
            request.getServerPort(),
            request.getHeader("X-Forwarded-Proto"),
            System.getenv("SERVER_SSL_ENABLED")
        );
    }
    static class HealthStatus {
        private final String status;
        private final String scheme;
        private final int port;
        private final String forwardedProto;
        private final String sslEnabled;
        public HealthStatus(String status, String scheme, int port, String forwardedProto, String sslEnabled) {
            this.status = status;
            this.scheme = scheme;
            this.port = port;
            this.forwardedProto = forwardedProto;
            this.sslEnabled = sslEnabled;
        }
        // getters...
    }
}

證書續(xù)期和監(jiān)控

自動化續(xù)期腳本

#!/bin/bash
# ssl-renew.sh
LOG_FILE="/var/log/ssl-renew.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] 開始檢查 SSL 證書續(xù)期..." >> $LOG_FILE
# 檢查 Let's Encrypt 證書
if command -v certbot &> /dev/null; then
    echo "[$DATE] 檢查 Let's Encrypt 證書..." >> $LOG_FILE
    certbot renew --quiet --post-hook "systemctl reload nginx" >> $LOG_FILE 2>&1
    if [ $? -eq 0 ]; then
        echo "[$DATE] Let's Encrypt 證書續(xù)期成功" >> $LOG_FILE
    else
        echo "[$DATE] Let's Encrypt 證書續(xù)期失敗" >> $LOG_FILE
    fi
fi
# 檢查證書到期時間
for cert in /etc/nginx/ssl/*.crt /etc/letsencrypt/live/*/fullchain.pem; do
    if [ -f "$cert" ]; then
        EXPIRY_DATE=$(openssl x509 -enddate -noout -in "$cert" | cut -d= -f2)
        DAYS_LEFT=$(echo "$EXPIRY_DATE" | xargs -I {} date -d {} +%s | xargs -I {} echo $(( ({} - $(date +%s)) / 86400 )))
        echo "[$DATE] 證書 $cert 到期時間: $EXPIRY_DATE (剩余 $DAYS_LEFT 天)" >> $LOG_FILE
        # 如果少于 30 天,發(fā)送警告
        if [ $DAYS_LEFT -lt 30 ] && [ $DAYS_LEFT -gt 0 ]; then
            echo "[$DATE] 警告: 證書 $cert 即將在 $DAYS_LEFT 天后過期!" >> $LOG_FILE
            # 這里可以添加郵件或短信通知邏輯
        fi
    fi
done
echo "[$DATE] SSL 證書檢查完成" >> $LOG_FILE
echo "=========================================" >> $LOG_FILE

證書監(jiān)控 Java 類

// Java 示例:證書到期監(jiān)控
import java.io.File;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
public class CertificateMonitor {
    private static final DateTimeFormatter DATE_FORMATTER = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
    public static CertificateInfo checkCertificate(String certPath) {
        try {
            File certFile = new File(certPath);
            if (!certFile.exists()) {
                return new CertificateInfo(certPath, false, "文件不存在", 0, null, null);
            }
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(new FileInputStream(certFile));
            Date notBefore = cert.getNotBefore();
            Date notAfter = cert.getNotAfter();
            long daysLeft = (notAfter.getTime() - System.currentTimeMillis()) / (24 * 60 * 60 * 1000);
            boolean isValid = daysLeft > 0;
            String status = isValid ? "有效" : "已過期";
            if (isValid && daysLeft < 30) {
                status = "即將過期 (" + daysLeft + "天)";
            }
            return new CertificateInfo(
                certPath,
                isValid,
                status,
                daysLeft,
                DATE_FORMATTER.format(notBefore.toInstant()),
                DATE_FORMATTER.format(notAfter.toInstant())
            );
        } catch (Exception e) {
            return new CertificateInfo(certPath, false, "解析錯誤: " + e.getMessage(), 0, null, null);
        }
    }
    public static class CertificateInfo {
        private final String path;
        private final boolean valid;
        private final String status;
        private final long daysLeft;
        private final String notBefore;
        private final String notAfter;
        public CertificateInfo(String path, boolean valid, String status, long daysLeft, String notBefore, String notAfter) {
            this.path = path;
            this.valid = valid;
            this.status = status;
            this.daysLeft = daysLeft;
            this.notBefore = notBefore;
            this.notAfter = notAfter;
        }
        // Getters...
        public String getPath() { return path; }
        public boolean isValid() { return valid; }
        public String getStatus() { return status; }
        public long getDaysLeft() { return daysLeft; }
        public String getNotBefore() { return notBefore; }
        public String getNotAfter() { return notAfter; }
        @Override
        public String toString() {
            return String.format(
                "證書: %s\n狀態(tài): %s\n有效期: %s 至 %s\n剩余天數(shù): %d",
                path, status, notBefore, notAfter, daysLeft
            );
        }
    }
    // 使用示例
    public static void main(String[] args) {
        String[] certPaths = {
            "/etc/letsencrypt/live/example.com/fullchain.pem",
            "/etc/nginx/ssl/selfsigned.crt"
        };
        for (String certPath : certPaths) {
            CertificateInfo info = checkCertificate(certPath);
            System.out.println(info);
            System.out.println("---");
        }
    }
}

高級配置:多域名和通配符證書

多域名證書配置

# 多域名服務(wù)器塊
server {
    listen 443 ssl http2;
    server_name example.com www.example.com blog.example.com shop.example.com;
    ssl_certificate /etc/nginx/ssl/multidomain.crt;
    ssl_certificate_key /etc/nginx/ssl/multidomain.key;
    # ... 其他 SSL 配置
    location / {
        root /var/www/example;
        index index.html;
    }
}
# 為不同子域名單獨配置
server {
    listen 443 ssl http2;
    server_name api.example.com;
    ssl_certificate /etc/nginx/ssl/api.crt;
    ssl_certificate_key /etc/nginx/ssl/api.key;
    # API 特定配置
    client_max_body_size 50M;
    proxy_read_timeout 300s;
    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

通配符證書配置

# 使用 Certbot 獲取通配符證書
sudo certbot certonly --manual --preferred-challenges=dns -d *.example.com -d example.com
# 通配符證書配置
server {
    listen 443 ssl http2;
    server_name *.example.com example.com;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    # 動態(tài)根目錄基于子域名
    set $root_path "/var/www/default";
    if ($host ~* ^([a-z0-9-]+)\.example\.com$) {
        set $subdomain $1;
        set $root_path "/var/www/$subdomain";
    }
    root $root_path;
    index index.html index.htm;
    location / {
        try_files $uri $uri/ =404;
    }
}
// Java 示例:基于子域名的動態(tài)路由
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
public class SubdomainController {
    @GetMapping("/")
    public SubdomainResponse handleSubdomainRequest(HttpServletRequest request) {
        String host = request.getHeader("Host");
        String subdomain = extractSubdomain(host);
        return new SubdomainResponse(
            host,
            subdomain,
            getSiteContent(subdomain),
            request.getScheme(),
            request.isSecure()
        );
    }
    private String extractSubdomain(String host) {
        if (host == null) return "unknown";
        // 移除端口號
        if (host.contains(":")) {
            host = host.substring(0, host.indexOf(":"));
        }
        // 提取子域名
        String domain = "example.com"; // 你的主域名
        if (host.endsWith("." + domain)) {
            return host.substring(0, host.length() - domain.length() - 1);
        }
        return "www"; // 默認子域名
    }
    private String getSiteContent(String subdomain) {
        switch (subdomain.toLowerCase()) {
            case "blog":
                return "博客內(nèi)容";
            case "shop":
                return "商店內(nèi)容";
            case "api":
                return "API 文檔";
            default:
                return "主頁內(nèi)容";
        }
    }
    static class SubdomainResponse {
        private final String host;
        private final String subdomain;
        private final String content;
        private final String scheme;
        private final boolean secure;
        public SubdomainResponse(String host, String subdomain, String content, String scheme, boolean secure) {
            this.host = host;
            this.subdomain = subdomain;
            this.content = content;
            this.scheme = scheme;
            this.secure = secure;
        }
        // Getters...
    }
}

Java 應(yīng)用與 HTTPS 集成

Spring Boot HTTPS 配置

// Java 示例:Spring Boot 內(nèi)置 HTTPS
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.Ssl;
@SpringBootApplication
public class SecureApplication {
    public static void main(String[] args) {
        SpringApplication.run(SecureApplication.class, args);
    }
    @Bean
    public TomcatServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        // 配置 SSL
        Ssl ssl = new Ssl();
        ssl.setKeyStore("classpath:keystore.p12");
        ssl.setKeyStorePassword("changeit");
        ssl.setKeyStoreType("PKCS12");
        ssl.setKeyAlias("tomcat");
        ssl.setEnabled(true);
        tomcat.setSsl(ssl);
        tomcat.setPort(8443);
        return tomcat;
    }
}

application.properties 配置

# HTTPS 配置
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=changeit
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=tomcat
# HTTP 重定向到 HTTPS
server.http.port=8080
# 安全頭配置
server.servlet.session.cookie.secure=true
server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.same-site=strict

REST API HTTPS 客戶端配置

// Java 示例:HTTPS REST 客戶端
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
@Configuration
public class RestClientConfig {
    @Bean
    public RestTemplate restTemplate() throws KeyManagementException, NoSuchAlgorithmException {
        // 創(chuàng)建信任所有證書的 SSL 上下文(僅用于測試?。?
        TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(X509Certificate[] certs, String authType) {}
                public void checkServerTrusted(X509Certificate[] certs, String authType) {}
            }
        };
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
        // 創(chuàng)建 HttpClient
        org.apache.http.impl.client.CloseableHttpClient httpClient = 
            org.apache.http.impl.client.HttpClients.custom()
                .setSSLContext(sslContext)
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory = 
            new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        return new RestTemplate(requestFactory);
    }
    // 生產(chǎn)環(huán)境安全的 REST 客戶端
    @Bean
    public RestTemplate secureRestTemplate() {
        // 使用系統(tǒng)默認的信任庫
        HttpComponentsClientHttpRequestFactory requestFactory = 
            new HttpComponentsClientHttpRequestFactory();
        return new RestTemplate(requestFactory);
    }
}

性能監(jiān)控和日志分析

Nginx 日志配置

# HTTPS 訪問日志格式
log_format ssl_log '$time_local | $scheme | $status | $request_method | '
                  '"$request" | $body_bytes_sent | '
                  '"$http_referer" | "$http_user_agent" | '
                  '$ssl_protocol | $ssl_cipher | $ssl_session_reused';
server {
    listen 443 ssl http2;
    server_name example.com;
    # SSL 專用訪問日志
    access_log /var/log/nginx/ssl-access.log ssl_log;
    error_log /var/log/nginx/ssl-error.log;
    # ... 其他配置
}

Java 監(jiān)控類

// Java 示例:HTTPS 性能監(jiān)控
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@Component
public class HttpsPerformanceFilter implements Filter {
    private final ConcurrentHashMap<String, RequestStats> statsMap = new ConcurrentHashMap<>();
    private final AtomicLong totalRequests = new AtomicLong(0);
    private final AtomicLong httpsRequests = new AtomicLong(0);
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String requestKey = httpRequest.getMethod() + " " + httpRequest.getRequestURI();
        Instant startTime = Instant.now();
        // 記錄請求總數(shù)
        totalRequests.incrementAndGet();
        // 記錄 HTTPS 請求數(shù)
        if ("https".equals(httpRequest.getScheme()) || 
            "https".equals(httpRequest.getHeader("X-Forwarded-Proto"))) {
            httpsRequests.incrementAndGet();
        }
        try {
            chain.doFilter(request, response);
        } finally {
            Duration duration = Duration.between(startTime, Instant.now());
            updateStats(requestKey, duration.toMillis(), httpResponse.getStatus());
        }
    }
    private void updateStats(String key, long durationMs, int statusCode) {
        statsMap.compute(key, (k, v) -> {
            if (v == null) {
                return new RequestStats(durationMs, statusCode);
            } else {
                v.addRequest(durationMs, statusCode);
                return v;
            }
        });
    }
    public PerformanceReport getPerformanceReport() {
        return new PerformanceReport(
            totalRequests.get(),
            httpsRequests.get(),
            statsMap.size(),
            calculateAverageResponseTime(),
            calculateHttpsPercentage()
        );
    }
    private double calculateAverageResponseTime() {
        long totalDuration = statsMap.values().stream()
            .mapToLong(RequestStats::getTotalDuration)
            .sum();
        long totalCount = statsMap.values().stream()
            .mapToLong(RequestStats::getRequestCount)
            .sum();
        return totalCount > 0 ? (double) totalDuration / totalCount : 0.0;
    }
    private double calculateHttpsPercentage() {
        long total = totalRequests.get();
        return total > 0 ? (double) httpsRequests.get() / total * 100 : 0.0;
    }
    static class RequestStats {
        private long totalDuration;
        private long requestCount;
        private int successCount;
        private long maxDuration;
        private long minDuration = Long.MAX_VALUE;
        public RequestStats(long duration, int statusCode) {
            this.totalDuration = duration;
            this.requestCount = 1;
            this.successCount = statusCode >= 200 && statusCode < 300 ? 1 : 0;
            this.maxDuration = duration;
            this.minDuration = duration;
        }
        public void addRequest(long duration, int statusCode) {
            this.totalDuration += duration;
            this.requestCount++;
            if (statusCode >= 200 && statusCode < 300) {
                this.successCount++;
            }
            this.maxDuration = Math.max(this.maxDuration, duration);
            this.minDuration = Math.min(this.minDuration, duration);
        }
        // Getters...
        public long getTotalDuration() { return totalDuration; }
        public long getRequestCount() { return requestCount; }
        public int getSuccessCount() { return successCount; }
        public long getMaxDuration() { return maxDuration; }
        public long getMinDuration() { return minDuration; }
        public double getAverageDuration() { 
            return requestCount > 0 ? (double) totalDuration / requestCount : 0.0; 
        }
        public double getSuccessRate() { 
            return requestCount > 0 ? (double) successCount / requestCount * 100 : 0.0; 
        }
    }
    public static class PerformanceReport {
        private final long totalRequests;
        private final long httpsRequests;
        private final int endpointCount;
        private final double averageResponseTime;
        private final double httpsPercentage;
        public PerformanceReport(long totalRequests, long httpsRequests, int endpointCount, 
                               double averageResponseTime, double httpsPercentage) {
            this.totalRequests = totalRequests;
            this.httpsRequests = httpsRequests;
            this.endpointCount = endpointCount;
            this.averageResponseTime = averageResponseTime;
            this.httpsPercentage = httpsPercentage;
        }
        // Getters...
        public long getTotalRequests() { return totalRequests; }
        public long getHttpsRequests() { return httpsRequests; }
        public int getEndpointCount() { return endpointCount; }
        public double getAverageResponseTime() { return averageResponseTime; }
        public double getHttpsPercentage() { return httpsPercentage; }
        @Override
        public String toString() {
            return String.format(
                "性能報告:\n" +
                "總請求數(shù): %d\n" +
                "HTTPS 請求數(shù): %d (%.2f%%)\n" +
                "端點數(shù)量: %d\n" +
                "平均響應(yīng)時間: %.2fms\n",
                totalRequests, httpsRequests, httpsPercentage, 
                endpointCount, averageResponseTime
            );
        }
    }
}

故障排除和常見問題

證書鏈問題

# 檢查證書鏈
openssl s_client -connect example.com:443 -showcerts
# 驗證證書鏈完整性
openssl verify -CAfile /path/to/ca-bundle.crt /path/to/your/certificate.crt

SSL/TLS 握手失敗

# 調(diào)試 SSL 配置
ssl_buffer_size 16k;
ssl_session_tickets off;
# 更寬松的加密套件(僅用于調(diào)試)
ssl_ciphers HIGH:!aNULL:!MD5;

Java 應(yīng)用 HTTPS 問題排查

// Java 示例:SSL/TLS 調(diào)試工具
import javax.net.ssl.*;
import java.io.IOException;
import java.net.URL;
import java.security.cert.X509Certificate;
public class SSLDebugTool {
    public static void enableSSLDebugging() {
        // 啟用 SSL 調(diào)試
        System.setProperty("javax.net.debug", "ssl:handshake:verbose");
        // 創(chuàng)建信任所有證書的 SSL 上下文(僅用于調(diào)試?。?
        try {
            TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() { return null; }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {}
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {}
                }
            };
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            // 創(chuàng)建所有主機都信任的主機名驗證器
            HostnameVerifier allHostsValid = (hostname, session) -> true;
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void testConnection(String urlString) {
        try {
            URL url = new URL(urlString);
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            System.out.println("正在測試連接: " + urlString);
            int responseCode = connection.getResponseCode();
            System.out.println("響應(yīng)碼: " + responseCode);
            System.out.println("響應(yīng)消息: " + connection.getResponseMessage());
            SSLSession session = connection.getSSLSession();
            if (session != null) {
                System.out.println("SSL 協(xié)議: " + session.getProtocol());
                System.out.println("SSL 密碼套件: " + session.getCipherSuite());
                System.out.println("對等證書數(shù)量: " + session.getPeerCertificates().length);
            }
            connection.disconnect();
        } catch (IOException e) {
            System.err.println("連接失敗: " + e.getMessage());
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        // 啟用調(diào)試(生產(chǎn)環(huán)境不要使用!)
        enableSSLDebugging();
        // 測試連接
        testConnection("https://example.com");
    }
}

最佳實踐總結(jié)

  1. 始終使用 HTTPS:即使是內(nèi)部應(yīng)用也應(yīng)該使用 HTTPS
  2. 定期更新證書:設(shè)置提醒和自動化續(xù)期
  3. 使用強加密:禁用舊的 SSL/TLS 版本和弱加密套件
  4. 啟用 HSTS:強制瀏覽器使用 HTTPS
  5. 監(jiān)控證書到期:提前 30 天收到續(xù)期提醒
  6. 備份私鑰:安全存儲私鑰,避免丟失
  7. 測試配置:使用在線工具測試 SSL 配置安全性

結(jié)語

配置 Nginx HTTPS 證書看似復雜,但按照本文的步驟操作,你可以輕松為你的網(wǎng)站或應(yīng)用啟用安全的 HTTPS 連接。記住,安全不是一次性的工作,而是需要持續(xù)維護的過程。定期檢查證書狀態(tài),更新加密配置,監(jiān)控性能指標,才能確保你的應(yīng)用始終保持安全可靠。

無論你是使用免費的 Let’s Encrypt 證書,還是購買商業(yè)證書,正確的配置都能為你的用戶提供安全、快速的瀏覽體驗。結(jié)合 Java 應(yīng)用的適當配置,你可以構(gòu)建一個完整的端到端安全解決方案。

現(xiàn)在就開始為你的網(wǎng)站啟用 HTTPS 吧!

以上就是在Nginx上配置HTTPS證書的完整指南的詳細內(nèi)容,更多關(guān)于Nginx配置HTTPS證書的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Nginx開啟stub_status模塊配置方法

    Nginx開啟stub_status模塊配置方法

    這篇文章主要介紹了Nginx開啟stub_status模塊配置方法,Nginx中的stub_status模塊主要用于查看Nginx的一些狀態(tài)信息,本文講解它的開啟配置方法,需要的朋友可以參考下
    2015-02-02
  • nginx 499錯誤處理及nginx的配置參數(shù)小結(jié)

    nginx 499錯誤處理及nginx的配置參數(shù)小結(jié)

    在項目容器化改造中,修改Nginx超時設(shè)置可解決499錯誤,本文就來介紹一下nginx 499錯誤處理及nginx的配置參數(shù)小結(jié),感興趣的可以了解一下
    2024-09-09
  • 詳解ngx_http_session_log_module的使用

    詳解ngx_http_session_log_module的使用

    本文主要介紹了詳解ngx_http_session_log_module的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-05-05
  • Nginx中的location路徑映射問題

    Nginx中的location路徑映射問題

    這篇文章主要介紹了Nginx中的location路徑映射問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • nginx配置文件目錄過程

    nginx配置文件目錄過程

    文章介紹了在本地使用VSCode打開Nginx配置文件時發(fā)現(xiàn)未指定配置文件目錄的問題,通過查看Nginx官網(wǎng)和默認配置文件目錄未找到配置文件,最終通過`nginx?-V`命令確認了Nginx在編譯時指定了配置文件目錄
    2025-11-11
  • Nginx服務(wù)器的location指令匹配規(guī)則詳解

    Nginx服務(wù)器的location指令匹配規(guī)則詳解

    這篇文章主要介紹了Nginx服務(wù)器的location指令匹配規(guī)則,文中介紹了一種動靜態(tài)地址分離的方法示例,需要的朋友可以參考下
    2015-12-12
  • 詳解nginx upstream 配置和作用

    詳解nginx upstream 配置和作用

    這篇文章主要介紹了詳解nginx upstream 配置和作用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-07-07
  • docker運行Nginx及配置方法

    docker運行Nginx及配置方法

    這篇文章主要介紹了docker運行Nginx及配置方法,本文給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • 服務(wù)器使用Nginx部署Springboot項目的詳細教程(jar包)

    服務(wù)器使用Nginx部署Springboot項目的詳細教程(jar包)

    這篇文章主要介紹了服務(wù)器使用Nginx部署Springboot項目的詳細教程(jar包),本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • 使用nginx打包部署前端vue項目完整過程(保姆級教程)

    使用nginx打包部署前端vue項目完整過程(保姆級教程)

    這篇文章主要給大家介紹了關(guān)于使用nginx打包部署前端vue項目的相關(guān)資料,包括打包命名、執(zhí)行打包命令、檢查打包成功、下載和解壓Nginx、部署到Nginx、啟動Nginx并訪問項目、以及Nginx的優(yōu)勢,需要的朋友可以參考下
    2024-11-11

最新評論

新宁县| 万全县| 瑞昌市| 罗甸县| 凤庆县| 山丹县| 嘉峪关市| 济源市| 安阳县| 南漳县| 资中县| 通城县| 长葛市| 晋江市| 霸州市| 北宁市| 通渭县| 靖远县| 瑞丽市| 靖江市| 阿瓦提县| 美姑县| 博爱县| 五大连池市| 黄山市| 马尔康县| 莱州市| 武山县| 泗洪县| 泸州市| 探索| 西华县| 聂拉木县| 仙桃市| 高清| 鹤峰县| 宽甸| 瓦房店市| 灵台县| 保德县| 林西县|