Wendy's Blog

个人站点自托管实践

9 分钟技术向

托管平台好用,但总有两个时刻你会想自托管:站点需要特定地区直连友好;或者你本来就要一台机器做别的用(代理、Nas、测试)。本文以一次真实迁移为例,把完整路径和里面的坑一次性讲清楚——照着做,不踩第二遍。

📌 适用范围(先看再读):本文案例是纯静态站点——构建期生成 HTML,线上零服务端进程、无数据库。

  • 通用部分(对任何 VPS 上的项目都成立):选型三维度、域名单一不变量、双防火墙、DNS/证书链路、安全加固、代理节点、验证分层、运维模型;
  • 静态专属部分(动态项目请替换):负载画像与"512MB 够用"结论、静态部署流程、缓存策略、纯静态验证标准。 如果你的项目是动态的(前后端分离/SSR/需要数据库与常驻进程),请按"运行时常驻内存 ×2 + 数据库所需"重新评估配置,并在文中标注 ⚠️ 的地方自行对应修订。

一、先定义"好":三个决策维度

买任何境外 VPS 前,先回答三个问题——这三个维度决定 90% 的体验,参数反而是次要的:

维度 要问的问题 对"个人站+代理"的意义
线路 大陆访问走什么路由?晚高峰丢包如何? 访客"秒开"还是"转圈"
换 IP 机制 IP 被墙后能否低成本换? 大陆直连的最大运维事故是"被墙",机制决定痛苦程度
条款 & 门槛 ToS 允许代理吗?支付方便吗? 被删机 = 前功尽弃;支付方式决定能不能买到

负载画像(量化"够用"):以一个纯静态站为例——约 10MB 文件、日请求几十、月流量不足 1GB,同机再挂两个自用代理节点(月流量数 GB 级)。 结论:1 核 / 512MB 起步都行——真正贵的是线路和换 IP 的自由,不是配置。

⚠️ 静态专属:以上画像与结论只适用于"构建期产物 + 文件服务"的静态站。动态项目(服务进程、数据库、定时任务)请以"运行时常驻内存 ×2 + 数据库所需 + 余量"重估配置,不要照搬 512MB——本文后续章节中,除部署方式外,其余方法仍然通用。

二、选型:遍历一圈后的决策框架

候选类别 线路 换 IP 年成本 定位
低价云商(普通跨境线路,163/4837 类) 中低,晚高峰抖动 按次收费(数美元/次) 最低(约 $20) 价格友好,但要接受较高的换 IP 频率与成本
国际大厂主流产品 中等(与运营商适配差异明显,联通/移动通常更佳) 删除重建即换,免费 中等($60-90) 均衡之选,支付无门槛
精品商(CN2 GIA / 9929 / CMIN2 等) 顶级,晚高峰稳定 自助免换有频次,超次可付费 偏高($50-130,视活动) 线路体验天花板
主流平台亚太节点 中上(以实测为准) 删除重建即换,免费 常规价位,促销期可显著更低(视当期活动) 三问均无硬伤时的收敛选项;若促销进一步降低首年成本,属于加分而非必要条件

下单前的关键方法:候选 IP 先用全国连通检测实测(均值 100-200ms、无超时即可用,追求更低延迟再考虑精品线路)——这一步比看参数重要得多,也是"线路"维度唯一的客观裁判。

决策依据浓缩成一句话:

没有硬伤的前提下,选"换 IP 免费 + 支付无门槛"里最便宜的那个;访客体验优先于财务时,再升精品线路。

三、架构:一台机器,多个角色

访客 ──直连──► DNS(灰云解析,不做反向代理)──► 云主机
                                            │
                      ┌─────────────────────┴──────────────────┐
                      ▼                                        ▼
           Web 服务 :443(HTTPS + 静态站点)        代理节点 ×N:高位端口
           /srv/www(站点文件)                    systemd 守护,随机口令

