Git 远程自建服务器完整指南
在自有 Linux 服务器上搭建 Git 远程仓库,用法与 GitHub SSH 一致:git push / git pull 同步代码,主机换成你的 VPS,仓库路径自行创建。
适用场景:私有仓库、内网部署、推送后自动发布静态站(如 Hexo)。
一、整体架构
flowchart LR
subgraph local["本地"]
A["工作区 .git"]
end
subgraph server["服务器"]
B["git 用户 + SSH"]
C["裸仓库 xxx.git"]
D["post-receive"]
E["网站目录"]
end
A -->|git push| B --> C --> D --> E
| 概念 | 说明 |
|---|---|
| 裸仓库 | 仅含 .git 数据,无工作区,专用于接收 push |
| git 用户 | 独立系统账号 + SSH 鉴权,避免用 root 推代码 |
| 远程地址 | git@IP:/home/git/项目.git,与 GitHub SSH 格式相同 |
二、原理速览
传输协议
Git 远程 = 传输通道 + pack 交换(git-upload-pack / git-receive-pack)。URL 前缀决定鉴权与传输方式,对象协商逻辑不变。
| 协议 | 示例 | 说明 |
|---|---|---|
| SSH | git@host:/path/repo.git |
本文推荐,密钥认证 |
| HTTPS | https://host/repo.git |
走 443,适合 Gitea/GitLab |
| 本地/file | /path/repo.git |
同机脚本或备份 |
| git:// | git://host/path |
无加密,公网不推荐 |
自建场景即 Smart over SSH:远端运行 receive-pack,双方协商差异后传输 packfile,而非拷贝整个目录。
push 做了什么
- 客户端声明要更新的 ref(如
refs/heads/master) - 计算远程缺失的对象,打成 pack 发送
- 对象落盘后原子更新 ref
- 触发服务器钩子(若配置)
git push 传的是 对象与引用,不是工作区文件夹;裸仓库无检出目录,不会自动更新网站——需 post-receive 钩子完成部署。
SSH push 流程
sequenceDiagram
participant Dev as 本地 git
participant SSH as SSH
participant Recv as receive-pack
participant Repo as 裸仓库
participant Hook as post-receive
Dev->>SSH: ssh git@host git-receive-pack 'repo.git'
SSH->>Recv: 鉴权并启动
Recv->>Dev: 协商 want/have
Dev->>Recv: 上传 pack
Recv->>Repo: 写入 objects,更新 refs
Recv->>Hook: 调用钩子
鉴权在 SSH 层(authorized_keys);git-shell 可限制用户仅执行 Git 命令。
钩子与自动部署
| 钩子 | 时机 | 用途 |
|---|---|---|
| pre-receive | ref 更新前 | 拒绝不合规 push |
| post-receive | 全部 ref 更新后 | 部署:checkout、构建 |
| post-update | 之后 | 通知、清缓存 |
post-receive 从 stdin 读取 旧SHA 新SHA 引用名。裸仓库检出需指定环境变量:
1 | |
钩子以 git 用户运行,需 chmod +x 且去掉 .sample 后缀才生效。
三、服务器配置
以下在服务器执行(Ubuntu/Debian 示例)。
3.1 基础环境
1 | |
3.2 添加公钥
本地生成密钥:
1 | |
服务器追加公钥:
1 | |
本地验证:ssh -i ~/.ssh/id_ed25519_git git@服务器IP。若提示 Interactive git shell is not enabled,说明 SSH 已通。
3.3 创建裸仓库
1 | |
远程地址:git@服务器IP:/home/git/my-blog.git
3.4 自动部署(可选)
1 | |
1 | |
1 | |
3.5 安全建议
sshd_config:PasswordAuthentication no,PermitRootLogin no- 防火墙仅开放 SSH:
sudo ufw allow OpenSSH && sudo ufw enable
四、本地关联与推送
多密钥时指定私钥:
1 | |
添加远程并推送:
1 | |
日常:git pull / git push / git clone,与 GitHub 无异。
可与 GitHub 并存:
1 | |
五、扩展与排错
多项目:在 /home/git/ 下为每个项目建 xxx.git 裸仓库。
多人协作:将各人公钥追加到 authorized_keys;需细粒度权限可上 Gitolite / Gitea。
| 现象 | 处理 |
|---|---|
Permission denied (publickey) |
检查公钥、core.sshCommand、私钥路径 |
not a git repository |
确认路径存在且已 init --bare |
| push 成功但站点未更新 | 钩子权限、分支名、hexo generate 是否执行 |
| 钩子写文件失败 | chown git:git 部署目录 |
查看服务器最近提交:
1 | |
六、检查清单
服务器
-
git用户与authorized_keys就绪 -
/home/git/项目.git已init --bare - (可选)
post-receive可执行、部署目录可写
本地
-
ssh -i 私钥 git@IP认证通过 -
git remote -v指向正确地址 -
git push -u origin master成功
备份裸仓库:直接打包 /home/git/*.git 目录即可。