0. 前言
0.1 要完成的事情
本文记录在全新安装的 Nginx 上,完成以下目标:
- 反向代理两个本地服务:
memos.example.com→127.0.0.1:18002(无认证)panso.example.com→127.0.0.1:18010(需要认证)
- 为
panso.example.com配置 Basic Auth 认证,用户名为war。 - 使用 Certbot 自动申请 Let's Encrypt 证书,配置 HTTPS,并将 HTTP 重定向到 HTTPS。
- 使用 fail2ban 监控 Nginx 日志,自动封禁反复认证失败的 IP,防止暴力破解。
- 验证证书自动续期是否正常。
域名使用占位符:
memos.example.com、panso.example.com,实际使用时替换为自己的域名。
0.2 系统环境
- 操作系统:Debian 13(apt 包管理)
- 服务器配置:2H2G,自用
- 域名:
memos.example.com、panso.example.com,均已解析到服务器公网 IP - 后端服务:已在本机运行,分别监听
127.0.0.1:18002和127.0.0.1:18010 - 软件环境:
- Nginx(apt 安装)
- Certbot、
python3-certbot-nginx apache2-utils(提供htpasswd)- fail2ban
- 网络要求:服务器 80、443 端口已开放
1. 安装 Nginx 与 Certbot
sudo apt update
sudo apt install nginx certbot python3-certbot-nginx apache2-utils -y
certbot、python3-certbot-nginx:自动申请并配置 SSL 证书。apache2-utils:提供htpasswd,用于生成 Basic Auth 密码文件。
安装完成后 Nginx 会自动启动。可访问 http://服务器IP 确认默认页面。

