用Xshell远程连接(ssh)阿里云(ecs)服务器搭建lnmp(linux+nginx+mysql+php)环境并部署workpress个人博客网站(记录个人学习)(仅供参考)

​

linux version:Rocky linux 9.7

nginx version: nginx/1.20.1

mysql Ver 8.0.46 for Linux on x86_64 (MySQL Community Server – GPL)

php version:PHP 8.0.30

一、环境准备与连接

1.1 使用 Xshell 连接ecs服务器

  • 打开 Xshell,新建会话:
    • 主机:输入服务器公网 IP
    • 端口:22
    • 协议:SSH
  • 点击“连接”,输入用户名(root)和密码(或选择密钥登录)。
  • 成功登录后,你会看到命令行提示符

1.2 更新系统

bash

dnf update -y

一般建议在新部署服务器时先执行一次全面更新,之后根据安全公告和实际需要定期更新。dnf update -y 中的 -y 自动确认,适合在非交互脚本中使用,但生产环境更新前最好先备份或建立快照。

二、安装 Nginx

bash

dnf install -y nginx
systemctl enable nginx
systemctl start nginx

验证:浏览器访问 http://服务器IP,能看到 Nginx 欢迎页即成功。

三、安装 MySQL 8.0(官方仓库)

3.1 添加 MySQL Yum 仓库

bash

dnf install -y https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm

3.2 安装 MySQL 服务器

bash

dnf install -y mysql-community-server

Error:gpg密钥验证失败问题,如过期:

检查并更新 GPG 密钥(如遇验证失败)

bash

# 查看当前仓库配置的 gpgkey
cat /etc/yum.repos.d/mysql-community.repo | grep gpgkey
如果密钥过期,需要下载新密钥(以 2025 年为例)
cd /tmp
wget https://repo.mysql.com/RPM-GPG-KEY-mysql-2025
rpm --import RPM-GPG-KEY-mysql-2025
编辑仓库文件,将 gpgkey 指向新密钥
vim /etc/yum.repos.d/mysql-community.repo
将所有 gpgkey= 行改为:
gpgkey=https://repo.mysql.com/RPM-GPG-KEY-mysql-2025

3.3 启动并设置开机自启

bash

systemctl enable mysqld
systemctl start mysqld

3.4 获取临时密码

bash

grep 'temporary password' /var/log/mysqld.log

复制输出的临时密码。

3.5 修改 root 密码

bash

mysql -u root -p

输入临时密码登录,然后执行:

sql

ALTER USER 'root'@'localhost' IDENTIFIED BY '你的强密码';
FLUSH PRIVILEGES;
EXIT;

3.6 创建 WordPress 数据库和用户

bash

mysql -u root -p

输入新密码,执行:

sql

CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY '你的数据库用户密码';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

四、安装 PHP 8 及扩展

bash

dnf install -y php php-fpm php-mysqlnd php-gd php-xml php-mbstring php-json php-curl php-zip php-intl php-opcache
systemctl enable php-fpm
systemctl start php-fpm

使用 Xshell 修改 PHP-FPM 运行用户

  1. vi /etc/php-fpm.d/www.conf
  2. 找到: text user = apache group = apache 修改为: text user = nginx group = nginx
  3. 保存文件 esc+:wq
  4. 回到终端执行: bash systemctl restart php-fpm

五、配置 Nginx 虚拟主机

5.1 创建站点目录

bash

mkdir -p /var/www/wordpress

5.2 使用 Xshell 创建并编辑配置文件

  1. cd /etc/nginx/conf.d/
  2. vi wordpress.conf
  3. 编辑,粘贴以下内容(将 server_name 改为你的域名或 IP,若没有域名写 _): nginx server {     listen 80;     server_name your_domain_or_ip;     root /var/www/wordpress;     index index.php index.html index.htm; location / {         try_files $uri $uri/ /index.php?$args;     } location ~ .php$ {         include fastcgi_params;         fastcgi_pass unix:/run/php-fpm/www.sock;         fastcgi_index index.php;         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;     } location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ {         expires max;         log_not_found off;     } }
  4. 保存文件

5.3 测试并重载 Nginx

bash

nginx -t
systemctl reload nginx

六、下载并配置 WordPress

6.1 下载 WordPress

bash

cd /var/www
wget https://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz
rm -f latest.tar.gz

6.2 设置权限

bash

chown -R nginx:nginx /var/www/wordpress
find /var/www/wordpress -type d -exec chmod 755 {} \;
find /var/www/wordpress -type f -exec chmod 644 {} \;

6.3 使用 Xshell 配置 wp-config.php

6.3.1 进入 WordPress 目录

在终端中执行:

bash

cd /var/www/wordpress

6.3.2 复制配置文件

bash

cp wp-config-sample.php wp-config.php

6.3.3 使用 vi 编辑器修改配置文件

执行:

bash

vi wp-config.php

这时会进入 vi 编辑器,全程键盘操作。

