2026年Debian上Laravel配置SSL证书完全指南:从Let’s Encrypt到自动化(2026)

一、为什么Laravel必须配置SSL

HTTPS不仅是安全需求,更是现代Web的硬性要求:

  • 浏览器强制:Chrome/Firefox对HTTP网站标记”不安全”
  • SEO排名:Google明确将HTTPS作为排名因素
  • API要求:许多第三方API(支付、OAuth等)强制HTTPS
  • 安全传输:防止登录凭据、会话Cookie被窃取
  • HSTS预加载:现代Web安全标准要求

二、SSL证书类型对比

类型 验证级别 签发速度 费用 适用场景
Let’s Encrypt (DV) 域名验证 数分钟 免费 个人/中小型站点
商业DV证书 域名验证 数分钟 $10-50/年 需要保险的商业站点
OV证书 组织验证 1-3天 $100-300/年 企业官网
EV证书 扩展验证 3-7天 $200-800/年 金融/电商平台
通配符证书 域名验证 数分钟 免费(LE) 多子域名站点

三、前置条件

3.1 环境要求

  • Debian 11/12服务器
  • 已安装Nginx
  • 已部署Laravel项目
  • 域名已解析到服务器IP
  • 80和443端口已开放

3.2 验证域名解析

# 检查域名是否解析到服务器
dig yourdomain.com +short
# 应返回你的服务器IP

# 检查端口是否开放
sudo ss -tulnp | grep -E ':(80|443)'

3.3 确认Nginx已配置HTTP

确保Nginx已正确监听80端口并可以访问Laravel站点:

# /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/myapp/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

四、使用Certbot获取SSL证书

4.1 安装Certbot

sudo apt update
sudo apt install -y certbot python3-certbot-nginx

4.2 获取单域名证书

sudo certbot --nginx -d yourdomain.com

4.3 获取多域名证书

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

4.4 获取通配符证书(需DNS验证)

sudo certbot certonly --manual --preferred-challenges dns \
  -d "*.yourdomain.com" -d yourdomain.com

执行后Certbot会给出DNS TXT记录要求,需要在域名管理后台添加:

_acme-challenge.yourdomain.com  TXT  "验证码字符串"

验证DNS记录生效后按回车继续。

4.5 使用DNS插件自动续期(Cloudflare示例)

# 安装Cloudflare DNS插件
sudo apt install -y python3-certbot-dns-cloudflare

# 创建Cloudflare API凭据文件
sudo mkdir -p /etc/letsencrypt
sudo nano /etc/letsencrypt/cloudflare.ini

写入内容:

dns_cloudflare_api_token = your_cloudflare_api_token
# 设置安全权限
sudo chmod 600 /etc/letsencrypt/cloudflare.ini

# 获取通配符证书
sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d "*.yourdomain.com" -d yourdomain.com

五、Nginx SSL完整配置

5.1 Certbot自动生成的配置

运行certbot --nginx后,Certbot会自动修改Nginx配置,添加SSL相关指令。

5.2 推荐的手动优化配置

# HTTP强制跳转HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com www.yourdomain.com;

    # Let's Encrypt验证仍需HTTP
    location /.well-known/acme-challenge/ {
        root /var/www/myapp/public;
    }

    # 其他请求跳转HTTPS
    location / {
        return 301 https://yourdomain.com$request_uri;
    }
}

# HTTPS主配置
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    root /var/www/myapp/public;
    index index.php;
    charset utf-8;

    # SSL证书路径
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    # SSL协议和加密套件(Mozilla推荐)
    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;

    # SSL会话缓存
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # 安全响应头
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;

    # Laravel重写规则
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # PHP-FPM处理
    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param HTTPS on;
        include fastcgi_params;

        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }

    # 禁止访问隐藏文件
    location ~ /\.(?!well-known) {
        deny all;
    }

    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
}

5.3 应用配置

sudo nginx -t
sudo systemctl reload nginx

六、Laravel应用层SSL配置

6.1 强制HTTPS(AppServiceProvider)

// app/Providers/AppServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\URL;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // 生产环境强制HTTPS
        if ($this->app->environment('production')) {
            URL::forceScheme('https');
        }
    }
}

6.2 信任代理(TrustProxies)

// app/Http/Middleware/TrustProxies.php
namespace App\Http\Middleware;

use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;

class TrustProxies extends Middleware
{
    protected $proxies = '*';  // 信任所有代理(负载均衡器)

