2191 字
约 7 分钟
9
S27-B05 · 自建站点与私有服务实操:从买机器到自动部署

适用读者:第一次自己买服务器建站、被"三口锅四张表"折腾过的人。
前置:S01(开发环境与工具链)、S15(Linux、Docker 与运维交付)、S26(nginx 与证书基础)。
覆盖旧文:3218(Github 博客粉丝转移)、3219(GitHub 被攻击后 Jekyll 修复与重建)、3220(Netty + JavaFx 仿微信上云)、3221(自建云盘 + PDF 预览)、3222(一天建 4 个博客)、3223(Cloudreve 云盘实践)、3224(码农云服务:环境/端口/域名/SSL/博客)、3225(vuepress 迁移踩坑)、3226(webhooks 自动部署)、3227(docsify 所见即所得)、3228(免费服务器部署 ChatGPT 网页版)、3229(搭博客展示经历)→ 12 篇 / 约 4 万字符。
扩展点:E-S27-021(四层自动化阶梯:手动→脚本→Git 钩子→CI)、E-S27-022(webhook 部署的四个安全坑与最小安全实现)、E-S27-023(静态站工具三选一:Jekyll / docsify / VitePress 的判据)。
下一篇:S27-X02 · 学成在线附录源码详解归档。


1. 一句话结论

自建站点的分水岭不是"用哪个框架",是"部署靠手还是靠机":手传 FTP → 脚本拉取 → Git 钩子 → CI 流水线。每上一层,省的是"忘记传某台机器"这类事故;同时每上一层都新增一个可被攻击的入口(3226 的 webhook 就是典型)。

出处:A-3224(云服务全流程)、A-3226(webhooks)、A-3225(迁移)、A-3223(Cloudreve)。


2. 四层自动化阶梯(E-S27-021)

层 做法 省掉什么 新增风险
0 手动 FTP/SFTP 逐台传 — 漏传、版本不一致(3226 的用户就是这样)
1 脚本 rsync -avz --delete dist/ host:/var/www/ 传输重复 无版本可回滚
2 Git 钩子 webhook → 服务器 git pull + 构建 人工触发 公网可达的部署入口(见 §3)
3 CI push → CI 构建 → 产物发布(含回滚) 人工判断 CI 凭据与流水线权限

判据:站点 ≤3 台、内容更新 <每周一次 → 第 2 层足够;多环境/多机房/需要回滚审计 → 第 3 层。不要一步跳到 Kubernetes。


3. webhook 部署的四个安全坑(E-S27-022)

3226 的最小实现是 webhooks.php 里 shell_exec("git pull origin main 2>&1") —— 能跑,但把公网请求直接变成命令执行入口。四个坑按严重度排序:

① 无来源校验:任何人 POST 你的 URL 都能触发部署(甚至注入参数)
   → 校验签名:HMAC-SHA256(body, secret) 与请求头 X-Hub-Signature-256 比对(定时安全比较)
② 参数拼进命令:shell_exec("git pull " . $_POST['branch'])
   → 命令注入。分支名必须白名单(如仅 main),且用数组形式执行、不拼字符串
③ 部署以 root 运行:一旦被利用即整机失守
   → 专用低权限用户 + 只对站点目录有写权限
④ 无并发/无幂等:重复推送并发执行 git pull → 索引锁、构建产物互相覆盖
   → 文件锁(flock)+ 部署队列串行化

最小安全实现(PHP 伪代码,可移植到任意语言):

$secret = getenv('HOOK_SECRET');
$body   = file_get_contents('php://input');
$sig    = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';
$expect = 'sha256=' . hash_hmac('sha256', $body, $secret);
if (!hash_equals($expect, $sig)) { http_response_code(403); exit; }

$payload = json_decode($body, true);
if (($payload['ref'] ?? '') !== 'refs/heads/main') { http_response_code(204); exit; }

$lock = fopen('/tmp/deploy.lock', 'c');
if (!flock($lock, LOCK_EX | LOCK_NB)) { http_response_code(409); exit; }   // 已在部署

// 用数组形式、固定命令,不拼接任何外部输入
exec('sudo -u deploy /opt/deploy/pull_and_build.sh 2>&1', $out, $rc);
flock($lock, LOCK_UN);
http_response_code($rc === 0 ? 200 : 500);
# /opt/deploy/pull_and_build.sh(由 deploy 用户执行,固定分支)
#!/usr/bin/env bash
set -euo pipefail
cd /srv/site
git fetch --prune origin main
git reset --hard origin/main          # 产物可重建,故用 reset 而非 merge
npm ci && npm run build
rsync -a --delete dist/ /var/www/site/

判据:"能否被重放"决定要不要签名——签名防的是伪造请求,flock 防的是并发,低权限防的是被利用后的爆炸半径。三者缺一不可。


4. 静态站工具三选一(E-S27-023)