vi 基本操作:

  1. 按 / 键进入搜索模式,输入 DB_NAME 然后回车,光标会跳到第一个匹配处。
  2. 按 n 键跳转到下一个匹配项,直到定位到 define( 'DB_NAME', 'database_name_here' ); 这一行。
  3. 按 i 键进入插入模式(屏幕底部会出现 -- INSERT --)。
  4. 使用方向键移动光标,将 'database_name_here' 修改为 'wordpress'。
  5. 按 Esc 键退出插入模式。
  6. 重复上述步骤修改 DB_USER 和 DB_PASSWORD:
    • 搜索 DB_USER,将 'username_here' 改为 'wpuser'。
    • 搜索 DB_PASSWORD,将 'password_here' 改为您的数据库用户密码(例如 '你的强密码')。
  7. 同样修改 DB_HOST 为 'localhost'(通常默认已是,但确认一下)。
  8. 按 Esc 确保退出插入模式。
  9. 输入 :wq 然后按回车,保存并退出。

6.4 替换安全密钥(可选但强烈建议)

ps:

为什么要替换?

具体作用:

  1. 加密 Cookie:当用户登录 WordPress 后,服务器会生成一个包含用户身份信息的 Cookie。这些密钥用于对该 Cookie 进行哈希和加密,确保 Cookie 无法被篡改或伪造。
  2. 防止会话劫持:如果没有这些随机密钥,攻击者可能更容易猜测或构造有效的登录 Cookie,从而冒充已登录用户。
  3. 增强密码存储安全性:虽然 WordPress 密码本身使用哈希存储,但密钥用于生成更复杂的认证令牌,间接提升了整体安全性。

为什么必须更换默认的占位符?

  • WordPress 默认配置文件中的密钥是空占位符(如 'put your unique phrase here'),如果保持原样,所有使用该默认配置的站点将共享相同的“密钥”,这使得攻击者可以轻易伪造 Cookie 并入侵任何未修改密钥的站点。
  • 更换为随机、唯一的密钥后,你的站点就拥有了独立的加密指纹,大幅提高安全性。

其他好处:

  • 强制用户重新登录:如果网站曾经被入侵或怀疑 Cookie 泄露,更换密钥会使所有现有登录 Cookie 失效,用户必须重新登录,从而切断攻击者的会话。

总结:更换安全密钥是 WordPress 安全配置的基本步骤,确保你的站点使用独一无二的加密密钥,防止 Cookie 伪造和会话劫持。强烈建议在安装时或首次配置时完成这一步。

bash

# 备份原文件
cp wp-config.php wp-config.php.bak
# 下载密钥并存储到临时文件
curl -s https://api.wordpress.org/secret-key/1.1/salt/ > /tmp/salt.txt
# 使用 sed 删除原有的 8 行密钥定义,并在相同位置插入新密钥
sed -i '/AUTH_KEY/d; /SECURE_AUTH_KEY/d; /LOGGED_IN_KEY/d; /NONCE_KEY/d; /AUTH_SALT/d; /SECURE_AUTH_SALT/d; /LOGGED_IN_SALT/d; /NONCE_SALT/d' wp-config.php
sed -i "/define( 'DB_COLLATE', '' );/r /tmp/salt.txt" wp-config.php

以上命令会删除所有旧密钥行,并在 DB_COLLATE 行之后插入新的密钥行。完成后可查看确认:

bash

grep -E 'AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|NONCE_KEY|AUTH_SALT|SECURE_AUTH_SALT|LOGGED_IN_SALT|NONCE_SALT' wp-config.php

6.5 验证文件权限

确保配置文件的属主和权限正确:

bash

chown nginx:nginx wp-config.php
chmod 640 wp-config.php


七、配置 SELinux 和防火墙

bash

# SELinux 设置
setsebool -P httpd_can_network_connect 1
setsebool -P httpd_can_network_connect_db 1
restorecon -Rv /var/www/wordpress
防火墙开放端口
ps:
这里可能没安装防火墙:

解决方案:

7.1 检查 firewalld 是否安装

bash

rpm -q firewalld

如果未安装,先安装:

bash

dnf install -y firewalld

7.2 启动 firewalld 并设置开机自启

bash

systemctl start firewalld
systemctl enable firewalld

7.3 重新添加端口规则

bash

firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

7.4 验证规则

bash

firewall-cmd --list-services

应该能看到 http 和 https。


补充说明:

  • 为什么 firewalld 没有运行? 可能在系统安装时没有启用,或者被其他防火墙工具(如 iptables)替代。Rocky Linux 9 默认使用 firewalld,但可能被禁用。
  • 如果不想使用 firewalld,可以跳过这一步,因为阿里云安全组已经提供了网络层过滤,只要安全组放行了 80/443 端口,外部就能访问。但系统防火墙(firewalld)建议保持开启,以增加一层防护。
  • 如果已经开启了 firewalld 但仍然无法访问,请检查阿里云安全组规则是否放行 80/443 端口。
>>
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

别忘了在阿里云控制台的安全组中放行 80 和 443 端口。


八、完成 WordPress 安装

浏览器访问 http://你的服务器IP 或域名,按照向导填写:

  • 站点标题
  • 管理员用户名
  • 密码
  • 邮箱
    点击“安装 WordPress”即可。

九、启用 HTTPS:使用 Certbot 申请免费 SSL 证书。

9.0 前置条件(全部必须满足才能开始)

