用 git 管 /etc:配置文件改坏了随时回滚

Nginx 配置改崩了,却想不起来改了哪一行?小够教你用 git 管理 /etc:每次改配置先提交,翻车了一条命令回滚,etckeeper 自动化的方案也讲。

我是小够。每个运维都经历过:改 Nginx 配置调优,改完 reload 报错,想回滚,却想不起来刚才改了哪三行。配置文件也需要版本管理,git 不只是管代码的。

手动方案:十分钟搭起来

cd /etc
sudo git init
sudo git add .
sudo git commit -m "初始提交:$(date +%F)"

以后每次改配置前,先提交一次:

cd /etc
sudo git add nginx/sites-available/mysite.conf
sudo git commit -m "mysite: 开启 gzip 压缩"

翻车了?

# 看改了什么
sudo git diff
# 回滚单个文件
sudo git checkout -- nginx/sites-available/mysite.conf
# 回到上一个提交
sudo git log --oneline
sudo git reset --hard <commit>

敏感文件别进仓库

/etc 里有影子文件、密钥,不能全提交。.gitignore 写好:

shadow
shadow-
gshadow
gshadow-
*.key
*.pem
ssh/ssh_host_*

或者用 git add 只加你要管的文件,别 git add . 无脑全加。

etckeeper:自动化方案

手动提交容易忘,etckeeper 是专干这个的工具:

sudo apt install etckeeper

它做三件事:

  1. 每天自动提交一次 /etc 的变化
  2. apt 装软件前后自动提交(装了个包改了配置?有记录)
  3. 自动处理文件权限(git 不存权限,etckeeper 用元数据补上)

装上基本不用管,cd /etc && sudo git log 随时翻历史。

工作流建议

  1. 改前提交:养成习惯,改配置前 git commit 存个干净版本
  2. 提交信息写清楚:写"为什么改",不只写"改了什么"——三个月后你只记得为什么
  3. 大改前打 tag:git tag before-nginx-rewrite,回滚更快
  4. 异地推一份:/etc 的 git 仓库定期 push 到备份服务器,机器没了配置还在

小够的结论

配置管理的本质是:任何时候都知道"现在是什么样"和"之前是什么样",并且能回去。git 管 /etc 是成本最低的实现,etckeeper 让它自动化。别等到改崩了才想起这篇,装机的时候就配好。

etckeeper 深入配置

etckeeper 装完基本不用管,但有几个配置值得看:

# /etc/etckeeper/etckeeper.conf
VCS="git"                    # 默认 git,不用动
AVOID_DAILY_AUTOCOMMITS=1    # 每天自动提交?小够建议关掉,手动提交更有意义
AVOID_COMMIT_BEFORE_INSTALL=1 # apt 装包前自动提交?建议开着

每天自动提交会产生大量"无意义提交",淹没真正的手动修改。小够的习惯:自动提交全关,手动提交,提交信息写清楚。

pre-commit hook:提交前自动检查

.git/hooks/pre-commit 里加检查,Nginx 配置语法不对就不让提交:

#!/bin/bash
nginx -t 2>/dev/null || {
    echo "Nginx 配置语法错误,拒绝提交!"
    exit 1
}

配置管理+语法检查双保险,翻车率再降一档。

多台机器:配置同步

几台机器的 Nginx 配置大同小异?把 /etc 的 git 仓库 push 到备份服务器:

# 在备份服务器上建裸仓库
git init --bare /data/configs/vps-a.git
# 每台机器加 remote,定期 push
git remote add backup backupuser@backup-server:/data/configs/vps-a.git
git push backup master

好处:

  1. 配置异地有备份
  2. 新开机器直接 git clone,配置秒同步
  3. 对比两台机器的配置差异:git diff

敏感信息处理:仓库是私有的,但密码、密钥还是别进。用 git-crypt 给敏感文件单独加密,或者敏感配置用模板+变量,变量放别处。

实战:一次完整的回滚

场景:改 Nginx 开启 HTTP/3,reload 后网站 502。

cd /etc
# 1. 看刚才改了什么
sudo git diff
# 2. 确认是这次改动的问题,直接回滚文件
sudo git checkout -- nginx/sites-available/mysite.conf
# 3. reload
sudo systemctl reload nginx
# 4. 网站恢复,刚才的提交还在历史里,事后慢慢研究