    protected function headers(): array
    {
        return [
            Request::HEADER_X_FORWARDED_FOR,
            Request::HEADER_X_FORWARDED_HOST,
            Request::HEADER_X_FORWARDED_PORT,
            Request::HEADER_X_FORWARDED_PROTO,
            Request::HEADER_X_FORWARDED_AWS_ELB,
        ];
    }
}

6.3 配置.env

APP_URL=https://yourdomain.com
APP_ENV=production

# 确保使用安全Cookie
SESSION_SECURE_COOKIE=true
SESSION_DOMAIN=yourdomain.com

6.4 清除并重建缓存

cd /var/www/myapp
php artisan config:clear
php artisan config:cache
php artisan route:cache
php artisan view:cache

七、自动续期配置

7.1 Certbot自动续期

# 检查自动续期定时器
sudo systemctl status certbot.timer

# 手动测试续期
sudo certbot renew --dry-run

7.2 续期后自动重载Nginx

# 创建续期后钩子
sudo nano /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
#!/bin/bash
# 续期成功后重载Nginx
systemctl reload nginx

# 可选:发送通知
curl -s "https://your-monitoring-endpoint/ssl-renewed?domain=yourdomain.com" > /dev/null
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh

7.3 监控证书过期时间

# 查看证书过期时间
echo | openssl s_client -connect yourdomain.com:443 2>/dev/null | openssl x509 -noout -enddate

# 添加到监控脚本
#!/bin/bash
EXPIRY=$(echo | openssl s_client -connect yourdomain.com:443 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

if [ $DAYS_LEFT -lt 14 ]; then
    echo "WARNING: SSL certificate expires in $DAYS_LEFT days!"
    # 发送告警通知
fi

八、常见问题排查

8.1 证书验证失败

# 检查证书文件是否存在
ls -la /etc/letsencrypt/live/yourdomain.com/

# 检查证书域名
openssl x509 -in /etc/letsencrypt/live/yourdomain.com/fullchain.pem -noout -text | grep DNS

# 重新获取证书
sudo certbot --nginx -d yourdomain.com --force-renewal

8.2 混合内容警告

浏览器显示”不安全”通常是因为页面中存在HTTP资源引用:

# 检查Laravel中是否有硬编码HTTP
grep -r "http://" /var/www/myapp/resources/views/

# 解决方案:
# 1. 使用URL::asset()而非硬编码
# 2. 在.env中设置APP_URL=https://yourdomain.com
# 3. 使用URL::forceScheme('https')

8.3 重定向循环

# 检查Nginx是否同时设置了HTTP跳转和Laravel强制HTTPS
# 如果Nginx已经做了301跳转,Laravel不需要再forceScheme

# 排查方法:查看响应头
curl -I http://yourdomain.com
curl -I https://yourdomain.com

# 确保只在一处做跳转,不要Nginx和Laravel都跳转

8.4 OCSP Stapling失败

# 测试OCSP Stapling
echo QUIT | openssl s_client -connect yourdomain.com:443 -status 2>/dev/null | grep -A2 "OCSP response"

# 如果失败,检查DNS resolver配置
# 临时禁用OCSP Stapling
# ssl_stapling off;

九、SSL安全测试

使用在线工具验证SSL配置安全性:

工具 地址 检测内容
SSL Labs ssllabs.com/ssltest 全面SSL安全评估
Security Headers securityheaders.com HTTP安全头检测
HSTS Preload hstspreload.org HSTS预加载状态

目标评分:SSL Labs A+、Security Headers A及以上

十、总结

步骤 命令/操作 说明
安装Certbot apt install certbot python3-certbot-nginx SSL证书工具
获取证书 certbot --nginx -d domain.com 自动配置Nginx
优化SSL配置 手动编辑Nginx配置 TLS 1.2+1.3、HSTS、OCSP
Laravel配置 forceScheme + TrustProxies 应用层HTTPS
自动续期 certbot timer 自动续期+重载
安全测试 SSL Labs 验证配置安全

关键提醒
1. 证书有效期仅90天,必须配置自动续期
2. 始终在Nginx层做HTTPS跳转,避免与Laravel冲突
3. 使用Mozilla推荐的SSL配置,不要自行精简加密套件
4. 定期检查SSL安全评分,及时更新配置

注:本文基于Laravel 11.x、Nginx 1.24、Certbot 3.x、Debian 12编写。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注