条件验证命令期望结果
域名已注册且实名认证通过阿里云控制台查看域名状态正常
DNS A 记录指向真实 ECS 公网 IPdig antpolsha.xyz +short返回真实公网 IP(如 47.119.131.43)
HTTP 80 可访问curl -I http://antpolsha.xyzHTTP/1.1 200 OK
ECS 安全组放行 80阿里云控制台有 TCP 80/80 授权 0.0.0.0/0
firewalld 放行 httpfirewall-cmd --list-services包含 http
Nginx server_name 包含域名grep server_name /etc/nginx/conf.d/wordpress.conf有 antpolsha.xyz www.antpolsha.xyz
ICP 备案已通过(国内服务器必须)阿里云控制台 → ICP 备案已备案

⚠️ 关键教训:DNS A 记录的记录值必须是服务器真实公网 IP,不能用文档里的示例 IP。错误示范:填了 47.98.123.45(示例 IP),导致 Let’s Encrypt 去访问别人的服务器,全部 Connection refused。

⚠️ 安全组必须有 80/443 对 0.0.0.0/0 放行。如果只放行校园网 IP,本机 curl 能通,但 Let’s Encrypt 从美国发起验证会被拦截。


9.1 前置检查(必须)

bash

# 检查真实公网 IP
curl ifconfig.me

作用:确认服务器的真实公网 IP,与 DNS 记录值对比。
必要性:【必须】 ——DNS 记录值必须与它一致。

bash

# 检查 DNS 解析
dig antpolsha.xyz +short
dig www.antpolsha.xyz +short

作用:确认域名解析指向真实 IP。
期望:返回与 curl ifconfig.me 一致的 IP。

bash

# 检查 HTTP 可访问
curl -I http://antpolsha.xyz

作用:验证 Let’s Encrypt 能否通过 HTTP-01 验证访问到服务器。
期望:返回 HTTP/1.1 200 OK。
必要性:【必须】 ——失败时申请证书一定会失败。


9.2 安装 Certbot(必须)

bash

# 安装 EPEL 仓库
dnf install -y epel-release

作用:启用 EPEL 额外软件仓库,Certbot 由其提供。

bash

# 安装 Certbot 和 Nginx 插件
dnf install -y certbot python3-certbot-nginx

作用:

  • certbot:Let’s Encrypt 官方证书管理客户端。
  • python3-certbot-nginx:Nginx 集成插件,可自动修改配置。

踩坑记录:如果 dnf 安装 EPEL 包时卡住,换阿里云镜像:

bash

dnf clean all
dnf remove -y epel-release
dnf install -y https://mirrors.aliyun.com/epel/epel-release-latest-9.noarch.rpm
dnf install -y certbot python3-certbot-nginx

bash

# 验证
certbot --version

期望:certbot 3.x.x(本次部署为 3.1.0)。


9.3 申请 Let’s Encrypt 证书(必须)

bash

certbot --nginx -d antpolsha.xyz -d www.antpolsha.xyz

参数说明:

  • --nginx:使用 Nginx 插件,自动修改配置。
  • -d antpolsha.xyz:主域名。
  • -d www.antpolsha.xyz:www 子域名(如不需要可去掉)。

交互提示及回答:

提示回答
Enter email address2297969511@qq.com(用于证书到期提醒)
Do you agree?Y
Share with EFF?N(可选)
HTTP redirect?2(自动重定向到 HTTPS)

成功输出:

text

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/antpolsha.xyz/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/antpolsha.xyz/privkey.pem
This certificate expires on 2026-12-20.

⚠️ 已知问题:Certbot 3.x 在处理多域名时,为第一个域名(antpolsha.xyz)自动部署证书后,会去匹配第二个域名(www.antpolsha.xyz)的 server 块,但此时配置已被临时修改,会报错:

text

Could not automatically find a matching server block for www.antpolsha.xyz.

这不影响证书签发,只是自动部署 Nginx 配置失败。解决方法是手动配置,见 9.4。


9.4 手动配置 Nginx 使用证书(必须,当 9.3 自动部署失败时)

前提:/etc/letsencrypt/live/antpolsha.xyz/ 目录下已有证书文件。

bash

# 确认证书文件存在
ls -la /etc/letsencrypt/live/antpolsha.xyz/

期望:看到 fullchain.pem 和 privkey.pem。

bash

# 编辑 Nginx 配置
vim /etc/nginx/conf.d/wordpress.conf

替换为以下结构(保留原有 location 配置,只增加 SSL 部分):

nginx

# HTTP 301 跳转到 HTTPS
server {
    listen 80;
    server_name antpolsha.xyz www.antpolsha.xyz;
    return 301 https://$host$request_uri;
}

# HTTPS 主配置
server {
    listen 443 ssl http2;
    server_name antpolsha.xyz www.antpolsha.xyz;
    root /var/www/wordpress;
    index index.php index.html index.htm;

    # SSL 证书路径(Certbot 生成)
    ssl_certificate     /etc/letsencrypt/live/antpolsha.xyz/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/antpolsha.xyz/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam         /etc/letsencrypt/ssl-dhparams.pem;

    # SSL 安全加固
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # 访问日志
    access_log /var/log/nginx/wordpress_access.log;
    error_log  /var/log/nginx/wordpress_error.log;

    # WordPress 伪静态
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    # PHP 处理
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_read_timeout 300;
    }

    # 静态文件缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 30d;
        log_not_found off;
        access_log off;
    }

    # 禁止访问敏感文件
    location ~* (wp-config\.php|\.htaccess|\.git) {
        deny all;
    }
}

