网站上线不是结束:备份、日志、更新与下一阶段
网站上线不是结束:备份、日志、更新与下一阶段
网站第一次通过 HTTPS 打开时,很容易产生一种错觉:完成了。
准确地说,只是它开始需要被照顾了。
程序会更新,数据库会增长,证书会续期,磁盘会变满,错误会挑你吃饭时出现。上线后的工作不必复杂,但必须能回答四个问题:
- 服务现在活着吗?
- 出错后去哪里找原因?
- 数据丢了能恢复吗?
- 更新失败能退回去吗?
下面是一套适合单机 Go 网站的最低运维方案。
一、先建立固定检查顺序
网站打不开时,不要随机重启所有服务。按照请求经过的顺序检查:
DNS -> 防火墙 -> Caddy -> Go -> PostgreSQL
1. 域名是否解析正确
getent ahostsv4 example.com
如果 IP 不对,先改 DNS。应用重启十次也修不好域名解析。
2. Caddy 是否运行
sudo systemctl status caddy --no-pager
sudo journalctl -u caddy -n 100 --no-pager
证书申请、端口占用、Caddyfile 语法错误都会出现在这里。
3. Go 服务是否运行
sudo systemctl status cairn --no-pager
sudo journalctl -u cairn -n 100 --no-pager
绕过 Caddy 直接检查:
curl -i http://127.0.0.1:8080/healthz
如果本机健康检查成功、域名访问失败,问题多半在 Caddy、证书、DNS 或防火墙,不在 Go。
4. 数据库是否健康
cd /opt/cairn
sudo docker compose --env-file /etc/cairn/cairn.env ps
sudo docker compose --env-file /etc/cairn/cairn.env logs --tail=100 db
不要忘记 --env-file。生产环境的 Compose 文件引用了 DB_PASSWORD,缺少环境文件时连 ps 都可能先报变量错误。
二、让日志能回答问题
Go 服务使用结构化日志输出到标准输出,systemd 会统一收集:
sudo journalctl -u cairn
查看最近日志:
sudo journalctl -u cairn -n 100 --no-pager
持续跟踪:
sudo journalctl -u cairn -f
查看某段时间:
sudo journalctl -u cairn \
--since "2026-06-21 14:00:00" \
--until "2026-06-21 15:00:00"
有用的应用日志至少应该包含:
- 请求或操作发生的时间;
- 日志级别;
- 发生错误的模块;
- 可以定位问题的资源标识;
- 原始错误信息。
不要把密码、Session token、完整 Cookie 或数据库连接串写入日志。日志是排查工具,不是秘密收藏夹。
对于 HTTP 请求,建议记录方法、路径、状态码和耗时,但不要无差别记录请求体。登录表单和评论内容都可能包含不适合长期保存的信息。
三、备份成功不等于可以恢复
PostgreSQL 可以通过 pg_dump 生成逻辑备份:
set -a
source /etc/cairn/cairn.env
set +a
timestamp="$(date -u +%Y%m%dT%H%M%SZ)"
PGPASSWORD="$DB_PASSWORD" pg_dump \
--host 127.0.0.1 \
--port 5432 \
--username cairn \
--dbname cairn \
--no-owner \
--no-privileges |
gzip > "/var/backups/cairn/cairn-${timestamp}.sql.gz"
备份目录应归专用服务用户所有,并限制权限:
sudo install -d -o cairn -g cairn -m 0750 /var/backups/cairn
可以用 systemd timer 定时执行。备份服务运行完成后显示:
inactive (dead)
对 Type=oneshot 服务来说,这是正常状态:任务执行成功后退出,并不是服务挂了。真正要看的是退出码和日志:
sudo systemctl status cairn-backup.service --no-pager
sudo journalctl -u cairn-backup.service -n 50 --no-pager
sudo systemctl list-timers cairn-backup.timer
定期做恢复演练
只有真正恢复过的备份,才值得信任。
可以创建临时数据库:
sudo docker exec cairn-db-1 \
psql -U cairn -d postgres \
-c "CREATE DATABASE cairn_restore_test;"
恢复最近一次备份:
latest_backup="$(ls -1t /var/backups/cairn/cairn-*.sql.gz | head -n 1)"
gunzip -c "$latest_backup" |
sudo docker exec -i cairn-db-1 \
psql -U cairn -d cairn_restore_test
检查核心表:
sudo docker exec cairn-db-1 \
psql -U cairn -d cairn_restore_test \
-c "\dt"
确认后删除临时数据库:
sudo docker exec cairn-db-1 \
psql -U cairn -d postgres \
-c "DROP DATABASE cairn_restore_test;"
恢复演练可能暴露很多问题:压缩包损坏、权限不对、备份脚本没读到密码、磁盘里只剩空文件。比起真正丢数据时才发现,提前尴尬划算得多。
四、建立可回退的更新流程
更新应用不要直接覆盖正在运行的二进制。一个简单而可靠的流程是:
上传源码
-> 编译新二进制
-> 备份旧二进制
-> 执行迁移
-> 原子替换
-> 重启
-> 健康检查
在服务器上编译临时文件:
cd /opt/cairn
go build -trimpath -ldflags="-s -w" -o bin/cairn.new ./cmd/server
先确认它确实是可执行文件:
file bin/cairn.new
ls -lh bin/cairn.new
备份当前版本并替换:
sudo cp bin/cairn "bin/cairn.$(date -u +%Y%m%dT%H%M%SZ)"
sudo mv bin/cairn.new bin/cairn
sudo chown cairn:cairn bin/cairn
sudo chmod 755 bin/cairn
sudo systemctl restart cairn
立即验收:
sudo systemctl status cairn --no-pager
curl -fsS http://127.0.0.1:8080/healthz
curl -fsS https://example.com/healthz
如果启动失败:
sudo journalctl -u cairn -n 100 --no-pager
确认是新版本问题后,再把最近的旧二进制恢复并重启。不要看到错误就先删数据库、清卷或重装服务器,那属于用拆房子的方式修门锁。
五、迁移必须考虑新旧版本兼容
数据库迁移比替换二进制更难回退,因为数据结构已经发生变化。
较稳妥的做法是采用“先兼容,再切换,最后清理”:
- 第一版迁移只增加新列或新表,旧程序仍能运行;
- 新程序开始同时支持旧结构和新结构;
- 数据回填完成;
- 确认没有旧程序运行;
- 后续版本再删除旧列。
例如把评论作者从文本用户名改成 user_id,不要在同一次发布里直接删除用户名列并要求所有数据立刻完美。可以先增加 user_id,完成关联和回填,验证查询稳定后,再用下一条迁移清理旧字段。
这是数据库领域里很朴素的一条经验:加东西通常容易回退,删东西通常很有主见。
六、监控先从最小可用开始
个人网站不一定需要立刻搭建一套监控平台,但至少要有外部健康检查。
外部服务可以定时请求:
https://example.com/healthz
不过健康检查不能只返回“Go 进程还活着”。如果页面依赖数据库,接口最好执行一次轻量数据库探测,并设置超时。
同时要注意:健康检查不应该泄露数据库地址、版本、错误堆栈或服务器信息。对外只返回必要状态,详细原因写入服务端日志。
本机也可以定期检查磁盘:
df -h
du -sh /var/backups/cairn
sudo journalctl --disk-usage
数据库备份和日志都很擅长悄悄吃满磁盘。备份脚本应设置保留周期,例如删除 30 天前的文件:
find /var/backups/cairn \
-type f \
-name 'cairn-*.sql.gz' \
-mtime +30 \
-delete
删除策略上线前先把 -delete 换成 -print,确认匹配结果正确。
七、秘密也需要维护
生产环境至少要定期检查:
- 数据库密码是否足够强;
- 环境文件是否只有必要用户可读;
- SSH 是否关闭密码登录并使用密钥;
- 系统和 Docker 是否及时安装安全更新;
- 不再使用的账号和密钥是否已经撤销;
- 备份文件是否被错误暴露到 Web 目录。
修改数据库密码时,要同时更新 PostgreSQL 和应用环境文件,并安排一次可控重启。只改一边,得到的通常不是“更安全”,而是“连接失败”。
八、下一阶段应该先做什么
网站上线后,很容易进入功能许愿池:搜索、标签、归档、后台、对象存储、访问统计、邮件通知,好像每个都应该马上出现。
排序标准可以简单一点:
- 数据是否安全;
- 读者能否顺利阅读;
- 作者能否稳定发布;
- 功能是否解决了反复出现的问题。
按这个标准,一个内容型网站更合理的顺序通常是:
备份恢复
-> 错误日志与外部健康检查
-> 发布体验
-> 标签和归档
-> 搜索
-> 图片管理
-> 访问统计
Redis、搜索引擎、对象存储当然都有价值,但应该在问题出现以后引入。没有性能瓶颈时先部署缓存,往往只是多得到一个需要备份、监控和排错的服务。
结尾
上线前,开发关注“功能能不能工作”;上线后,关注点会悄悄变成:
- 它能不能一直工作;
- 出问题能不能看懂;
- 数据能不能找回来;
- 更新能不能安心进行。
这四件事没有炫目的界面,却决定了一个网站究竟是偶尔能打开的作品,还是可以长期生长的系统。
评论
暂无评论,来说点什么吧。
请先登录后再发表评论
去登录