三条关键设计(通用):

  1. 域名是唯一不变量,IP 是消耗品:访客永远访问域名;换服务器只改一条 DNS 记录,访客无感;
  2. 不绑定静态公网 IP:多数云厂商"删除→重建"即换新 IP(分钟级、免费)——这是被墙场景最便宜的自救;
  3. 双重防火墙心智:系统防火墙(ufw)+ 云平台层防火墙是两道独立的门,任何端口都要过两道——新端口只开一道门时,现象是"服务活着,外部永远连不上"。

⚠️ 静态专属:图中 Web 层 = 文件服务(直接吐静态产物)。动态项目在此层替换为应用运行时(如容器或进程管理器,再配数据库与反向代理),架构其余部分(域名、DNS、防火墙、代理节点)保持不变——本文后面"七阶段"里的部署与验证步骤,动态项目按"镜像/代码同步 + 运行时健康检查"对应替换。

四、执行:七个阶段,每步有验证

阶段 做什么 验证什么
初始化 系统升级、Web 服务/防火墙/防爆破、swap、时区、SSH 仅密钥 服务 active、规则到位、swap 生效
部署 本地产物打包 → 上传 → 解压到站点根 文件数/关键文件存在/首页 200
域名切换 DNS API(Token 只给"单域名编辑"最小权限)改 A 记录 回读记录、全国解析一致
HTTPS Web 服务自动签发证书 证书日志、外部抓取 200
节点 代理服务程序(systemd 守护)+ 随机生成端口/口令 服务 active、外部端口连通、客户端实测延迟
安全加固 禁 root 登录、代理进程降权独立用户、审核端口与密钥 服务仍活、端口仍通、权限归位
验收 外部抓取 + 资源 HTTP 状态 + 全国连通检测 + 真机访问 全绿

一个原则:凡"改",必先"记"(配置进仓库脚本);凡"升级",必先"验"(改前改后各查一次)。

五、真实踩坑(本篇核心复用价值)

1. Windows 压缩包解压"丢文件"——换 POSIX tar

Windows 打的 zip 在 Linux 解压会报"反斜杠路径分隔符"警告,严重时中断后文件树残缺——曾出现解压中断导致全部样式丢失,页面白板但 HTML 还在,极具迷惑性。 结论:跨平台部署一律用 tar 打包(tar -czf out.tgz -C out .,解压 tar -xzf),从此不用 zip。

2. 远程命令一行流"中文+括号必崩"——远程操作脚本化

ssh host 'echo 中文(备注)...' 经本地 Shell 传参后,远程 bash 遇到中文括号/管道会报 syntax error near unexpected token结论:所有远程命令写成 .sh 上传执行,零踩坑。

3. 白板事故:只验证 HTML 的盲区

"验证通过"时依赖的是抓取 HTML 文本——CSS 是独立文件,丢没丢文本验证看不到,只有浏览器渲染暴露。 结论:站点验证必须分层:HTML 200 → 引用资源(CSS/JS/字体)逐一 HTTP 状态 → 渲染比对。

4. 旧 HTML + 404 CSS 的缓存残留——HTML no-cache 治本

白板修好后,已访问过的浏览器/应用内置浏览器仍显示旧版,因为旧 HTML 引用着已消失的样式名解法:Cache-Control: no-cache, must-revalidate 给 HTML(每次强制校验),静态资源保持 immutable(一年缓存)。

5. 云平台"隐形门":默认防火墙没有自定义端口

实例建好、证书也签了(验证走 80 端口成功),但测试 443 与高位端口全部超时——平台层防火墙默认只放 22/80,系统里的放行是另一道门结论:任何"端口不通"先问自己:两道门都开了吗?

6. 云主机回流限制:本机连自己公网 IP 失败

服务器上 curl https://域名 返回 000,一度怀疑部署失败——多数云厂商实例访问自身公网 IP 会被网络策略挡住,不代表外部不可达。 结论:服务器自测用 --resolve 域名:443:127.0.0.1 走回环,同时从外部抓取交叉验证。

7. 浏览器"记忆"与无痕模式

普通窗口标签页保留打开那一刻的页面;无痕不吃缓存永远最新。"无痕正常、普通旧"不是故障。 结论:修复/改版后的验收标准动作 = 无痕窗口或"关标签重开"。