bash

# 测试语法
nginx -t

期望:syntax is ok + test is successful。

bash

# 重载 Nginx
systemctl reload nginx

作用:平滑加载新配置,使 443 端口开始监听。

⚠️ 关键教训:修改配置后必须 reload,否则 443 端口不会监听,curl https://... 会返回 Connection refused。

bash

# 确认 443 已监听
ss -tlnp | grep :443

期望:输出包含 0.0.0.0:443。


9.5 验证 HTTPS(必须)

bash

# 本地测试(绕过安全组)
curl -I https://127.0.0.1 -k

期望:HTTP/2 200。

bash

# 域名测试
curl -I https://antpolsha.xyz
curl -I https://www.antpolsha.xyz

期望:都返回 HTTP/2 200。

bash

# HTTP 跳转测试
curl -I http://antpolsha.xyz

期望:HTTP/1.1 301 Moved Permanently + Location: https://antpolsha.xyz/。

浏览器验证:访问 https://antpolsha.xyz,确认:

  • 地址栏有锁图标 🔒
  • 点击锁 → 证书有效,颁发者 Let’s Encrypt
  • HTTP 自动跳转到 HTTPS

9.6 更新 WordPress 站点地址(必须)

背景:WordPress 数据库里存的还是旧 IP(如 http://47.119.131.43),会导致页面链接指向 IP、后台登录异常、混合内容警告。

bash

mysql -u root -p wordpress -e "UPDATE wp_options SET option_value='https://antpolsha.xyz' WHERE option_name IN ('siteurl','home');"

作用:把 WordPress 的站点地址和主页地址都改为 HTTPS 域名。

bash

# 验证
mysql -u root -p wordpress -e "SELECT option_name, option_value FROM wp_options WHERE option_name IN ('siteurl','home');"

期望:

text

siteurl  https://antpolsha.xyz
home     https://antpolsha.xyz

bash

# 确认 Link 头也更新了
curl -I https://antpolsha.xyz

期望:link: <https://antpolsha.xyz/index.php?rest_route=/>。

⚠️ 执行时机:必须在 HTTPS 生效后才执行,否则 WordPress 后台可能登录不了。


9.7 配置自动续期(必须)

背景:Let’s Encrypt 证书有效期 90 天,Certbot 会自动创建 systemd timer 每天检查续期。

bash

# 检查 timer 是否存在
systemctl list-units --all | grep -i certbot

踩坑记录:Certbot 3.x 的 timer 名字是 certbot-renew.timer,不是旧版的 certbot.timer。首次部署时可能是 disabled 状态(显示为 -),需要手动启用。

bash

# 启用并启动 timer
systemctl enable --now certbot-renew.timer

作用:

  • enable:设置开机自启。
  • --now:立即启动。
  • 启用后,每天会运行两次 certbot renew 检查续期。

bash

# 验证 timer 状态
systemctl status certbot-renew.timer

期望:

text

Loaded: loaded (/usr/lib/systemd/system/certbot-renew.timer; enabled; ...)
Active: active (waiting) since ...
Trigger: Tue 2026-09-22 08:08:39 CST; 13h left

bash

# 查看下次执行时间
systemctl list-timers | grep certbot

期望:显示 NEXT 时间。


9.8 创建 deploy hook(必须)

问题:Certbot 续期成功后,新证书文件已替换,但 Nginx 还在用旧证书。需要重载 Nginx。

bash

# 创建 hook 脚本
vim /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

内容:

bash

#!/bin/bash
systemctl reload nginx

bash

# 赋予执行权限
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

作用:Certbot 每次续期成功后,会自动执行该目录下所有脚本,从而重载 Nginx。

bash

# 验证
ls -la /etc/letsencrypt/renewal-hooks/deploy/

期望:reload-nginx.sh 有 x 权限。

说明:使用 renewal-hooks/deploy/ 目录是 Certbot 官方推荐方式,无需修改 systemd service 文件,也适用于手动 certbot renew。


9.9 验证自动续期机制(必须)

bash

# 手动触发一次检查(不会真正续期,因为还没到期)
systemctl start certbot-renew.service
systemctl status certbot-renew.service

期望:status=0/SUCCESS,日志显示 Certificate not yet due for renewal。

bash

# 查看日志
tail -30 /var/log/letsencrypt/letsencrypt.log

期望:看到 Processing /etc/letsencrypt/renewal/antpolsha.xyz.conf、Certificate not yet due for renewal。

bash

# 模拟续期测试
certbot renew --dry-run

期望:Congratulations, all simulated renewals succeeded。

必要性:【必须】 ——确保 90 天后证书能自动续期,否则网站会因证书过期而无法访问。


9.10 确认防火墙和安全组放行 443(必须)

bash

# firewalld
firewall-cmd --list-services | grep https

期望:包含 https。
如果没有:

bash

firewall-cmd --permanent --add-service=https
firewall-cmd --reload

阿里云安全组:

text

阿里云控制台 → ECS → 安全组 → sg-xxx → 入方向

确认存在:

协议端口授权对象
TCP80/800.0.0.0/0
TCP443/4430.0.0.0/0

⚠️ 关键:80/443 必须对 0.0.0.0/0 开放,不能只放行校园网 IP,否则:

  • 别人访问不了你的网站
  • Let’s Encrypt 从美国验证会失败
  • 搜索引擎爬虫无法抓取

9.11 验证完整清单

检查项命令期望结果
证书文件存在ls /etc/letsencrypt/live/antpolsha.xyz/有 fullchain.pem 和 privkey.pem
443 端口监听ss -tlnp | grep :4430.0.0.0:443
HTTPS 本地访问curl -I https://127.0.0.1 -kHTTP/2 200
HTTPS 域名访问curl -I https://antpolsha.xyzHTTP/2 200
HTTP 自动跳转curl -I http://antpolsha.xyz301 + Location: https://...
HSTS 已启用curl -I https://antpolsha.xyz | grep -i strict返回 strict-transport-security
TLS 版本正确grep ssl_protocols /etc/nginx/conf.d/wordpress.confTLSv1.2 TLSv1.3
WP 站点地址mysql -u root -p wordpress -e "SELECT ..."https://antpolsha.xyz
Timer 已启用systemctl is-enabled certbot-renew.timerenabled
Timer 运行中systemctl is-active certbot-renew.timeractive
Deploy hook 存在ls /etc/letsencrypt/renewal-hooks/deploy/有 reload-nginx.sh
续期模拟通过certbot renew --dry-runCongratulations, all simulated renewals succeeded

9.12 本次部署踩过的坑(经验总结)

问题原因解决
dig 返回 NXDOMAIN域名未注册或 NS 未设置注册域名 + 设置 NS 为阿里云
dig 返回错误 IPDNS A 记录填了示例 IP 47.98.123.45改为真实 IP 47.119.131.43
Certbot 验证 Connection refused安全组只放行校园网 IP,Let’s Encrypt 从美国访问被拦截80/443 对 0.0.0.0/0 放行
Certbot 自动部署失败多域名场景 Certbot 3.x 的已知边界问题手动配置 Nginx 443 server 块
curl https://... Connection refused修改 Nginx 配置后没 reloadsystemctl reload nginx
certbot.timer 找不到Certbot 3.x 的 timer 名字是 certbot-renew.timer启用 certbot-renew.timer
续期后 Nginx 未加载新证书Certbot 默认 service 没有 reload hook创建 renewal-hooks/deploy/reload-nginx.sh
WordPress 链接还指向 IP数据库 siteurl/home 还是旧值SQL 更新为 https://antpolsha.xyz

9.13 后续可选优化(非必须)

优化项命令/操作作用
SSL 在线评分访问 ssllabs.com/ssltest/检查是否 A 或 A+
检查混合内容浏览器 F12 → Console查找并替换 http:// 资源
批量替换数据库中的 http安装 Better Search Replace 插件修复残留的 http 链接
OCSP StaplingNginx 配置 ssl_stapling on加速证书验证
证书到期监控定时检查 certbot certificates提前发现续期失败

9.14 状态

✅ HTTPS 配置已彻底完成

  • 证书有效期:2026-09-21 ~ 2026-12-20
  • 自动续期:certbot-renew.timer 已启用,每天检查两次
  • 续期后自动重载:renewal-hooks/deploy/reload-nginx.sh 已配置
  • 下次自动检查时间:2026-09-22 08:08:39

十、定期备份

10.1 创建备份目录

bash

mkdir -p /backup/database
mkdir -p /backup/website

10.2 备份 MySQL 数据库

使用 mysqldump 命令导出数据库,注意替换您的数据库用户名和密码。

bash

mysqldump -u root -p'你的数据库root密码' wordpress > /backup/database/wordpress_$(date +%F).sql
  • $(date +%F) 会生成日期,如 2026-08-28,避免覆盖。
  • 如果密码包含特殊字符,建议将密码放在 ~/.my.cnf 文件中,避免命令行泄露(见下文)。

验证备份文件:

bash

ls -lh /backup/database/

10.3 备份网站文件

网站目录为 /var/www/wordpress,打包压缩:

bash

tar -czf /backup/website/wordpress_files_$(date +%F).tar.gz /var/www/wordpress

验证:

bash

ls -lh /backup/website/

10.4 自动化备份(使用 cron)

编辑当前用户的 crontab:

bash

crontab -e

如果是第一次使用,会提示选择编辑器,输入 1 或直接回车(通常选择 vi)。添加以下两行(每天凌晨 2 点执行备份):

text

0 2 * * * mysqldump -u root -p'你的数据库root密码' wordpress > /backup/database/wordpress_$(date +\%F).sql
0 3 * * * tar -czf /backup/website/wordpress_files_$(date +\%F).tar.gz /var/www/wordpress

注意:cron 中 % 需要转义为 \%,否则会被当作换行符。

保存退出后,cron 会自动生效。可通过 crontab -l 查看已添加的任务。

10.5 更安全的备份方式(可选)

在命令行直接写密码有风险,建议创建一个 MySQL 配置文件存储凭证:

bash

vi ~/.my.cnf

内容:

ini

[mysqldump]
user=root
password=你的数据库root密码

保存后设置权限:

bash

chmod 600 ~/.my.cnf

然后备份命令可简化为:

bash

mysqldump wordpress > /backup/database/wordpress_$(date +%F).sql

cron 中同样使用该简化命令,无需再写密码。

10.6 自动化清理:定期删除旧备份

您可以在 cron 定时任务中添加清理命令,使其在备份完成后自动删除超过指定天数的旧备份文件。

编辑 crontab:

bash

crontab -e

添加清理任务(例如每天凌晨 4 点清理 7 天前的备份):

text

0 4 * * * find /backup/database -name "wordpress_*.sql" -mtime +7 -delete
0 4 * * * find /backup/website -name "wordpress_files_*.tar.gz" -mtime +7 -delete

说明:

  • find 查找文件;
  • -name "wordpress_*.sql" 匹配文件名模式;
  • -mtime +7 表示修改时间在 7 天前;
  • -delete 删除匹配的文件。

验证命令是否生效:
可以手动执行一次,确认不会误删:

bash

find /backup/database -name "wordpress_*.sql" -mtime +7 -print

先使用 -print 查看将要删除的文件列表,确认无误后再使用 -delete。


10.7 异地备份:同步到阿里云 OSS

异地备份可以防止服务器本身故障(如磁盘损坏、被入侵)导致本地备份也丢失。这里以阿里云 OSS 为例。

10.7.1 安装 ossutil 工具

1). 获取最新版本的 ossutil 下载地址

