<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>网络安全 on 友派博客</title><link>https://blog.uipad.com/zh-cn/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/</link><description>Recent content in 网络安全 on 友派博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sat, 14 Mar 2026 21:00:00 +0800</lastBuildDate><atom:link href="https://blog.uipad.com/zh-cn/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/index.xml" rel="self" type="application/rss+xml"/><item><title>独立开发者的异地灾备实践：PostgreSQL 跨云流复制与全链路 SSL 加固</title><link>https://blog.uipad.com/zh-cn/post/2026-03/postgresql-cross-cloud-streaming-replication-with-ssl/</link><pubDate>Sat, 14 Mar 2026 21:00:00 +0800</pubDate><guid>https://blog.uipad.com/zh-cn/post/2026-03/postgresql-cross-cloud-streaming-replication-with-ssl/</guid><description>&lt;p&gt;作为一名独立开发者，最担心的莫过于“单点故障”。虽然 Oracle Cloud 的机器很香，但万一哪天账号被封或机房波动，数据就是命根子。为了实现数据异地实时灾备，我近期完成了一次 PostgreSQL 跨公网的主从同步部署。&lt;/p&gt;
&lt;p&gt;这不仅仅是简单的 &lt;code&gt;pg_dump&lt;/code&gt;，而是基于流复制（Streaming Replication）的“实时影子库”方案。&lt;/p&gt;
&lt;h2 id="1-需求分析为什么不直接全量备份"&gt;1. 需求分析：为什么不直接全量备份？
&lt;/h2&gt;&lt;p&gt;早期的方案是每天定时跑脚本备份到对象存储，但存在两个痛点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据不一致&lt;/strong&gt;：如果主库在备份间隔内崩掉，会丢失数小时的数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;恢复慢&lt;/strong&gt;：紧急情况下，重新拉起容器并还原 TB 级或 GB 级数据的时间成本太高。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;我的目标&lt;/strong&gt;：在另一台 VPS 上维护一个随时待命的只读副本，一旦主库失联，分钟级完成主从切换。&lt;/p&gt;
&lt;h2 id="2-解决方案流复制--双向-ssl-加密"&gt;2. 解决方案：流复制 + 双向 SSL 加密
&lt;/h2&gt;&lt;p&gt;由于数据需要跨越公网传输，&lt;strong&gt;安全性&lt;/strong&gt;是首要考量。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;传输层安全&lt;/strong&gt;：必须开启 SSL，防止数据在公网被嗅探。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;身份验证&lt;/strong&gt;：不使用简单的密码，而是采用 &lt;strong&gt;双向证书校验（Cert Authentication）&lt;/strong&gt;。只有持有我签发的客户端证书的服务器，才有权连接主库进行数据同步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络隔离&lt;/strong&gt;：非标准端口（如 &lt;code&gt;8765&lt;/code&gt;）+ 严格的防火墙（iptables/ufw）白名单。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-实战避坑指南"&gt;3. 实战避坑指南
&lt;/h2&gt;&lt;h3 id="坑一docker-容器与防火墙的暗箱操作"&gt;坑一：Docker 容器与防火墙的“暗箱操作”
&lt;/h3&gt;&lt;p&gt;在使用 Docker 暴露端口时，Docker 会自动操作 &lt;code&gt;iptables&lt;/code&gt; 规则，导致很多时候即便你没开系统防火墙，端口也是暴露的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;对策&lt;/strong&gt;：手动在 &lt;code&gt;INPUT&lt;/code&gt; 链中通过 &lt;code&gt;-s &amp;lt;备库IP&amp;gt;&lt;/code&gt; 锁定来源地址，并持久化规则（&lt;code&gt;iptables-persistent&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="坑二pg_basebackup-的路径幽灵"&gt;坑二：pg_basebackup 的路径“幽灵”
&lt;/h3&gt;&lt;p&gt;第一次执行 &lt;code&gt;pg_basebackup&lt;/code&gt; 克隆数据时，它生成的 &lt;code&gt;postgresql.auto.conf&lt;/code&gt; 会保留当时临时容器的证书路径（比如 &lt;code&gt;/temp_certs&lt;/code&gt;）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;对策&lt;/strong&gt;：克隆完成后，务必手动修正数据目录下的配置文件，将证书路径指向容器启动时的正式挂载路径（如 &lt;code&gt;/var/lib/postgresql/data/certs/&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="坑三权限权限还是权限"&gt;坑三：权限！权限！还是权限！
&lt;/h3&gt;&lt;p&gt;Postgres 对私钥文件的权限极其挑剔。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;报错&lt;/strong&gt;：&lt;code&gt;could not open file &amp;quot;server.key&amp;quot;: Permission denied&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对策&lt;/strong&gt;：在宿主机执行 &lt;code&gt;chown -R 999:999&lt;/code&gt; 修正 UID。即便在宿主机看是 root，在容器里必须是 &lt;code&gt;postgres&lt;/code&gt; 用户（UID 999）才能读取。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-关键配置概览"&gt;4. 关键配置概览
&lt;/h2&gt;&lt;h3 id="主库-pg_hbaconf-安全策略"&gt;主库 &lt;code&gt;pg_hba.conf&lt;/code&gt; 安全策略
&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-conf" data-lang="conf"&gt;# 仅允许 replication_user 通过证书验证进行流复制
hostssl replication replication_user 备库IP/32 cert
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="备库同步配置-postgresqlautoconf"&gt;备库同步配置 (&lt;code&gt;postgresql.auto.conf&lt;/code&gt;)
&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-conf" data-lang="conf"&gt;primary_conninfo = &amp;#39;user=replication_user host=主库IP port=8765 sslmode=verify-ca sslcert=/path/to/client.crt sslkey=/path/to/client.key sslrootcert=/path/to/ca.crt&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="5-迁移与维护的思考"&gt;5. 迁移与维护的思考
&lt;/h2&gt;&lt;p&gt;关于数据卷映射，我最终选择了 &lt;strong&gt;Bind Mounts（直接路径映射）&lt;/strong&gt; 而非 Docker Named Volumes。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;理由&lt;/strong&gt;：当需要更换服务器迁移备库时，直接一个 &lt;code&gt;tar&lt;/code&gt; 命令打包 &lt;code&gt;/opt/pgsql/data&lt;/code&gt; 极其透明。不需要去翻 &lt;code&gt;/var/lib/docker/volumes/&lt;/code&gt; 那些隐秘的哈希目录，迁移效率提升 200%。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="最后"&gt;最后
&lt;/h2&gt;&lt;p&gt;高可用架构不是为了炫技，而是为了在意外发生时能睡个好觉。目前这套方案在 Uptime Kuma 的监控下表现稳定，主从延迟几乎保持在 0ms。&lt;/p&gt;</description></item></channel></rss>