8. 批处理快捷指令的三大坑

  • 批处理按 ANSI 解析,UTF-8 中文路径乱码,文件直接"找不到";
  • 脚本里用到了 Shell 内置只读变量($Host),赋值即报错;
  • 有的 cmdlet 根本没有你以为的参数(如 Start-Process-LiteralPath,那是 Invoke-Item 的)。 结论:含中文的路径,用 powershell -EncodedCommand(Base64 编码的 Unicode 命令),让脚本文件本身纯 ASCII,任何语言环境免疫;写脚本前先查参数表。

9. 教程都推新协议,但"稳定版"才是生产选择

代理协议新版本常见"只有 RC/Beta"的过渡期,生产节点应选官方稳定版,与客户端全兼容;升级成本也低(换二进制+改配置)。

10. "买了为什么没扣款"——结算周期焦虑

云账单页面都有小字说明更新/抵扣时机。创建当天显示"已用 $0"是正常现象。 结论:账单类疑问,先读页面小字,再去看账单页——多数"异常"只是周期未到。

11. 验证链缺环:字体不现身 ≠ 字体文件缺失

一客户端正常、另一客户端字体缺失,逐层验证后:全部字体子集在位——问题在客户端缓存。 结论:排查顺序永远是"服务器 → 网络 → 客户端",每层都有可执行的检查,不要跳层下结论。

六、验证体系(可直接复制)

动作 通过标准
HTML 外部抓取首页/文章/RSS/404 200/200/200/404 与内容正确
资源 页面引用的 CSS/JS/字体逐个请求 全部 200,Content-Type 正确
DNS 全国连通检测(填域名) 全网解析一致,平均 <200ms,无超时
端口 443/节点端口外部 TCP 连通 全通
客户端 无痕/关标签重开 + 代理客户端实测 渲染完整;节点延迟 60-180ms
服务 一键状态脚本九项 服务 active,站点 200

七、安全闭环(检查单)

已完成:SSH 仅密钥、root 登录禁用、防爆破、双防火墙仅业务端口、自动安全更新、各服务以独立低权限用户运行、管理端口仅本机、Web 安全头与托管平台同规格、API Token 最小权限+自动到期、凭据双份(完整值本地 + 脱敏索引入库)。 待做三件:云账号开 MFA / 定期实例快照 / 密钥副本入私密保管。

八、运维投入模型:每月 5 分钟

频次 动作
每月 1 号(5 分钟) 状态巡检 + 直连一眼 + 节点延迟 + 凭据档案对照
每季度(10 分钟) 快照 + 全国连通检测 + 账单一眼
信号驱动 访客打不开/节点断 → 先重启服务(10 秒),再查日志
年度 3 个日期 证书基本自动;Token 到期前重生成;计费到期前一个月决策续费或换商

**决策五问:**影响谁?影响多久?数据在吗?修复成本?值得做吗?——大多数"问题"问完五问,就自动降级为"不用管"。

九、可复用的四张模板

A. 选型三问表(见第一节)——任何境外 VPS 决策直接套。 B. 部署检查单:脚本按 00→NN 编号放版本库随项目走(初始化→修复→部署→验证→诊断→加固),每步幂等可重跑;换机或重建后按序执行即完整还原。 C. 故障定位顺序:信号 → 一键状态(服务/端口)→ 全国连通检测(线路)→ 日志 → 客户端重试。 D. 发布流程:写内容 → 构建 → 一键发布(打包+上传+解压+校验)→ 无痕验收。

十、可带走的十条

  1. 先定义"什么算好"——三个维度,不是配置;
  2. 配置可以便宜,换 IP 不能麻烦;
  3. 域名是唯一不变量,IP 是消耗品;
  4. 每道防火墙都要过两道门;
  5. 跨平台部署用 tar,不用 zip;
  6. 远程命令脚本化,别拼一行流;
  7. 验证要分层,HTML 通过 ≠ 渲染正确;
  8. HTML 永不缓存,静态资源一年缓存;
  9. 生产选稳定版,新协议等正式版;
  10. 运维投入按月算:每月 5 分钟,一年 3 个日期。

文中原则(最小权限、双备份、信号驱动、验证分层)适用于任何"小系统 + 长期跑"的场景。