方法一:查看阿里云官方文档

打开阿里云 OSS 工具页面(可在浏览器访问):
下载并安装命令行工具ossutil-对象存储(OSS)-阿里云帮助中心
在页面中查找 “下载 ossutil” 部分,获取当前最新的下载链接和版本号。例如,文档中可能会提供类似:

bash

wget https://gosspublic.alicdn.com/ossutil/1.7.18/ossutil64

或者更新版本。

方法二:尝试已知的可用版本(稍旧但通常有效)

如果无法访问文档,可以尝试其他版本,例如 1.7.18 或 1.7.16:

bash

wget https://gosspublic.alicdn.com/ossutil/1.7.18/ossutil64

如果还是 404,可以尝试不带版本号,使用官方安装脚本:

bash

curl -o /usr/local/bin/ossutil https://gosspublic.alicdn.com/ossutil/install.sh
bash /usr/local/bin/ossutil

但这种方法不一定成功,因为安装脚本可能也有变化。

方法三:使用 curl 跟随重定向

有时候链接会重定向到最新版本,使用 -L 参数:

bash

curl -L -o ossutil64 https://gosspublic.alicdn.com/ossutil/ossutil64

如果成功下载,再继续后续操作。


2). 手动下载并上传(如果命令行下载总失败)

如果因为网络或链接问题始终无法下载,可以在您本地电脑浏览器中打开阿里云官方文档,找到 ossutil 的下载链接,用浏览器下载 ossutil64 文件,然后通过 FinalShell 的文件管理器上传到服务器(例如上传到 /root 目录)。上传后执行:

bash

chmod +x /root/ossutil64
mv /root/ossutil64 /usr/local/bin/ossutil

3). 验证安装

无论哪种方式,安装完成后运行:

bash

ossutil --version

如果能显示版本号,说明安装成功。


4). 继续配置 OSS

10.7.2 配置 OSS 访问凭证

运行配置向导:

bash

ossutil config

按提示输入:

  • Endpoint:例如 oss-cn-hangzhou.aliyuncs.com(根据您的 OSS 地域填写)
  • AccessKey ID:在阿里云 AccessKey 管理页面创建
  • AccessKey Secret:对应的密钥
  • STSToken:留空直接回车

配置信息会保存在 ~/.ossutilconfig,权限自动设置。

10.7.3 创建 OSS Bucket(如果还没有)

可以在阿里云控制台创建,或使用命令:

bash

ossutil mb oss://your-bucket-name

(假设您已经创建好,此步骤可跳过)

10.7.4 同步备份目录到 OSS

使用 ossutil sync 命令,将本地备份目录同步到 OSS 的指定路径:

bash

ossutil sync /backup/database oss://your-bucket-name/backup/database --delete
ossutil sync /backup/website oss://your-bucket-name/backup/website --delete
  • --delete 表示删除 OSS 中本地不存在的文件(保持完全同步),可根据需求选择是否使用。

10.7.5 定时同步

在 crontab 中添加同步任务,例如每天凌晨 5 点(备份完成后)执行:

text

0 5 * * * /usr/local/bin/ossutil sync /backup/database oss://your-bucket-name/backup/database --delete
0 5 * * * /usr/local/bin/ossutil sync /backup/website oss://your-bucket-name/backup/website --delete

注意: 请确保服务器能访问 OSS(通常没问题),并妥善保管 AccessKey 权限,建议使用最小权限(仅允许访问该 Bucket)。


10.8. 定期验证:确保备份文件可用

备份文件如果损坏,等于没有备份。应定期验证备份的完整性,甚至进行恢复演练。

10.8.1 简单验证:检查备份文件大小和内容

  • 数据库备份:可以用 mysql 导入到一个临时数据库进行验证,或者使用 gzip -t 测试压缩包完整性。
  • 网站文件备份:使用 tar -tzf 列出压缩包内容,检查是否完整。

手动验证命令示例:

bash

