分类: 极客

  • 运维复盘:WordPress 事故恢复与架构升级实战记录

    1. 事故背景
      现状:服务器上有运行中的 WordPress 和 MySQL 8.0 容器。

    问题:/root/wordpress-app/ 目录下的 docker-compose.yml 丢失,导致无法对现有容器进行升级、维护或修改。

    需求:

    100% 还原配置文件。

    解决站点健康中提示的“页面缓存”性能问题。

    提升安全性(更换默认/已知密码)。

    1. 阶段一:逆向工程——找回配置
      由于容器还在运行,我们通过 Docker 内部信息反推配置。

    找回密码:通过 docker inspect wordpress_app | grep WORDPRESS_DB_PASSWORD 获取了连接密码。

    定位数据卷:通过 docker inspect 确认了数据卷名为 wordpress-app_wp_data 和 wordpress-app_db_data。

    重构 YAML:

    关键点:在 volumes 部分必须标记 external: true。这告诉 Docker:“卷已经存在了,直接挂载就好,千万别给我创建新的空卷”,否则数据会丢失。

    1. 阶段二:性能飞跃——引入双层缓存
      为了解决 WordPress 提示的“页面缓存”告警,我们实施了架构升级。

    架构图示
    操作步骤
    修改配置:在 docker-compose.yml 中新增 redis 服务。

    配置注入:在 WordPress 环境变量中加入 WORDPRESS_CONFIG_EXTRA,自动将 Redis 链接信息写入 wp-config.php。

    应用变更:执行 docker compose up -d。此时 WordPress 容器被“Recreated”(重建),但由于数据卷是外部挂载的,文章和图片毫发无损。

    插件激活:

    WP Super Cache:实现页面级静态化(解决站点健康告警)。

    Redis Object Cache:实现数据库查询缓存(提升后台操作速度)。

    1. 阶段三:安全加固——修改数据库密码
      修改已运行中的 MySQL 密码不能只改配置文件,必须遵循“锁钥匙同步”原则。

    关键流程:
    手动换锁:进入容器内部修改 MySQL 用户表。

    Bash

    docker exec -it wordpress_db mysql -u root -p旧密码
    ALTER USER ‘root’@’%’ IDENTIFIED WITH mysql_native_password BY ‘新密码’;
    FLUSH PRIVILEGES;
    同步钥匙:将 docker-compose.yml 中的两处密码同步修改为新密码。

    重启生效:执行 docker compose up -d,让 WordPress 带着新钥匙重新连接数据库。

    1. 核心:最终版生产环境 docker-compose.yml
      YAML

    name: wordpress-app

    services:
    db:
    image: mysql:8.0
    container_name: wordpress_db
    restart: always
    environment:
    MYSQL_DATABASE: wordpress
    MYSQL_ROOT_PASSWORD: “你的新密码”
    volumes:
    – wordpress-app_db_data:/var/lib/mysql

    redis:
    image: redis:6-alpine
    container_name: wordpress_redis
    restart: always

    wordpress:
    image: wordpress:latest
    container_name: wordpress_app
    restart: always
    ports:
    – “8080:80”
    environment:
    WORDPRESS_DB_HOST: db
    WORDPRESS_DB_USER: root
    WORDPRESS_DB_PASSWORD: “你的新密码”
    WORDPRESS_CONFIG_EXTRA: |
    define( ‘WP_REDIS_HOST’, ‘redis’ );
    define( ‘WP_REDIS_PORT’, 6379 );
    volumes:
    – wordpress-app_wp_data:/var/www/html
    depends_on:
    – db
    – redis

    volumes:
    wordpress-app_wp_data:
    external: true
    wordpress-app_db_data:
    external: true

    1. 经验与教训 (Best Practices)
      配置文件是灵魂:一定要备份 docker-compose.yml 到云端或 Git。

    External 是护身符:只要使用了外部卷(External Volumes),容器随便怎么删,数据永远在宿主机磁盘上。

    缓存是刚需:对于 WordPress,WP Super Cache + Redis 是标配,能极大延长服务器寿命。

  • 🛡️ WordPress 后台安全加固总结

    1. 核心防御原理

    我们在 Nginx 反向代理层(也就是你服务器的最外层大门)建立了一套“白名单准入机制”。

    • 逻辑: 只有来自你授权的 IP 地址,Nginx 才会将请求转发给 Docker 里的 WordPress 容器;其他所有 IP 访问敏感路径时,直接由 Nginx 拦截并返回 403 Forbidden
    • 优势: 攻击者无法通过暴力破解尝试密码,因为他们连登录页面都打不开,同时也减轻了 WordPress 插件和数据库的运算压力。

    2. 配置结构梳理

    你在 /etc/nginx/sites-available/wordpress 中实现的规则分为三个层次:

    访问路径规则策略目的
    / (全站首页/文章)全员开放保证读者能正常访问你的网站内容。
    /wp-admin/admin-ajax.php全员开放关键点:保证前台功能的动态加载(如评论、翻页)不失效。
    wp-admin & wp-login.phpIP 白名单只有你的 IP 能看到后台登录框,彻底封死暴力破解入口。

    3. 故障排除回顾(解决冲突)

    在配置过程中,我们遇到了 conflicting server name 警告,这是新手常踩的坑:

    • 问题: defaultwordpress 两个配置文件同时声明了对 yaoyuan.me 的所有权。
    • 解决: 通过删除 /etc/nginx/sites-enabled/default 软链接,确保了 Nginx 路径唯一化,让新规则真正生效。

    4. 日常维护手册

    • 查看被拦下的倒霉蛋:使用 tail -f /var/log/nginx/error.log | grep “forbidden”。
    • 自己被锁在外面了:
      1. SSH 登录服务器。
      2. 执行 curl ifconfig.me 获取当前新 IP。
      3. 修改 allow 后的 IP,运行 nginx -s reload
    • 增加办公环境 IP:在 allow 下方直接增加一行 allow x.x.x.x; 即可,记得保留最后一行 deny all;。

  • 我的GitHub第一个项目

    🛡️ SpartanHost Monitor (Universal Edition)

    一款专为 Spartan Host 设计的工业级库存监控系统,支持多平台 Linux 自动适配。提供交互式部署流程、自动邮件提醒及 RESTful API 支持,能够轻松完成库存监控应用的搭建。


    License
    Issues
    Stars
    Node
    Lint
    Architecture
    Style
    Security

    🚀 技术栈支持


    ✨ 核心特性

    •  全系统适配:一键支持 Ubuntu, Debian, CentOS, AlmaLinux, Rocky, Fedora。
    •  交互式部署:安装时动态配置邮箱及密码,实现零代码基础配置。
    •  智能提醒:支持 Gmail 等 SMTP 服务,内置防骚扰冷却机制。
    •  安全加固:管理密码支持自定义或强随机生成,接口受鉴权保护。
    •  进程守护:基于 PM2 实现开机自启、崩溃重启及实时日志监控。
    •  RESTful API:预留库存数据及订阅者管理接口,方便二次开发。

    🚀 快速开始

    1️⃣ 克隆项目 (Git 方式)

    git clone https://github.com/yokopro/spartanhost-monitor.git
    cd spartanhost-monitor

    2️⃣ 执行一键部署脚本

    将自动识别系统环境并安装 Node.js 与 PM2

    # 修复换行符并赋予权限
    sed -i 's/\r$//' deploy.sh && chmod +x deploy.sh
    
    # 运行交互式安装
    ./deploy.sh

    3️⃣ 查看管理密码

    如果在安装时选择了随机生成密码,请运行以下命令查看密码:

    pm2 logs spartan-monitor --lines 50

    🛠️ 运维管理指令

    需求指令
    实时日志pm2 logs spartan-monitor
    状态面板pm2 status
    重启应用pm2 restart spartan-monitor
    停止监控pm2 stop spartan-monitor
    资源监控pm2 monit
    彻底卸载pm2 delete spartan-monitor && rm -rf $(pwd)

    🔗 API 接口文档

    系统默认运行在 3000 端口。

    1️⃣ 实时库存数据

    • EndpointGET /api/stock
    • 说明: 返回当前监控的所有产品及其库存状态。

    2️⃣ 查看订阅者清单

    • EndpointGET /api/subscribers
    • 认证: 需在 Request Header 中添加:password: 你的管理密码

    3️⃣ 系统健康检查

    • EndpointGET /health

    📂 项目结构

    ├── public/                # Web 前端页面 (订阅及展示)
    ├── server.js              # 后端核心逻辑与 API 服务
    ├── config.js              # 自动生成的配置文件 (由 deploy.sh 生成)
    ├── deploy.sh              # 终极全能交互式部署脚本
    ├── package.json           # 项目依赖清单
    └── subscribers.json       # 订阅用户数据存储 (本地 JSON)
    

    ⚠️ 注意事项

    1. Gmail 用户
      • 请务必开启“两步验证”并使用 16 位应用专用密码,而非邮箱登录密码。
    2. 防火墙设置
      • 本脚本会自动尝试开放 3000 端口,若无法访问,请检查云服务商的安全组设置。
    3. 隐私保护
      • .gitignore 已默认忽略 config.js,请勿手动取消,防止授权码泄露至公共仓库。

    联系我

    📧邮件:mail.yaoyuan(@)gmail.com 如果还有其他需求或特色添加,请随时告诉我! 😊

  • 使用Simple Icons

    结合Gemini设计一款wordpress页脚,我的理念是以简约、留白、高级、apple风格为主。因为是个人blog所以特别鸣谢开源软件提供一切的驱动’‘wordpress、docker’‘以及我最喜爱之一的SpartanHost主机服务商。

    HTMl代码

    <div class="footer-credits" style="text-align: center; font-size: 12px; color: #86868b; margin-top: 25px; display: flex; align-items: center; justify-content: center; gap: 20px; flex-wrap: wrap; font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Arial, sans-serif; -webkit-font-smoothing: antialiased;">
        
        <a href="https://wordpress.com/" target="_blank" style="display: inline-flex; align-items: center; color: #1d1d1f; text-decoration: none; transition: opacity 0.3s ease;">
            <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" style="margin-right: 6px;">
                <title>WordPress</title>
                <path d="M21.469 6.825c.84 1.537 1.318 3.3 1.318 5.175 0 3.979-2.156 7.456-5.363 9.325l3.295-9.527c.615-1.54.82-2.771.82-3.864 0-.405-.026-.78-.07-1.11m-7.981.105c.647-.03 1.232-.105 1.232-.105.582-.075.514-.93-.067-.899 0 0-1.755.135-2.88.135-1.064 0-2.85-.15-2.85-.15-.585-.03-.661.855-.075.885 0 0 .54.061 1.125.09l1.68 4.605-2.37 7.08L5.354 6.9c.649-.03 1.234-.1 1.234-.1.585-.075.516-.93-.065-.896 0 0-1.746.138-2.874.138-.2 0-.438-.008-.69-.015C4.911 3.15 8.235 1.215 12 1.215c2.809 0 5.365 1.072 7.286 2.833-.046-.003-.091-.009-.141-.009-1.06 0-1.812.923-1.812 1.914 0 .89.513 1.643 1.06 2.531.411.72.89 1.643.89 2.977 0 .915-.354 1.994-.821 3.479l-1.075 3.585-3.9-11.61.001.014zM12 22.784c-1.059 0-2.081-.153-3.048-.437l3.237-9.406 3.315 9.087c.024.053.05.101.078.149-1.12.393-2.325.609-3.582.609M1.211 12c0-1.564.336-3.05.935-4.39L7.29 21.709C3.694 19.96 1.212 16.271 1.211 12M12 0C5.385 0 0 5.385 0 12s5.385 12 12 12 12-5.385 12-12S18.615 0 12 0"/>
            </svg>
            <span style="font-weight: 500;">WordPress</span>
        </a>
    
        <span style="color: #d2d2d7; user-select: none;">|</span>
    
        <a href="https://www.docker.com/" target="_blank" style="display: inline-flex; align-items: center; color: #1d1d1f; text-decoration: none; transition: opacity 0.3s ease;">
            <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" style="margin-right: 6px;">
                <title>Docker</title>
                <path d="M13.983 11.078h2.119a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.119a.185.185 0 00-.185.185v1.888c0 .102.083.185.185.185m-2.954-5.43h2.118a.186.186 0 00.186-.186V3.574a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m0 2.716h2.118a.187.187 0 00.186-.186V6.29a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.887c0 .102.082.185.185.186m-2.93 0h2.12a.186.186 0 00.184-.186V6.29a.185.185 0 00-.185-.185H8.1a.185.185 0 00-.185.185v1.887c0 .102.083.185.185.186m-2.964 0h2.119a.186.186 0 00.185-.186V6.29a.185.185 0 00-.185-.185H5.136a.186.186 0 00-.186.185v1.887c0 .102.084.185.186.186m5.893 2.715h2.118a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m-2.93 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.083.185.185.185m-2.964 0h2.119a.185.185 0 00.185-.185V9.006a.185.185 0 00-.184-.186h-2.12a.186.186 0 00-.186.186v1.887c0 .102.084.185.186.185m-2.92 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.082.185.185.185M23.763 9.89c-.065-.051-.672-.51-1.954-.51-.338.001-.676.03-1.01.087-.248-1.7-1.653-2.53-1.716-2.566l-.344-.199-.226.327c-.284.438-.49.922-.612 1.43-.23.97-.09 1.882.403 2.661-.595.332-1.55.413-1.744.42H.751a.751.751 0 00-.75.748 11.376 11.376 0 00.692 4.062c.545 1.428 1.355 2.48 2.41 3.124 1.18.723 3.1 1.137 5.275 1.137.983.003 1.963-.086 2.93-.266a12.248 12.248 0 003.823-1.389c.98-.567 1.86-1.288 2.61-2.136 1.252-1.418 1.998-2.997 2.553-4.4h.221c1.372 0 2.215-.549 2.68-1.009.309-.293.55-.65.707-1.046l.098-.288Z"/>
            </svg>
            <span style="font-weight: 500;">Docker</span>
        </a>
    
        <span style="color: #d2d2d7; user-select: none;">|</span>
    
        <a href="https://billing.spartanhost.net/aff.php?aff=2704" target="_blank" style="display: inline-flex; align-items: center; color: #1d1d1f; text-decoration: none; transition: opacity 0.3s ease;">
            <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" style="margin-right: 6px;">
                <title>iCloud</title>
                <path d="M13.762 4.29a6.51 6.51 0 0 0-5.669 3.332 3.571 3.571 0 0 0-1.558-.36 3.571 3.571 0 0 0-3.516 3A4.918 4.918 0 0 0 0 14.796a4.918 4.918 0 0 0 4.92 4.914 4.93 4.93 0 0 0 .617-.045h14.42c2.305-.272 4.041-2.258 4.043-4.589v-.009a4.594 4.594 0 0 0-3.727-4.508 6.51 6.51 0 0 0-6.511-6.27z"/>
            </svg>
            <span style="font-weight: 500;">SpartanHost</span>
        </a>
    
    </div>
    
    <style>
        /* 模拟 Apple 官网的悬停效果 */
        .footer-credits a:hover {
            opacity: 0.7;
        }
    </style>

    说明:

    1. 矢量清晰度:使用内联 SVG 替代 <img>,在 4K 或移动端 Retinia 屏幕上永远保持锐利。
    2. 响应速度:由于 SVG 直接写在 HTML 中,减少了三次网络图片请求,页面加载会更快。
    3. SVG图标:引用simpleicons图标库,开源且免费。

    现在,这款blog的布局、排版都是由我自主设计,风格上参考apple。哎,谁让apple的审美如此时尚呢。

  • 用通俗易懂的方式讲解充电、电流、电压、电池相关知识,帮你建立基础电力概念。


    1️⃣ 电压 (Voltage, V)

    • 作用:就像水管里的水压,推动电流流动。
    • 单位:伏特 (V)
    • 例子:你电动车电池是 60 V,意思是电池能推动电流流动的“压力”大约是 60 伏特。

    2️⃣ 电流 (Current, A)

    • 作用:就像水管里的水流量,决定每秒钟有多少电流流过。
    • 单位:安培 (A)
    • 例子:你的充电器输出 2.6 A,意思是每秒钟有 2.6 安培的电流流进电池,给电池充电。
    • 注意:电流太大会烧坏电池,太小充电会很慢。2.6 A 对 20 Ah 铅酸电池来说是安全且温和的充电速度。

    3️⃣ 功率 (Power, W)

    • 作用:电压 × 电流,表示“电力工作量”或者“用电速度”。
    • 公式

    功率(W)=电压(V)×电流(A)功率(W) = 电压(V) \times 电流(A)功率(W)=电压(V)×电流(A)

    • 例子:你的充电器输出 68–74 V,2.6 A,大约功率是:

    68×2.6177W,74×2.6192W68 \times 2.6 \approx 177 W, \quad 74 \times 2.6 \approx 192 W68×2.6≈177W,74×2.6≈192W

    和标称 200 W 非常接近,说明数据匹配。


    4️⃣ 电池容量 (Capacity, Ah)

    • 作用:就像水桶大小,表示电池能储存多少电量。
    • 单位:安培小时 (Ah)
    • 例子:20 Ah 的电池,理论上可以输出 20 A 电流 1 小时,或者 2 A 电流 10 小时。

    5️⃣ 铅酸电池充电方式

    • 铅酸电池有标称电压(12 V/块),5 块串联就是 60 V。
    • 充电电压通常比标称电压略高(68–74 V),保证电池能充满。
    • 充电电流不宜过大,0.1–0.3C(C 是电池容量 Ah)是安全的充电速度。
      • 你 20 Ah 电池,0.1C ≈ 2 A,0.3C ≈ 6 A → 2.6 A 很安全。

    6️⃣ 插排额定功率

    • 插排上写的 2500 W,表示它能承受的最大功率是 2500 W。
    • 你的充电器只有 200 W,插排承受能力远大于充电器消耗,所以安全无忧

    7️⃣ 电压、电流、功率的关系

    你可以把它类比成水管系统

    概念类比数值对应
    电压 V水压推动水流的压力
    电流 A水流量每秒流过的水量
    功率 W水的能量流速水压 × 流量

    这样理解,就能知道为什么充电器功率低、电压对、插排大功率都没问题。


    “电压、电流、功率、电池容量”概念的水管示意图

    图片由CHATGPT提供

  • 使用Docker部署WordPress

    一、获取docker安装文档(基于Debian13)

    https://docs.docker.com/engine/install/debian

    二、创建目录(方便管理项目文件以及配置)

    mkdir -p /root/wordpress-app && cd /root/wordpress-app

    三、创建 docker-compose.yml

    使用 nano docker-compose.yml 命令创建文件,并将以下内容粘贴进去。这个配置包含了 WordPress 容器和 MySQL 8.0 数据库。

    services:db:image: mysql:8.0container_name: wordpress_dbrestart: alwaysenvironment:MYSQL_ROOT_PASSWORD: your_root_password  # 修改为你的数据库管理员密码MYSQL_DATABASE: wordpressMYSQL_USER: wordpress_userMYSQL_PASSWORD: wordpress_password       # 修改为你的数据库用户密码volumes:      - db_data:/var/lib/mysqlnetworks:      - wp_networkwordpress:image: wordpress:latestcontainer_name: wordpress_apprestart: alwaysports:      - "8080:80"  # 外部访问端口,如果你想用 80 端口,改为 "80:80"environment:WORDPRESS_DB_HOST: db:3306WORDPRESS_DB_USER: wordpress_userWORDPRESS_DB_PASSWORD: wordpress_password # 必须与上面 db 处的密码一致WORDPRESS_DB_NAME: wordpressvolumes:      - wp_data:/var/www/htmldepends_on:      - dbnetworks:      - wp_networknetworks:wp_network:driver: bridgevolumes:db_data:wp_data:

    四、启动部署

    在当前目录下运行以下命令:(cd /root/wordpress-app)

    docker compose up -d

    -d 表示在后台运行

    五、验证运行状态

    检查容器是否正常启动:

    docker compose ps

    能看到 wordpress_app 和 wordpress_db 两个容器的状态都是 Up

    六、访问与配置

    1. 打开浏览器,输入服务器 IP 地址和端口:http://你的服务器IP:8080
    2. 你将看到 WordPress 的安装界面。
    3. 按照提示选择语言、设置网站标题、管理员账号和密码。

    七、部署Nginx

    想通过域名(如 blog.youer.com)访问,需要您安装最新版的Nginx,配置一个反向代理:

    先执行

    aptupdateaptinstall -y nginx

    创建反向代理配置文件

    Nginx 的配置建议每个站点一个文件。创建一个新文件(以你的域名命名,例如 blog.conf):

    nano /etc/nginx/sites-available/wordpress

    将以下内容粘贴进去(注意修改 server_name):

    server {listen80;server_name blog.youer.com; # 这里改成你解析好的域名# 限制上传文件大小(WordPress 上传插件或主题需要)client_max_body_size64M;location / {proxy_pass http://127.0.0.1:8080; # 对应 Docker 中的端口# 传递真实的客户端信息给后端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;# 解决 WordPress 登录重定向循环的问题proxy_redirectoff;    }}

    启用配置并重启

    在 Debian/Ubuntu 系统中,你需要将文件从 sites-available 软链接到 sites-enabled

    # 1. 建立软链接启用配置ln-s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/# 2. 测试配置文件语法是否正确nginx-t# 3. 如果显示 syntax is ok,则重启 Nginxsystemctlrestart nginx

    开启 HTTPS (强烈建议)

    既然用了反代,用 Certbot 申请免费的 Let’s Encrypt 证书非常简单:

    # 安装 Certbotaptinstall -y python3-certbot-nginx# 运行申请脚本(按提示输入邮箱,选 A 和 Y)certbot--nginx -d blog.youer.com

    Certbot 会自动修改你的 Nginx 配置文件,把 80 端口强制跳转到 443

    八、常用维护命令

    查看日志(排查报错):docker compose logs -f

    停止并删除容器docker compose down

    重启服务docker compose restart

    备份数据

    • 数据库数据存在 db_data 卷中。
    • 网页文件存在 wp_data 卷中。
    • 物理路径通常在 /var/lib/docker/volumes/ 下。