从发现 502 到恢复,全程 2 分钟。这就是版本管理的价值:回滚的速度,取决于你多快能找到"上一个能用的版本"。

和配置管理工具的关系

Ansible、Salt 这些是"配置管理"的重武器,适合几十台机器。几台 VPS 的个人用户,git + etckeeper 完全够用,别为了用工具而用工具。等机器多到 git 管不过来了,再上 Ansible 不迟。

常见问题

Q:/etc 里好多文件,哪些值得管? A:你亲手改过的都值得:nginx/、ssh/、systemd/system/、fstab、sysctl.conf、cron.d/。没动过的文件不用管,etckeeper 初始提交会有点大,之后都是增量。

Q:git 仓库放 /etc 里,权限问题? A:etckeeper 会处理权限元数据。手动方案的话,.git 目录权限设 700,只让 root 进。别把 .git 暴露给 Web 服务。

Q:和备份是什么关系? A:互补。git 管"配置的变化历史",备份管"数据的完整快照"。配置回滚用 git,整机恢复用备份。两个都要有。

.gitignore 实战模板

# 密码影子文件
shadow
shadow-
gshadow
gshadow-

# 主机密钥
ssh/ssh_host_*

# 应用密钥
*.key
*.pem
*.p12

# 敏感配置(按需)
# mysql/debian.cnf

提交前 git status 看一眼,别把不该进的加进去。已经误提交的:git rm --cached 移出来,再重写历史(filter-branch 或 BFG),但已经 push 到异地的……就当交学费,赶紧换密钥。

提交信息规范

nginx: 开启 gzip,提升首屏速度

- 压缩级别 6,兼顾 CPU 和体积
- 图片目录排除,已经压过的别再压

格式:范围: 一句话 + 空行 + 原因。小半年后回看,你会感谢现在写清楚的自己。

分支策略:别只在 master 上玩

# 大改前开分支
sudo git checkout -b nginx-http3
# 改,测试,没问题再合并
sudo git checkout master
sudo git merge nginx-http3

听起来像开发流程,但配置改崩的代价一点不比代码小。分支用起来,稳。

和 Ansible 的配合

等机器多了上了 Ansible,git 管 /etc 照样有用:

  • Ansible 的 playbook 放 git 仓库,和 /etc 历史分开管
  • 机器上的 etckeeper 记录"实际生效的配置"
  • 两边对照:playbook 说应该这样,etckeeper 说实际那样,不一致就是有人手动改了

手动改配置是运维的大忌,有了版本历史,至少能发现、能回滚。

小够的习惯

小够每台 VPS 装机第一天就做三件事:etckeeper 装上、初始提交、.gitignore 写好。之后每次改配置,提交信息里写"为什么"。这个习惯坚持一年,你的 /etc 就是一本运维日记——哪天出了怪问题,git log 一翻,答案往往就在里面。

etckeeper 卸载与迁移

换机器了,etckeeper 的历史怎么带走:

# 老机器:打包整个 /etc/.git
tar -czf etckeeper-history.tar.gz -C /etc .git
# 新机器:装好 etckeeper 后解压覆盖
tar -xzf etckeeper-history.tar.gz -C /etc

历史跟着走,新机器上 git log 能看到老机器的变更记录。运维知识的传承,有时候就是这几 MB 的 git 历史。

忽略特定文件

有些文件天天变,加进版本没意义(比如 resolv.conf):

# /etc/.gitignore
resolv.conf
mtab

etckeeper 默认已经忽略了一批,AVOID_SPECIAL_FILE_WARNING 相关配置可以看。原则:只管"你亲手改的",不管"系统自动变的"。

对比两台机器的配置

# 把两台机器的 /etc 仓库都 clone 到本地
git --git-dir=/tmp/vps-a.git log --oneline
git --git-dir=/tmp/vps-b.git log --oneline
# diff 两个分支
git diff vps-a/master vps-b/master -- nginx/

“为什么 A 机器行、B 机器不行”,diff 一下配置,答案常常就在里面。这是版本管理附赠的排错神器。

小够的最终建议

配置版本管理这件事,越早做越好,成本越低。装机第一天 10 分钟,换来的是:永远知道配置怎么变成今天这样的,永远能回去。和备份一样,属于"没出事时觉得多余,出事时救命"的东西。

记住三个习惯:改前提交、信息写清、敏感不进。做到这三条,你的 /etc 就比 90% 的人管得好。