# 检查 tar 包完整性
tar -tzf /backup/website/wordpress_files_2026-08-28.tar.gz > /dev/null && echo "tar OK"
检查 SQL 文件可读性(前几行)
head -n 5 /backup/database/wordpress_2026-08-28.sql

10.8.2 自动验证脚本

可以编写一个简单的 Bash 脚本,定期检查最近备份文件是否存在且非空,并记录日志。

创建验证脚本:

bash

vi /usr/local/bin/check_backup.sh

内容如下:

bash

#!/bin/bash
# 检查最近备份文件是否存在且大小大于0
DB_FILE=$(ls -t /backup/database/wordpress_*.sql | head -1)
WEB_FILE=$(ls -t /backup/website/wordpress_files_*.tar.gz | head -1)
if [[ -s "$DB_FILE" ]] && [[ -s "$WEB_FILE" ]]; then
echo "$(date +%F_%T) Backup check passed" >> /var/log/backup_check.log
else
echo "$(date +%F_%T) Backup check FAILED" >> /var/log/backup_check.log
# 可选:发送告警邮件
fi

赋予执行权限:

bash

chmod +x /usr/local/bin/check_backup.sh

在 crontab 中添加每天上午 9 点执行验证:

text

0 9 * * * /usr/local/bin/check_backup.sh

10.8.3 恢复演练(高级)

定期(如每月)将备份恢复到临时目录或临时数据库,确认备份可正常使用。例如:

  • 将数据库备份导入到临时数据库 wordpress_test。
  • 将网站文件解压到临时目录,检查关键文件是否存在。

数据库恢复演练:

bash

mysql -e "CREATE DATABASE IF NOT EXISTS wordpress_test"
mysql wordpress_test < /backup/database/wordpress_2026-08-28.sql
# 检查是否成功导入
mysql -e "SHOW TABLES FROM wordpress_test"
# 清理
mysql -e "DROP DATABASE wordpress_test"

文件恢复演练:

bash

mkdir -p /tmp/restore_test
tar -xzf /backup/website/wordpress_files_2026-08-28.tar.gz -C /tmp/restore_test
ls /tmp/restore_test/var/www/wordpress
rm -rf /tmp/restore_test

可将这些步骤写入脚本,定期手动执行。


总结

  • 自动化清理:用 find 命令配合 cron 删除过期备份,节省磁盘空间。
  • 异地备份:使用 ossutil 同步到阿里云 OSS,防止本地灾难。
  • 定期验证:通过脚本检查备份文件完整性,并定期进行恢复测试,确保备份真的可用。

十一:Nginx 限流


11.1 限流原理

Nginx 限流通过漏桶算法实现:

text

请求进入 → 漏桶(按固定速率流出) → 后端处理
              ↓ 桶满了
           返回 503(拒绝)
概念作用
rate允许的请求速率(如 30r/s)
burst允许突发的请求数(桶的容量)
nodelay突发请求立即处理,不排队延迟
limit_conn单 IP 并发连接数限制

核心:超出速率的请求直接返回 503,不会打满后端 PHP-FPM。


11.2 两层限流设计

层级对象速率作用
general所有请求30r/s,突发 50防止 CC 攻击
loginwp-login.php5r/m,突发 3防止登录爆破
limit_conn所有请求单 IP 20 并发防止连接耗尽

11.3 修改 nginx.conf(定义限流区)【必须】

bash

vim /etc/nginx/nginx.conf

在 http { ... } 块内(不要放在 server 块)添加:

nginx

# 普通请求:每个 IP 每秒 30 次
limit_req_zone $binary_remote_addr zone=general:10m rate=30r/s;

# 登录请求:每个 IP 每分钟 5 次
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

# 并发连接:每个 IP 最多 20 个
limit_conn_zone $binary_remote_addr zone=addr:10m;

# 限流时返回的状态码
limit_req_status 503;
limit_conn_status 503;

参数说明:

参数含义
$binary_remote_addr以客户端 IP 为限流 key
zone=general:10m共享内存区名 general,10MB 约存 16 万 IP
rate=30r/s每秒 30 个请求
rate=5r/m每分钟 5 个请求
limit_req_status 503触发限流返回 503

⚠️ 关键教训:5r/s 和 5r/m 差 60 倍。写错会导致登录爆破无法被拦截。

必要性:【必须】


11.4 修改 wordpress.conf(应用限流)【必须】

bash

vim /etc/nginx/conf.d/wordpress.conf

在 443 server 块内添加限流规则。

完整配置参考

nginx

server {
    listen 443 ssl http2;
    server_name antpolsha.xyz www.antpolsha.xyz;
    root /var/www/wordpress;
    index index.php index.html index.htm;

    # ========== 全局限流(server 块顶层)==========
    limit_req zone=general burst=50 nodelay;
    limit_conn addr 20;

    # SSL 证书配置
    ssl_certificate     /etc/letsencrypt/live/antpolsha.xyz/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/antpolsha.xyz/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam         /etc/letsencrypt/ssl-dhparams.pem;

    # ========== 登录接口:更严格的限流 ==========
    location = /wp-login.php {
        limit_req zone=login burst=3 nodelay;
        auth_basic "Admin Area";
        auth_basic_user_file /etc/nginx/.htpasswd;
        include fastcgi_params;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # ========== wp-admin 目录 ==========
    location ^~ /wp-admin/ {
        auth_basic "Admin Area";
        auth_basic_user_file /etc/nginx/.htpasswd;

        location ~ \.php$ {
            include fastcgi_params;
            fastcgi_pass unix:/run/php-fpm/www.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }
        try_files $uri $uri/ /index.php?$args;
    }

    # ========== 禁用 XML-RPC ==========
    location = /xmlrpc.php {
        deny all;
        access_log off;
    }

    # ========== 默认 location ==========
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_read_timeout 300;
    }

    # ========== 静态文件(不限流)==========
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        limit_req off;
        limit_conn off;
        expires 30d;
        log_not_found off;
        access_log off;
    }

    # 禁止敏感文件
    location ~* (wp-config\.php|\.htaccess|\.git) {
        deny all;
    }
}

