# 使用 Certbot --webroot 模式为 Nginx 配置 HTTPS



之前我一直使用：

```shell
certbot --nginx
```

来自动申请和配置 HTTPS 证书。

这种方法虽然方便，但在实际使用中，我遇到了比较严重的问题：

- certbot 会自动修改 nginx 配置
- certbot 会自动 reload/restart nginx，导致systemd 状态与 nginx 实际状态脱节，出现“游离 nginx”，然后第一个证书成功、后面失败

最终决定迁移到：

```shell
certbot --webroot
```

这种模式下：

- certbot 不再接管 nginx
- 不再自动修改 nginx 配置
- 不再 reload/restart nginx
- nginx 完全手动管理

------

## 一、安装 certbot

Ubuntu：

```shell
sudo apt update
sudo apt install certbot
```

------

## 二、创建 challenge 目录

统一使用：

```shell
mkdir -p /var/www/.letsencrypt/.well-known/acme-challenge
```

说明：

- certbot 以 root 身份运行，因此无需 `www-data` 写权限
- nginx 只需要可读权限

------

## 三、配置 nginx challenge 路由

在所有 80 端口 server 中加入：

```nginx
location /.well-known/acme-challenge/ {
    root /var/www/.letsencrypt;
}
```

例如：

```nginx
server {
    listen 80;
    server_name fupcode.com www.fupcode.com;

    location /.well-known/acme-challenge/ {
        root /var/www/.letsencrypt;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}
```

------

## 四、申请证书

```shell
certbot certonly --webroot -w /var/www/.letsencrypt -d fupcode.com
```

说明：

| 参数        | 含义                           |
| ----------- | ------------------------------ |
| certonly    | 只申请证书，不修改 nginx       |
| --webroot   | 使用 webroot challenge         |
| --cert-name | 指定证书名称，可选，默认为域名 |
| -w          | challenge 根目录               |
| -d          | 域名，可多个                   |

------

## 五、查看证书

```shell
certbot certificates
```

证书通常位于：

```shell
/etc/letsencrypt/live/fupcode.com/
```

例如：

```shell
/etc/letsencrypt/live/fupcode.com/fullchain.pem
/etc/letsencrypt/live/fupcode.com/privkey.pem
```

------

## 六、配置 nginx HTTPS

在 nginx 中手动配置：

```shell
ssl_certificate /etc/letsencrypt/live/fupcode.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/fupcode.com/privkey.pem;
```

例如：

```nginx
server {
    listen 443 ssl http2;
    server_name fupcode.com www.fupcode.com;

    ssl_certificate /etc/letsencrypt/live/fupcode.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/fupcode.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8000;
    }
}
```

------

## 七、nginx 重载

```shell
nginx -t
nginx -s reload
```

------

## 八、配置 deploy-hook

```shell
mkdir -p /etc/letsencrypt/renewal-hooks/deploy

cat >/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh <<'EOF'
#!/bin/sh
nginx -s reload
EOF

chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
```

## 九、测试续期

```shell
certbot renew --dry-run
```

如果成功，说明：

- challenge 正常
- 续期流程正常


---

> 作者: [fupcode](https://github.com/fupcode)  
> URL: https://fupcode.com/blog/posts/devops/certbot-webroot/  