2. 配置 Memos 站点(无认证)
创建配置文件:
sudo nano /etc/nginx/sites-available/memos.example.com
写入:
server {
listen 80;
server_name memos.example.com;
location / {
proxy_pass http://localhost:18002;
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;
}
}
说明:
proxy_pass指向本机18002端口。- 四个
proxy_set_header是反向代理标准配置,确保后端获取真实客户端 IP 和原始协议。
3. 配置 Panso 站点(Basic Auth + 反代)
3.1 生成 Basic Auth 密码文件
使用 htpasswd 创建密码文件,用户名为 war,密码自行设置:
sudo htpasswd -Bc /etc/nginx/.htpasswd war
-B:使用 bcrypt 算法加密密码。-c:创建新文件;后续再添加用户时去掉-c。- 按提示输入并确认密码。
如果再执行一次如下命令
sudo htpasswd -B /etc/nginx/.htpasswd alice
就会出现两个用户,两个用户都可以登录网站。/etc/nginx/.htpasswd 生成的格式如下:
war:$2y$05$...
alice:$2y$05$...
3.2 创建 Nginx 配置文件
sudo nano /etc/nginx/sites-available/panso.example.com
写入:
server {
listen 80;
server_name panso.example.com;
location / {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://localhost:18010;
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;
}
}
4. 启用站点并测试 Nginx
sudo ln -s /etc/nginx/sites-available/memos.example.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/panso.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
如果 nginx -t 显示 syntax is ok 和 test is successful,说明配置无误。
Ubuntu / Debian 下,Nginx 默认用两个目录管理站点配置:
-
/etc/nginx/sites-available/:站点配置的“仓库”。所有写好的配置文件都放这里,但不会自动生效。 -
/etc/nginx/sites-enabled/:真正启用的站点配置。Nginx 主配置(/etc/nginx/nginx.conf)中通常有一行:include /etc/nginx/sites-enabled/*;因此只有这个目录里的文件或软链接会被 Nginx 加载。
其他发行版也可以自己加这个配置到达和本文档一样的效果。
5. 用 Certbot 配置 HTTPS
一条命令同时为两个域名申请证书并自动修改 Nginx 配置:
sudo certbot --nginx -d memos.example.com -d panso.example.com
Certbot 会:
- 自动申请 Let's Encrypt 证书;
- 修改 Nginx 配置文件,添加 SSL 配置;
- 询问是否将 HTTP 重定向到 HTTPS,建议选择 “2: Redirect”。
完成后访问:
https://memos.example.comhttps://panso.example.com
Panso 会弹出 Basic Auth 登录框,输入用户 war 和密码即可。
6. 验证证书自动续期
Let's Encrypt 证书有效期 90 天,Certbot 会自动续期。手动测试:
sudo certbot renew --dry-run
看到 Congratulations, all simulated renewals succeeded 即表示自动续期配置正常。
7. 日志查看
Nginx 默认日志位置:
- 访问日志:
/var/log/nginx/access.log - 错误日志:
/var/log/nginx/error.log
筛选认证失败记录:
sudo grep -E " (401|403) " /var/log/nginx/access.log
8. 使用 fail2ban 防止暴力破解
Basic Auth 虽然方便,但公网上面临持续的密码爆破尝试。fail2ban 可以监控 Nginx 日志,自动封禁反复认证失败的 IP,且不会误伤正常访问。
8.1 安装 fail2ban
sudo apt install fail2ban -y
安装后服务会自动启动,但默认没有针对 Nginx Basic Auth 的规则,需要手动添加。
8.2 创建过滤器
新建 /etc/fail2ban/filter.d/nginx-basic-auth.conf:
sudo nano /etc/fail2ban/filter.d/nginx-basic-auth.conf
写入以下内容:
[Definition]
failregex = ^<HOST> - - \[.*\] ".*" (401|403) \d+$
ignoreregex =
说明:
- 该正则匹配 Nginx 默认 combined 日志格式中状态码为
401或403的行。 <HOST>会被 fail2ban 自动替换为客户端 IP。
8.3 创建 jail 配置
新建 /etc/fail2ban/jail.d/nginx-basic-auth.local:
sudo nano /etc/fail2ban/jail.d/nginx-basic-auth.local
写入:
[nginx-basic-auth]
enabled = true
port = http,https
filter = nginx-basic-auth
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 300
bantime = 600
参数解释:
| 参数 | 值 | 含义 |
|---|---|---|
maxretry |
10 | 5 分钟内失败 5 次即封禁 |
findtime |
300 | 统计窗口为 300 秒(5 分钟) |
bantime |
600 | 封禁 10 分钟 |
可根据需要调整。
推荐一个通用方案:在 jail.local 中补上 jail.d 的 include,然后把每个 jail 的配置放在 jail.d/*.local 里。
理由:
jail.d/*.local是 fail2ban 官方约定,多个 jail 分文件管理更清晰。jail.local只负责“启用 include”,不堆具体 jail 配置。- 这样以后加任何新 jail,直接往
jail.d/扔文件即可,不用改jail.local。 - Debian 13 的
jail.conf缺失了这行 include,补上后就符合通用预期。
8.4 让 fail2ban 加载 jail.d 下的配置
Debian 13 的 fail2ban 1.1.0 中,/etc/fail2ban/jail.conf 默认没有 include jail.d/ 目录,导致放在 jail.d/ 下的 jail 配置不会生效。需要在 jail.local 中手动补上 include。
创建或编辑 /etc/fail2ban/jail.local:
sudo nano /etc/fail2ban/jail.local
写入:
[INCLUDES]
after = jail.d/*.conf jail.d/*.local
说明:
after表示在读取完jail.local后再加载jail.d/下的文件。*.conf和*.local都包含,兼容两种命名习惯。- 这一行让 fail2ban 恢复官方默认行为,之后所有
jail.d/下的配置都会生效。
然后重启 fail2ban:
sudo systemctl restart fail2ban
sudo fail2ban-client status
此时 Jail list 中应同时出现 sshd 和 nginx-basic-auth。
8.5 测试并启动
测试过滤器是否能正确匹配日志:
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-basic-auth.conf
若输出中 matched 行数大于 0,说明规则有效。
8.6 查看封禁状态
sudo fail2ban-client status nginx-basic-auth
可看到当前被封禁的 IP 列表及失败统计。
8.7 手动解封
如果自己误触封禁,可用以下命令解封:
sudo fail2ban-client set nginx-basic-auth unbanip 你的IP
9. 关闭站点与证书处理
当某个站点不再需要时,根据你是否还想保留证书,有以下几种处理方式。
9.1 暂时关闭站点(保留证书)
如果只是暂时不想让别人访问,但以后可能还会开启,最简单的方法是停用 Nginx 站点配置,证书继续保留并自动续签。
-
删除
sites-enabled中的软链接:sudo rm /etc/nginx/sites-enabled/panso.example.com -
测试并重载 Nginx:
sudo nginx -t sudo systemctl reload nginx此时
panso.example.com将无法访问,但证书文件仍在/etc/letsencrypt/live/下,Certbot 也会继续为它自动续签(因为续签配置未改动)。 -
以后想重新启用,只需重新创建软链接:
sudo ln -s /etc/nginx/sites-available/panso.example.com /etc/nginx/sites-enabled/ sudo systemctl reload nginx
9.2 彻底删除站点与证书
如果确定不再使用该站点,并且希望删除证书、停止续签,按以下步骤操作。
-
先从 Nginx 配置中移除对证书的引用编辑
sites-available中对应的站点文件,删除或注释掉所有ssl_certificate、ssl_certificate_key等 SSL 相关行,以及监听 443 的server块。也可以直接删除整个站点配置文件。 -
删除
sites-enabled中的软链接:sudo rm /etc/nginx/sites-enabled/panso.example.com -
删除证书:
sudo certbot delete --cert-name panso.example.com如果不确定证书名称,可以先运行
sudo certbot certificates查看所有证书列表。 -
测试并重载 Nginx:
sudo nginx -t sudo systemctl reload nginx
9.3 仅停止证书自动续签
如果只想停止某个证书的自动续期,但保留现有证书文件直到过期,可以禁用其续签配置。
-
找到对应的续签配置文件:
ls /etc/letsencrypt/renewal/文件名通常与证书名一致,例如
panso.example.com.conf。 -
重命名该文件,使其不再被 Certbot 识别:
sudo mv /etc/letsencrypt/renewal/panso.example.com.conf \ /etc/letsencrypt/renewal/panso.example.com.conf.disabled或者直接删除:
sudo rm /etc/letsencrypt/renewal/panso.example.com.conf -
验证:
sudo certbot renew --dry-run如果输出中没有该证书的续签模拟,说明已成功停止。
9.4 关于共享证书的特别说明
如果多个域名共用同一张证书(例如 memos.example.com 和 panso.example.com 一起申请,证书保存在 /etc/letsencrypt/live/memos.example.com/),则:
-
不能单独删除
panso的证书,因为它与memos共用同一个证书文件。 -
执行
sudo certbot delete --cert-name memos.example.com会同时影响两个站点。 -
只想关闭
panso、保留memos:只需停用panso的 Nginx 站点配置(删除sites-enabled中的软链接),无需操作证书。证书会继续为memos自动续签。 -
想为每个域名使用独立证书:先删除共享证书,再分别申请:
# 确保两个站点的 Nginx 配置已移除对旧证书的引用 sudo certbot delete --cert-name memos.example.com # 分别申请独立证书 sudo certbot --nginx -d memos.example.com sudo certbot --nginx -d panso.example.com