应用位置说明

位置限流规则说明
server 块顶层limit_req zone=general burst=50 nodelay;所有请求生效
server 块顶层limit_conn addr 20;单 IP 最大 20 并发连接
location = /wp-login.phplimit_req zone=login burst=3 nodelay;登录接口单独严格限制
静态文件 locationlimit_req off; limit_conn off;静态文件不限流

必要性:【必须】


11.5 测试并重载【必须】

bash

# 测试语法
nginx -t

期望:

text

nginx: configuration file /etc/nginx/nginx.conf test is successful

bash

# 平滑重载
systemctl reload nginx

⚠️ 注意:reload 不改变 Nginx 主进程启动时间,不能用 systemctl status 显示的 “Active since” 判断配置是否生效。判断标准是 nginx -t 通过 + 重载无报错。

必要性:【必须】


11.6 验证限流生效【必须】

测试 1:登录限流(推荐)

bash

for i in $(seq 1 10); do
    code=$(curl -s -o /dev/null -w "%{http_code}" -u admin:你的basic密码 https://antpolsha.xyz/wp-login.php)
    echo "第 $i 次: $code"
done

期望输出(5r/m + burst=3):

text

第 1 次: 200
第 2 次: 200
第 3 次: 200
第 4 次: 503    ← 触发限流
第 5 次: 503
第 6 次: 503
...

看到 503 → 限流生效 ✅

测试 2:检查限流日志

bash

grep -i "limiting" /var/log/nginx/wordpress_error.log | tail -20

期望:

text

2026/09/29 ... [error] ... limiting requests, excess: 0.950 by zone "login", ...

测试 3:全局限流(可选)

bash

ab -n 200 -c 50 https://antpolsha.xyz/

关注输出:

text

Non-2xx responses:      xx    ← 出现 503 说明生效

注意:ab 对 HTTP/2 和 HTTPS 支持不佳,可能报 SSL 错误。优先用测试 1 验证。

必要性:【必须】


11.7 参数调优参考【建议】

个人博客(推荐起始值)

nginx

limit_req_zone $binary_remote_addr zone=general:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=login:10m   rate=5r/m;
limit_conn_zone $binary_remote_addr zone=addr:10m;

调整场景

现象调整
正常用户被误伤rate 提到 50r/s,burst 提到 100
攻击仍然打满rate 降到 10r/s,burst 降到 20
登录太容易触发rate 调到 10r/m
静态资源被限流给静态文件 location 加 limit_req off; limit_conn off;

不同场景参考值

场景general rateburstlogin rate
个人博客30r/s505r/m
中小企业50r/s10010r/m
高流量站点100r/s20020r/m

11.8 常见问题

问题原因解决
限流不触发rate 写成 r/s 而非 r/m检查单位
限流不触发配置未 reloadnginx -t && systemctl reload nginx
限流不触发limit_req_zone 放在 server 块必须放在 http 块
误伤正常用户rate 太小或 burst 太小调大参数
静态资源被限流没给静态文件加 off静态文件 location 加 limit_req off
ab 测试报 SSL 错误ab 对 HTTP/2 支持差改用 curl 循环测试

11.9 配置检查清单

检查项命令期望
限流区定义grep "limit_req_zone" /etc/nginx/nginx.conf3 行(general/login/conn)
general rategrep "zone=general" /etc/nginx/nginx.confrate=30r/s
login rategrep "zone=login" /etc/nginx/nginx.confrate=5r/m
server 块应用grep "limit_req zone" /etc/nginx/conf.d/wordpress.conf至少 2 行
语法正确nginx -tsuccessful
已重载systemctl reload nginx无报错
限流触发连续请求 wp-login.php 6 次第 4 次开始 503
限流日志grep limiting /var/log/nginx/wordpress_error.log有记录

11.10 本次踩过的坑

问题原因解决
限流不触发rate=5r/s(应 5r/m)改正单位,差 60 倍
误以为配置未生效systemctl status 显示 “Active since 4 days ago”reload 不改启动时间,配置已加载
ab 测试报 SSL 错误ab 不支持 HTTP/2改用 curl 循环测试
for + wait 命令卡住wait 不接受管道用 ab 或写文件统计

11.11 状态

✅ Nginx 限流已配置完成

  • general 限流:30r/s,突发 50
  • login 限流:5r/m,突发 3
  • 并发连接:单 IP 20
  • 验证结果:连续 6 次请求 wp-login.php,第 4 次开始返回 503

​

发表评论

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

滚动至顶部