工具 构建 适合 坑(旧文实测)
Jekyll Ruby + Liquid 老牌、GitHub Pages 原生 依赖 Ruby 环境(3219 重建时踩 gem 源、版本);主题生态旧
docsify 运行时渲染(无构建) 文档型、极简、改完即生效(3227) SEO 差(内容由 JS 渲染)、首屏慢;不适合长文博客
VuePress / VitePress Node 构建为静态 HTML 中文技术博客、Markdown 友好 迁移期配置与主题适配最痛(3225:300 篇从 jekyll 迁 vuepress 差点拉胯)

迁移三原则(3225 的教训):

① 先迁「内容」再迁「样式」:Markdown 与 front-matter 先跑通,主题后调
② 保留旧 URL 映射:生成 301 表(旧路径→新路径),否则外链与搜索收录全废
③ 一次性全量迁移前,先迁 10 篇做端到端验证(构建、图片、代码高亮、锚点、RSS)

判据:"内容要 SEO / 要长文"就别选 docsify;"只要内部文档、改完立刻看"选 docsify 最省。


5. 私有服务的三类最小实现

服务 最小实现 关键配置 风险点
云盘(3221/3223) Cloudreve(Go 单体 + SQLite/MySQL) 存储策略(本地/对象存储)、分享链接有效期、限速 目录遍历与分享越权;默认管理员口令
PDF 预览 前端 pdf.js 或后端转图 大文件分片、Range 请求 内存爆(整本加载)
多媒体/AI 网页(3228) 反向代理 + 密钥放服务端 nginx proxy_pass + 超时 把 API Key 写进前端 JS(等于公开)

判据:"任何密钥出现在浏览器可见处即视为泄露"——前端只能持短期票据,长期密钥留在服务端或网关。


6. 域名、端口、证书与备案(3224 的可执行清单)

□ 域名:注册 → 实名 → (国内服务器)备案 → DNS 解析到服务器公网 IP
□ 端口:只开 22/80/443;应用端口(如 8080)只监听 127.0.0.1,由 nginx 反代
□ 证书:Let's Encrypt(certbot --nginx)或云厂商免费证书;配置自动续期与到期告警
□ nginx:80 全量 301 到 443;HSTS 谨慎开启(先确认全站 HTTPS 可用)
□ 防火墙:ufw/firewalld 默认拒绝入站;云安全组与系统防火墙两处都要开
□ 备份:站点目录 + 数据库每日备份,**备份文件不在同一台机器**

验证命令(只读,安全):

ss -lntp | grep -E ':(22|80|443|8080)'      # 确认监听地址
curl -sI https://DOMAIN | head -5           # 状态码与 HSTS/CSP 头
echo | openssl s_client -connect DOMAIN:443 -servername DOMAIN 2>/dev/null | openssl x509 -noout -dates

7. 反例:七种"建完就后悔"

做法 后果
FTP 逐台传 三台机器版本不一致(3226 用户原话)
webhook 无签名、root 执行 公网可触发命令执行
应用端口直接暴露公网 绕过 nginx 的限流与鉴权
密钥写进前端 一夜之间被刷爆额度
docsify 做长文博客 搜索引擎收录差、首屏慢
迁移不做 301 旧外链全 404,流量归零
备份与站点同机 机器挂了备份一起没

8. 自测

  1. 四层自动化阶梯各层省什么、新增什么风险?
  2. webhook 部署的四个安全坑与对应措施?
  3. Jekyll / docsify / VuePress 的判据?
  4. 迁移三原则?
  5. 域名端口证书清单里,哪两项最容易被漏?
答案
  1. 手动→脚本→Git 钩子→CI;省人工与不一致,新增公网入口与凭据风险。
  2. 无签名(HMAC+定时安全比较)、命令注入(白名单+数组执行)、root 运行(低权限用户)、并发(flock)。
  3. 要 SEO 与长文用 VuePress/VitePress,内部文档用 docsify,GitHub Pages 生态用 Jekyll。
  4. 先内容后样式、保留 301 映射、先迁 10 篇端到端验证。
  5. 应用端口只监听 127.0.0.1、备份不在同一台机器。

9. 下一篇

S27-X02 · 学成在线附录源码详解归档 —— A–L 十个附录(185 万字符)的模块划分、与 S07/S08/S11/S17 主讲篇的映射表,以及为什么这批教材附录不做点位级吸收。


本篇属于系列《S27 · 杂项归档与工具实测》。旧文来源:A-3218–3229(12 篇自建站实操,作者 小傅哥 / bugstack.cn);扩展点 E-S27-021/022/023。文中命令与配置在 Ubuntu 24.04 + nginx 1.25 口径下核对,具体版本差异需按环境验证。

S27-B05 · 自建站点与私有服务实操:从买机器到自动部署
https://www.clxhxhhr.top/posts/5618/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。