分类: 2025-2026 技术笔记整理

  • 使用 Caddy 为容器网站配置反向代理与 HTTPS

    整理说明:本文属于“2025-2026 技术笔记整理”系列,于 2026 年 8 月集中整理并公开发布。

    用 Caddy 为 WordPress 配置反向代理与域名 HTTPS

    WordPress 可只监听内部网络,由 Caddy 接收公网请求、终止 TLS,再转发给应用。这样只有代理发布端口,数据库和应用不直接暴露,也便于管理证书。

    域名和网络是自动 HTTPS 的前提

    把 A 记录指向服务器公网 IPv4;若发布 AAAA 记录,也要确保 IPv6 可达。防火墙需允许 TCP 80、443。Caddy 使用域名作为站点地址时会申请、续期证书,并把 HTTP 重定向到 HTTPS。解析错误或公网无法回源会导致签发失败。

    代理与 WordPress 应加入同一 Compose 网络。内部 DNS 会解析服务名,因此上游可写 wordpress:80;对 Caddy 容器而言,localhost 指向它自己。

    example.com {
      encode zstd gzip
      reverse_proxy wordpress:80
    
      header {
        -Server
        X-Content-Type-Options "nosniff"
        Referrer-Policy "strict-origin-when-cross-origin"
      }
    }
    

    example.com 换成真实域名即可触发 HTTPS;仅写 :80 不会申请域名证书。裸域名与 www 同时使用时,应明确主域名并重定向。

    保存证书状态,正确传递协议

    Caddy 的 /data 包含证书、私钥和自动 HTTPS 状态,必须挂载持久卷;/config 也宜持久化。丢失这些数据可能导致重复申请证书。私钥卷及其备份应限制权限。

    reverse_proxy 会设置常用的 X-Forwarded-* 头。WordPress 必须识别 X-Forwarded-Proto: https,并使用 https:// 站点地址,否则可能出现循环跳转或混合内容。只应信任受控代理的转发头。

    验证配置再切换流量

    docker compose exec proxy \
      caddy validate --config /etc/caddy/Caddyfile
    docker compose restart proxy
    docker compose logs -f --tail=100 proxy
    

    校验通过后重启代理,并从外部访问域名,检查证书主机名、HTTPS 跳转、后台登录和媒体资源。保留管理 API 时可优雅重载;显式关闭管理 API 时应重启容器。

    • 证书错误先查 A、AAAA 记录,再查 80、443 端口。
    • 出现 502 时,检查共享网络、服务名、容器状态和上游日志。
    • 循环跳转时,核对 WordPress 的 HTTPS 识别逻辑和站点地址。

    上线后应观察证书续期和错误日志。域名可达、存储持久化和正确处理代理头,都是稳定运行的必要条件。

  • 自建邮件系统需要理解的 DNS、MX 与 PTR 记录

    整理说明:本文属于“2025-2026 技术笔记整理”系列,于 2026 年 8 月集中整理并公开发布。

    邮件系统的 DNS 基础:MX、A/AAAA 与 PTR 如何配合

    邮件能否稳定收发,首先取决于域名、主机名和公网地址是否形成一致、可验证的身份链。DNS 记录本身不会提升内容质量,也不能替代发信许可,但配置错误会造成投递失败、延迟或信誉判断异常。

    收信入口:MX 指向邮件主机

    MX 记录发布某个域名由哪些服务器接收邮件。记录值必须是主机名,再由该主机名的 A 或 AAAA 记录解析到地址;不要把 MX 直接写成 IP,也应避免让其目标依赖 CNAME。优先级数字越小,发送方越先尝试。

    • 主、备 MX 都必须真实接收该域邮件,并采用一致的反垃圾与队列策略。
    • 不要为了“看起来冗余”填写并不存在或无法转交邮件的备用主机。
    • 没有明确 MX 时虽可能回退到 A/AAAA,但生产环境应发布显式 MX。

    发信身份:正向解析与 PTR

    PTR 是 IP 地址到主机名的反向解析,通常只能由云厂商、机房或地址持有者设置。建议专用发信 IP 对应一个稳定主机名,例如 mail.example.com,且该名称再正向解析回同一 IP。SMTP 的 EHLO 名称也应与这套身份一致。IPv6 发信同样需要相应的 AAAA 与 PTR。

    example.com.       3600 IN MX 10 mail.example.com.
    mail.example.com.  3600 IN A     192.0.2.10
    ; 反向区域由 IP 提供方配置:
    10.2.0.192.in-addr.arpa. IN PTR mail.example.com.

    192.0.2.10 是文档示例地址,不可用于实际部署。若同一主机承担收发,MX、A 与 PTR 应互相吻合;若收信和发信分离,则分别建立清晰的主机名和职责。

    上线顺序与核验

    先用较短但合理的 TTL 发布新记录,确认稳定后再延长缓存时间。切换期间保留旧服务足够长时间,避免仍持有旧缓存的服务器无处投递。可从不同网络检查:

    dig MX example.com
    dig A mail.example.com
    dig -x 192.0.2.10
    openssl s_client -starttls smtp -connect mail.example.com:25
    • 检查主机名拼写、末尾点、IPv4/IPv6 连通性及 SMTP 证书名称。
    • 确认防火墙仅开放所需端口,服务器不是开放中继,并能处理退信。
    • 再配置 SPF、DKIM、DMARC;它们解决授权和对齐问题,不能代替 MX/PTR。

    合规比记录齐全更重要

    完整 DNS 只是基础。应仅向有合法依据或明确订阅关系的收件人发送邮件,提供清晰退订入口,及时清理无效地址,并持续处理投诉与滥用报告。不要购买地址库或伪造发件身份;认证通过也不等于邮件天然可信。

  • 从 SPF、DKIM 到 DMARC:邮件域名认证的完整链路

    整理说明:本文属于“2025-2026 技术笔记整理”系列,于 2026 年 8 月集中整理并公开发布。

    SPF、DKIM、DMARC:从可观测到严格保护的配置路径

    三项机制解决的是不同问题:SPF 声明哪些系统可以代表域名发信,DKIM 为邮件生成数字签名,DMARC 则检查它们是否与用户看到的 From 域名对齐,并给出失败邮件的处理策略。认证能降低冒用风险,却不是群发许可或进箱保证。

    SPF:约束信封发件来源

    收件方用连接 IP 检查信封 MAIL FROM(退信地址)域名的 TXT 记录,必要时也检查 HELO。一个域名只能发布一条有效 SPF 记录,多个来源应合并。includeamx 等会触发 DNS 查询,评估过程最多允许 10 次此类查询,因此不要无限叠加服务商。

    example.com. IN TXT "v=spf1 ip4:192.0.2.10 include:_spf.provider.example ~all"

    转发可能改变连接来源,使 SPF 失败;同时,SPF 通过也只说明信封域名获授权。DMARC 要求该域名与 From 域名按严格或宽松模式对齐。

    DKIM:验证签名与内容完整性

    发信系统用私钥对选定邮件头和正文摘要签名,收件方从 selector._domainkey.example.com 查询公钥。私钥不得放入 DNS 或代码仓库;选择器让旧、新密钥可以并行,便于轮换。转发时只要已签名部分未被破坏,DKIM 通常仍可验证。

    s2026._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=PUBLIC_KEY"
    _dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"

    DMARC:以 From 域名做最终对齐

    DMARC 在“对齐的 SPF”或“对齐的 DKIM”至少一项通过时通过。策略可设为 nonequarantinerejectrua 接收聚合报告,可能包含基础投递元数据,应设置访问控制并按隐私要求保存。

    推荐的渐进上线步骤

    • 盘点业务系统、客服平台、营销平台和退信域,先停止未知来源。
    • 合并 SPF,先用 ~all 观察,确认来源完整后改为 -all;为合法来源启用 DKIM。
    • 发布 p=none,连续分析聚合报告,修复未对齐的合法流量。
    • 逐步使用 pct 提升 quarantine 覆盖率,确认无误后再到 reject
    • sp 明确子域策略,并定期移除停用供应商与轮换 DKIM 密钥。

    策略升级应基于真实报告,而不是一次性照抄模板。对营销邮件还要取得适当同意、标明发件主体、提供有效退订并抑制已退订地址;对交易邮件也应限制用途和频率。认证负责证明身份,合规发送和良好名单维护才决定长期信誉。

  • 25 端口、587 提交端口与 SMTP 中继应该怎样选择

    整理说明:本文属于“2025-2026 技术笔记整理”系列,于 2026 年 8 月集中整理并公开发布。

    云服务器 25 端口受限时:理解 587 中继并做出选择

    云平台限制出站 25 端口,通常是为了控制垃圾邮件、被盗账号和新 IP 滥用带来的信誉风险。限制可能只针对出站,也可能因账号、区域或产品而异,应以控制台和服务条款为准。不要把端口限制当成网络故障,更不应尝试绕过平台审核。

    25 与 587 承担不同角色

    • 25/tcp 用于邮件服务器之间的 SMTP 投递。发送服务器查询收件域 MX 后,通常连接其 25 端口。
    • 587/tcp 是邮件提交端口,供应用或用户经身份认证把邮件交给受信任的提交服务器,通常通过 STARTTLS 加密。
    • 465/tcp 也常用于采用隐式 TLS 的邮件提交;是否提供取决于中继服务。

    因此,远端 MX 不会因为你的 25 端口受限就自动接受 587。使用 587 的正确方式是选择合规的智能主机(SMTP relay):应用把邮件提交给中继,中继再负责通过 25 端口投递、排队重试和反馈退信。TLS 保护当前链路,并不等同于端到端加密。

    什么时候选直投,什么时候选中继

    直投适合具备静态专用 IP、可配置 PTR、获准开放 25 端口,并有人员维护队列、信誉、退信和滥用响应的团队。若发送量较小、来源多、运维能力有限,正规中继通常更可控;它还能提供速率限制和投递统计,但需评估数据驻留、费用、配额及供应商锁定。

    • 先向云平台按正式流程申请开放 25,并如实说明业务类型、名单来源和投诉处理。
    • 若未获开放,使用平台邮件服务或第三方中继的 587/465,不要搭建隧道规避限制。
    • 区分交易与营销流量,设置独立凭据、限额和监控,避免单一故障影响全部邮件。

    中继配置要点

    以下仅展示 Postfix 的配置形态,主机名和凭据须按供应商文档设置。密码应放在权限受控的凭据映射中,而不是直接写进主配置或仓库。

    relayhost = [smtp.relay.example]:587
    smtp_sasl_auth_enable = yes
    smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
    smtp_tls_security_level = encrypt

    启用中继后仍要让身份链一致:按中继说明更新 SPF,由本地或供应商使用你的域名进行 DKIM 签名,再用 DMARC 报告核验对齐。还应验证退信、投诉回路、连接超时和限流告警,而不能只以“测试邮件已收到”作为上线标准。

    合规边界

    无论直投还是中继,都应只发送收件人合理预期的邮件,落实订阅证明、退订、地址抑制和最小发送频率。中继服务的高信誉不能替代名单质量;违反反垃圾政策可能导致账号暂停,也会损害域名信誉。

  • Ubuntu UFW 与 Docker 端口暴露的安全边界

    整理说明:本文属于“2025-2026 技术笔记整理”系列,于 2026 年 8 月集中整理并公开发布。

    先分清主机入站与容器转发

    在 Ubuntu 上把 UFW 设为默认拒绝入站,并不等于 Docker 发布的端口也会自动被拒绝。执行 docker run -p 8080:80 或在 Compose 中写入 ports 后,Docker 会为目标端口建立地址转换和转发规则。典型的 iptables 后端中,外部数据包经过 DNAT 后进入转发路径,而 UFW 常见的入站规则主要作用于主机的 INPUT 链。因此,ufw status 没有放行 8080,外部仍可能访问容器。

    把暴露范围写进部署配置

    最可靠的第一步不是补一条拦截规则,而是避免发布不需要的端口。应用与数据库可加入同一个 Docker 网络,通过服务名通信;Compose 的 expose 只声明容器网络中的端口,不会把端口发布到主机。只需要由本机反向代理访问的服务,应绑定回环地址:

    services:
      app:
        ports:
          - "127.0.0.1:8080:80"
      db:
        expose:
          - "3306"
    

    对公网服务只发布反向代理的 80 和 443;SSH、数据库、管理面板等端口按来源地址限制。未指定主机地址的 8080:80 通常会绑定所有主机地址,不能把“容器里只监听一个端口”理解为“只有本机能访问”。IPv4 与 IPv6 也要分别核对。

    用三组视角核对实际边界

    sudo ufw status numbered
    docker ps --format 'table {{.Names}}\t{{.Ports}}'
    sudo ss -lntup
    sudo iptables -S DOCKER-USER
    

    ufw status 展示主机策略,docker ps 展示发布映射,ss 展示主机监听;三者必须结合外部机器的连接测试。不要只在服务器本机执行 curl localhost,因为它无法证明公网边界是否正确。

    确需过滤已发布端口时

    使用 Docker iptables 后端时,可在 DOCKER-USER 链加入转发前置策略,或把等价规则纳入经过验证的 UFW 扩展配置。该链看到的目标通常已经完成 DNAT,匹配的是容器地址和容器端口;若要匹配发布前的原始目标,需要 conntrack 条件。规则还应明确公网接口、允许来源、已建立连接和 IPv6 行为,并配置持久化,不能只临时执行一次命令。

    • 优先取消发布,或绑定 127.0.0.1
    • 只让反向代理进入应用网络,不发布数据库端口。
    • 变更后从允许与不允许的外部来源各测试一次。
    • 升级 Docker、防火墙后重新检查规则顺序与实际端口。

    安全边界应由“监听地址、Docker 网络、转发规则、UFW 主机规则”共同定义。只依赖其中一层,最容易在重建容器或新增端口时产生意外暴露。

  • WordPress 邮箱注册背后的事务邮件链路

    整理说明:本文属于“2025-2026 技术笔记整理”系列,于 2026 年 8 月集中整理并公开发布。

    注册功能只是链路的起点

    WordPress 在“设置-常规”中允许任何人注册后,会开放注册入口,并按“新用户默认角色”创建账号。默认角色应保持为订阅者等低权限角色,不能为了省事设为管理员。公开注册还需要验证码、速率限制或人工审核等反滥用措施;这些措施负责控制账号创建,却不能代替邮件投递配置。

    一封激活邮件经过哪些组件

    注册、密码重置或评论通知触发后,核心代码或插件调用 wp_mail(),再由 WordPress 内置的 PHPMailer 交给本机邮件程序或 SMTP 服务。SMTP 服务器接受后,还要经过队列、域名认证、收件方策略和最终邮箱分类。一封邮件没有出现在收件箱,故障可能位于任意一段:

    注册动作 -> WordPress/插件 -> wp_mail()
             -> PHPMailer -> SMTP 提交 -> 收件服务器 -> 邮箱
    

    wp_mail() 返回成功,只说明调用阶段没有报告错误,不代表收件服务器已经接收,更不代表邮件进入收件箱。应同时查看 WordPress 错误、SMTP 响应、服务商投递事件以及退信内容。

    为事务邮件配置稳定出口

    生产站点通常通过 SMTP 插件或代码把邮件提交到受控中继。587 端口常用于 STARTTLS 提交,465 常用于隐式 TLS;25 端口主要承担邮件服务器之间的传输,不应把主机商封禁 25 端口误判为 WordPress 无法发送邮件。凭据应使用专用账号或令牌,并通过环境变量、秘密文件等受控方式管理,避免出现在仓库、日志和截图中。

    • 发件地址使用站点自己的域名,并保持可接收退信。
    • SPF 授权实际中继,DKIM 由出站系统签名,DMARC 检查 From 域对齐。
    • 邮件正文提供站点名称、操作目的和有效链接,不记录密码或完整重置令牌。
    • 限制注册频率,并为邮件失败提供重新发送入口。

    按场景完成上线测试

    先验证 SMTP 端点的 DNS、端口和 TLS,再分别执行新用户注册、找回密码、管理员通知三类测试。测试应覆盖至少两个不同邮件服务商,并检查发件人、回复地址、链接域名、垃圾箱、延迟和移动端显示。只测试插件自带的“测试邮件”不够,因为它不会覆盖真实注册钩子、模板和权限逻辑。

    openssl s_client -starttls smtp \
      -connect smtp.example.net:587 -servername smtp.example.net
    

    这条命令只能验证网络与 TLS 握手,不能证明账号认证或最终投递成功。运行中应记录时间、收件域、消息标识和 SMTP 状态码,但避免保存邮件正文与敏感链接。这样才能沿链路定位问题,而不是反复更换插件碰运气。

  • 轻量服务器上的 Docker 资源监控与故障排查

    整理说明:本文属于“2025-2026 技术笔记整理”系列,于 2026 年 8 月集中整理并公开发布。

    轻量监控先回答三个问题

    小型服务器不一定需要完整的指标平台,但必须持续知道容器是否存活、资源是否接近边界、服务是否真的可用。Docker 的运行状态只能回答进程有没有退出;CPU、内存和磁盘反映压力;HTTP、数据库连接等探测才反映业务可用性。把三类信号混在一个“运行中”状态里,会漏掉卡死、只读文件系统或依赖不可达等故障。

    建立低成本基线

    docker stats --no-stream
    docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
    docker system df
    free -h
    df -h
    df -i
    

    docker stats 提供瞬时 CPU、内存、网络、块 I/O 和进程数,适合快速巡检,但不是历史记录。应在服务正常时保存一份基线,并用定时任务采样关键值;需要趋势和告警时,再增加 cAdvisor、Prometheus 或主机监控代理。对资源紧张的机器,先明确保留周期和采样间隔,避免监控本身占满磁盘。

    限制失控范围

    为核心服务设置合理的内存、CPU 和日志上限。限制值应依据基线留出峰值空间,过低会把短时波动变成重启循环。Docker 的 HEALTHCHECK 会标记健康状态,但普通 Docker 重启策略不会仅因 unhealthy 自动重启容器;探测结果需要由告警或编排逻辑处理。

    services:
      app:
        mem_limit: 512m
        cpus: 1.0
        restart: unless-stopped
        logging:
          driver: json-file
          options:
            max-size: "10m"
            max-file: "3"
    

    故障时先留证再恢复

    docker inspect -f '{{.State.Status}} {{.State.OOMKilled}} {{.State.ExitCode}}' app
    docker logs --since 30m --tail 200 app
    docker events --since 30m
    journalctl -k --since '-30 min' | grep -Ei 'oom|killed process'
    

    先记录时间、状态、退出码、重启次数和近期日志,再检查主机内存、负载、磁盘容量与 inode。OOMKilled=true 或内核 OOM 记录指向内存压力;退出码只能提供线索,仍需结合应用日志。磁盘满时还要检查 Docker 数据目录、容器可写层和日志,不能直接执行 docker system prune,因为未使用的镜像、网络或构建缓存可能仍有恢复价值。

    • CPU 高:用 docker top 定位进程,并核对主机整体负载。
    • 网络异常:检查容器网络、DNS 解析、监听地址和已发布端口。
    • 频繁重启:比较首次失败日志与后续连锁错误。
    • 确认已保留证据后,再做单容器重启或回滚。

    轻量运维的关键不是命令数量,而是固定顺序:先确认影响范围,保存现场,判断资源还是依赖问题,再采取最小恢复动作,并把本次阈值和症状补进下一轮监控。

  • 用 Docker Compose 管理一组长期运行的服务

    整理说明:本文属于“2025-2026 技术笔记整理”系列,于 2026 年 8 月集中整理并公开发布。

    用 Docker Compose 管理 WordPress 服务栈

    当站点同时依赖 WordPress、数据库和反向代理时,逐个启动容器容易遗漏网络、存储或参数。Docker Compose 把这些约束写进 compose.yaml,让部署和维护使用同一套声明。

    先读懂编排文件

    services 定义组件;同一 Compose 网络中的容器可用服务名通信,例如 WordPress 通过 database:3306 访问数据库。volumes 保存持久数据,secrets 以文件形式挂载敏感值,profiles 可放置仅在维护时启动的工具。

    • restart: unless-stopped 可在异常退出或主机重启后恢复服务,但不能替代监控。
    • depends_on 只表达依赖关系;需要等待数据库真正可用时,应配合健康检查和 service_healthy 条件。
    • 数据库可只加入内部网络,减少不必要的端口暴露。
    services:
      wordpress:
        depends_on:
          database:
            condition: service_healthy
        volumes:
          - wordpress_data:/var/www/html
    

    启动前检查,启动后观察

    修改 YAML 后先运行配置渲染命令,它会合并环境变量和覆盖文件,并及早发现缩进、字段或变量问题。确认结果无误后再后台启动:

    docker compose config
    docker compose up -d
    docker compose ps
    docker compose logs -f --tail=100
    

    ps 检查运行和健康状态,logs 用于追踪故障。在运行中的容器执行诊断可用 docker compose exec wordpress php -v;带 profile 的工具服务可用 docker compose --profile tools run --rm wpcli ... 临时启动。

    更新、暂停与清理

    更新时先运行 docker compose pull,再执行 docker compose up -d。Compose 会重建需要变化的容器,命名卷不会因此消失。操作前仍应备份,完成后检查日志和站点;镜像标签应按维护策略固定。

    • stop 停止服务但保留容器,start 可原样恢复。
    • restart 只重启现有容器,不会把新 YAML 配置应用进去。
    • down 删除容器和项目网络,默认保留命名卷。
    • down -v 会删除命名卷,可能清空站点与数据库,不能作为普通重启命令。

    应把 config、备份、启动、健康检查和日志复核固化为操作顺序。Compose 让环境可重复,数据保护和上线验证仍需明确流程。

  • WordPress 容器化部署中的数据持久化与备份

    整理说明:本文属于“2025-2026 技术笔记整理”系列,于 2026 年 8 月集中整理并公开发布。

    WordPress 容器的数据持久化与可恢复备份

    容器可以重建,但数据不能随可写层消失。WordPress 状态包括数据库中的文章、用户和配置,以及文件系统中的上传、主题、插件与运行配置。只备份一类无法恢复完整站点。

    把数据放到容器之外

    WordPress 站点目录通常是 /var/www/html,MariaDB 数据目录是 /var/lib/mysql。为它们挂载命名卷,容器替换后仍可挂载原数据:

    services:
      database:
        volumes:
          - database_data:/var/lib/mysql
      wordpress:
        volumes:
          - wordpress_data:/var/www/html
    
    volumes:
      database_data:
      wordpress_data:
    

    命名卷由 Docker 管理。docker compose down 默认保留它们,docker compose down -v 则会删除项目命名卷。卷并非备份:磁盘损坏、误删和错误写入仍会影响数据。

    分别导出数据库和站点文件

    数据库应使用自身的逻辑导出工具备份,不能在运行中直接复制 /var/lib/mysql。以下命令从挂载的密码文件读取凭据,并把 SQL 输出到主机;备份目录应提前创建并限制权限:

    docker compose exec -T database sh -c \
      'mariadb-dump --single-transaction --quick \
      -u"$MARIADB_USER" -p"$(cat "$MARIADB_PASSWORD_FILE")" \
      "$MARIADB_DATABASE"' > backup/wordpress.sql
    
    docker compose exec -T wordpress \
      tar -C /var/www/html -czf - . \
      > backup/wordpress-files.tar.gz
    

    -T 关闭伪终端,避免混入控制内容。--single-transaction 为事务表提供一致性快照;存在非事务表或结构变更时应安排维护窗口。文件与数据库应同期备份,减少附件不匹配。

    备份完成不等于可以恢复

    • 为文件名加入时间标识,记录对应的 Compose 配置、镜像标签和恢复说明。
    • 将备份复制到另一台主机或对象存储,不要只放在原服务器磁盘。
    • 对归档和 SQL 计算校验值,备份任务失败时应产生告警。
    • 密码和密钥应单独加密保管,避免明文秘密混进普通归档。

    恢复时先阻止写入,在干净卷还原文件并导入数据库,再核对域名、媒体、登录和插件。演练应在隔离环境执行;只有完成关键操作,才能证明备份有效。生产站点还应明确恢复时间和可接受的数据丢失范围。