Skip to content

02 | 生产环境入门:部署到云服务器

在上一篇文章中,已经在本地用 Nginx 跑通了静态站点。然而,http://localhost 只有你自己的电脑能访问。如果想让网站发布到互联网,需要将它部署到

什么是生产环境

从本地开发到线上生产,核心变化在于服务对象的改变。我们用一张表直观对比:

维度 (Development)生产环境 (Production)
服务用户你自己互联网真实用户
运行时间随用随开7 × 24 小时无间断
网络边界本地局域网互联网公网可达
数据故障随时重来线上事故

要让网站,生产环境必须跨越两个最低门槛:7 × 24 小时运行具备公网 IP。对于个人而言,最快捷、低成本的达成方案就是租用一台

为什么选择云服务器

满足 7 × 24 小时运行和公网 IP 这两个条件,最短路径就是云服务器。云厂商对新用户扶持力度大,包年购买一台入门的 2 核 2G(2C2G) 轻量服务器通常只需数十元。

在选购云服务器时,规格选择 2 核 2G,系统镜像首选 Ubuntu 22.04 或 24.04 LTS,避开预装各种面板的系统,保持环境纯净。

您可以通过我的专属优惠链接直接选购:

💡 运维小经验:2C2G 的配置为什么够用? Linux 生产服务器无须运行图形界面,系统本身开销通常不到 200MB。Nginx 作为服务器时也很轻量,2GB 内存足以支撑个人站点和学习环境。

准备工作

SSH 连接服务器

购买云服务器后,你通常会拿到三类信息:

信息作用
公网 IP从互联网访问这台服务器
登录用户不同厂商系统可能不同,推荐使用默认用户 ubuntu
登录密码或 SSH 密钥用来证明“你有权限登录”

连接服务器有两种常见方式。

方式一:在本地终端使用 SSH

这是最推荐掌握的方式,因为后续部署、上传文件、排查问题都离不开命令行:

bash
ssh ubuntu@your-public-IP

如果云厂商默认用户不是 ubuntu,就把命令里的 ubuntu 换成对应用户名,高权限操作通过 sudo 临时提权,能降低误删系统文件、误改全局配置的风险。

bash
whoami

可以查看当前登录用户。

首次 SSH 连接会提示确认主机指纹,输入 yes,然后输入服务器登录密码即可登录。

连接成功后,你会看到类似这样的终端提示:

text
Welcome to Ubuntu 24.04 LTS (GNU/Linux 5.15.0-xx-generic x86_64)

ubuntu@your-server:~$

这说明你已经登录到一台运行在云端的 Linux 服务器上了。

方式二:使用云厂商提供的 WebUI

阿里云、腾讯云等控制台通常都提供“远程连接”之类的浏览器入口(腾讯云侧常见为 OrcaTerm 等),不需要你本地先配好 SSH。

WebUI 适合第一次确认服务器能否登录。但它更像备用入口:后续 scp 上传、脚本化部署、CI 自动发布,都会更依赖本地终端里的 SSH。

密码登录和 SSH 密钥有什么区别

SSH 是连接服务器的协议,密码和 SSH 密钥是两种不同的认证方式。

认证方式怎么理解优点缺点
密码登录输入服务器账号密码简单直观,适合初学者第一次登录容易被弱密码、撞库、暴力破解影响
SSH 密钥本地保存私钥,服务器保存公钥更安全,适合长期使用和自动化部署初学者第一次配置稍微复杂

我的建议是:初学者第一次学习可以先用 ubuntu 用户 + 密码登录,跑通完整流程;一旦网站真正长期在线,就切换到 SSH 密钥登录,并关闭 root 密码登录。

把终端这把剑磨快

开发写代码、运维连服务器、排障看日志——软件从业者几乎每天都要和终端、Shell 打交道。GUI 能完成一部分工作,但一到 SSH、脚本、批量操作、远程排查,终端才是真正的主战场。

既然这把剑天天出鞘,就值得认真武装:选一个顺手的终端 App,配好 Shell 与必备插件,让补全、高亮、分屏成为肌肉记忆。App 决定长相,插件决定手感,两者叠加,不冲突。Windows 用户用 PowerShell 即可上手;想和云服务器对齐,装 WSL Ubuntu(Linux 子系统)并用 Windows Terminal 打开——本地与云上同一套 Linux 习惯,不用来回翻译。Mac 自带 Terminal 已够用;想换更现代的 AI 终端,Warp 值得一试。选型见延伸阅读。

按环境把“剑”磨利:

使用环境推荐阅读
MacMac 终端起手式:iTerm2、zsh 与插件
WindowsWindows 上使用 WSL Ubuntu 开发
云服务器云服务器 Linux 起手式优化

安装 Nginx

在服务器上安装 Nginx(和本地一样的步骤):

bash
sudo apt update
sudo apt install nginx

验证安装:

bash
nginx -v

启动 Nginx:

bash
sudo systemctl start nginx

如果浏览器访问公网 IP 加载超时,优先检查云控制台的 或“防火墙”是否已放通 TCP 80 端口。

此时在浏览器访问 http://your-public-IP,应该能看到 Nginx 默认欢迎页面。恭喜,你的服务器已经在公网可访问了。

手动部署

现在把本地的网站文件传到服务器上。

本地构建

在本地项目目录中构建生产版本:

bash
pnpm run docs:build

构建产物在 docs/.vitepress/dist/ 目录下。

scp 上传到服务器

使用 scp 命令将构建产物上传到服务器:

bash
scp -r docs/.vitepress/dist ubuntu@your-public-IP:~/

这条命令做了什么:

  • scp:基于 SSH 的文件复制命令
  • -r:递归复制目录
  • docs/.vitepress/dist:本地构建产物目录
  • ubuntu@your-public-IP:~/:复制到服务器 ubuntu 用户的家目录

上传完成后,登录服务器,将文件复制到 Nginx 静态资源目录:

bash
sudo cp -r ~/dist/* /var/www/html/

静态资源已经复制到 Nginx 目录,不需要重启 Nginx。刷新浏览器访问 http://your-public-IP,看到你的网站了——这就是 上线。

上线只是开始

到这里,你已经完成了一次完整的“本地 → 服务器”部署。流程是通的,但用不了多久你就会遇到这些问题。

本地和服务器环境不一致

部署不是一步到位的。第一次把网站放到服务器上,大概率不会一次成功——Nginx 配置路径不对、权限不够、文件位置不对,都需要登录服务器反复调试。这意味着你需要同时维护本地开发环境服务器生产环境两套配置。

回顾一下:本地 Mac 上安装 Nginx 用 brew install nginx,服务器 Ubuntu 上用 apt install nginx,连安装方式都不一样。配置文件路径也不同——Mac 在 /opt/homebrew/etc/nginx/,Ubuntu 在 /etc/nginx/

好消息是,这些差异通常只需要首次部署时排查清楚,后续就稳定了。坏消息是,可迁移性很差——如果你换了一台服务器(比如从阿里云换到腾讯云),或者换了操作系统版本,之前踩过的坑可能要重新踩一遍。环境配置的细节散落在操作记忆里,没有被固化下来。

当前部署的是纯静态资源,跨平台传输没有问题。但涉及编译产物时,环境差异的影响会更加突出,我们在第 04 篇展开。

每次发布都要手动 scp

软件交付其实分两段,节奏完全不同

阶段角色环境节奏在干什么
开发开发者本地循环多次改 → 预览 → 再改,直到满意
部署开发者操作本地 → 云服务器验收后通常一次构建 → 上传 → 落盘 → 公网验证

一句话:多次 dev,一次 prod——本地转很多圈;生产发布是“做完再发”,不是边改边发。

多次开发闭环、一次生产发布

本地热更新很快;真正费事的是验收后那一次跨机器发布——构建在本地,上传与落盘在云服务器,验证还要看公网。步骤一多就容易漏,表面都是“页面没变化”。

不过发布链本身可以模板化:构建 → 上传 → 落盘 → 验证。这就是 (Pipeline)的雏形——也是本系列给“运维工作”下定义的入口。

用数学语言定义运维工作

业务工作回答“改什么”:文案、功能、逻辑。
运维工作回答“怎么稳定地让改动变成线上可用状态”:同一套动作可重复、可验证,不因业务细节每次重写。

本系列把(自动化)运维先钉成一句定义:

在约定的规范集合内,用固定结构的运维动作,把任意一次合法业务变更,稳定变成约定的发布结果。

写成数学形态:

xX,f(x)=c\forall x \in X, \quad f(x) = c

符号含义在本篇的例子
xx一次具体的业务变更(源码改动)改了一段 Markdown
XX规范集合:这套流程承诺能接管的变更范围“VitePress 静态站点”
ff运维动作:固定结构的动作链构建 → 上传 → 落盘 → 验证
cc约定结果:产物路径、落盘位置、验证方式一致dist//var/www/html,公网可访问

读法:只要 xx 仍落在 XX 内,ff 就不改。 业务可以改一万次;运维侧重复同一条动作链。

关键在于 XXff 的关系,而不是公式本身:

  • 业务仍在 XX 内(文案、参数、局部逻辑)——ff 不动。
  • 变化突破 XX(换构建工具、引入新中间件、交付形态变了)——ff 才演进。
  • ff 演进后,对更大的 XX' 重新闭合。

X突破Xff,xX:f(x)=cX \xrightarrow{\text{突破}} X' \quad\Rightarrow\quad f \to f', \quad \forall x' \in X': f'(x') = c'

因此,运维工作的稳态是关于 XX 的闭包:集合内业务怎么热闹都与 ff 无关;只有边界被突破时,ff 才升级一次,然后再次回到“对所有 xx 输出恒定”。
“集合 → 闭包 → 扩容 → 再闭包”——这正是后续 DevOps、CI/CD 能持续运转的基石:让运维动作稳定,业务变化自由。

套回今天这次部署:

  • ff = 构建 → 上传 → 落盘 → 验证(仍是手动四步)
  • XX = “VitePress 静态站点”
  • cc = dist/ 经 scp 落到 /var/www/html,Nginx 直接服务

下次只改文案,这四步还是这四步——就是“xXx \in Xff 不变”。

当前缺口不是定义不成立,而是 ff 的每一步仍靠人敲:定义有了,自动化还没有。

没有版本记录

运维领域的常规做法是:部署前先备份当前版本,再覆盖新版本。比如把旧的 dist 重命名为 dist-20260713,然后再上传新的 dist。这样出了问题至少还能手动回退。

但手动备份有三个绕不开的断点:

第一,备份这一步本身会被跳过。 “这次改动很小,应该没问题”、“备份目录越来越多,占空间”、“上次备份了也没用过”——这些理由每次都成立,结果就是备份时有时无,一旦跳过就回不去

第二,即使做了备份,也只是“一份旧的目录”。 dist-20260713 对应的是哪次代码变更?改了什么?只有日期,没有上下文。事后想排查“当时为什么挂”,找不到入口。

第三,回退要重做一遍部署动作。 出问题后,要手动把备份目录重命名回去,再手动重启服务。回退本身就是另一轮容易出错的手动流程——一次部署出错的概率不高,但部署 + 回退都要靠人不出错,概率就高了

这三个断点叠在一起,手动备份有点像错题本:抄了但没看,看了又找不到,找到也用不上——形式上在做,实际上只是一套越来越繁琐的运维琐事。

更隐蔽的是版本不一致。本地构建的 dist 是基于当前代码生成的,但服务器上跑的 Nginx 配置、环境变量、依赖版本可能是上次部署时遗留的。你更新了 dist,却忘了同步 Nginx 配置;或者反过来,改了 Nginx 配置,但 dist 还是旧的。新旧版本混在一起,踩坑是常态——页面白屏、接口 404、样式错乱,排查半天才发现是前后端版本对不上。

手动备份解决不了 版本管理。 它只是把“覆盖”变成了“覆盖前先复制一份”,但“历史可追溯”、“变更可对比”、“回退可一键”这些能力,手动方式都给不了。这些不是备份的问题,是版本管理的问题——下一步我们会看到,Git 天然就有这套能力。

流程旁白

  • 谁发起:开发者(本人)决定“可以上线了”。
  • 谁执行:同一人完成构建、scp、落盘、公网验证。
  • 谁审批:本步无审批——个人学习场景下,发起即执行。
  • 职责边界:业务改动可以任意试;服务器上的发布动作与回退仍未成文,默认全压在执行者记忆里。后续篇会逐步把边界写清楚。

小结

生产环境的两个最低必要条件是 7×24 和公网 IP,云服务器是最短路径。通过 SSH 连接服务器 + scp 上传文件,就能完成一次最朴素的手动部署。

本篇同时埋下运维定义:xX, f(x)=c\forall x \in X,\ f(x)=c——规范集合内动作恒定。手动部署能跑通,但 ff 的每一步仍靠人。下一步引入 Git 和 GitHub,先解决版本与可追溯,再谈如何把 ff 跑稳。

思考

  1. 如果你的服务器宕机了,用户访问会发生什么?生产环境的“7×24”是由谁保证的?
  2. scp 和直接在服务器上改文件有什么区别?为什么我们选择在本地构建再上传?
  3. 你在 scp 时输错了目标路径,覆盖了服务器上的其他文件,怎么办?

延伸阅读:终端怎么选

终端 App 和 Shell 插件是两层叠加:App 负责长相,插件负责手感。选型优先 稳定、延迟低、习惯顺手——花哨功能其次。

终端 App

平台默认 / 推荐一句话特点
WindowsPowerShell(系统自带)原生上手;命令习惯偏 Windows
WindowsWindows Terminal + WSL Ubuntu学 Linux 运维的默认组合
macOSTerminal.app(系统自带)够用,配 zsh 已现代化
macOSiTerm2分屏、搜索、主题成熟
macOSWarpAI 终端:补全、解释、工作流内置

为什么还要装 Windows Terminal? WSL Ubuntu 自带的是系统 Console 里的基础窗口——能用但丑、无分屏、字体受限。Windows Terminal 是独立的“终端前端”,能挂 WSL、PowerShell、SSH 等多个 shell 到同一窗口,标签页 / 分屏 / 字体 / 配色统一管。这是两个不同的东西,WSL 自带的那个不是 Windows Terminal。

Mac 默认 Terminal 与云服务器命令习惯完全兼容(都是 Unix 一脉),换 Warp / iTerm2 是体验升级,不是必需。

Shell 插件(zsh,Mac / WSL Ubuntu / Linux 都适用)

插件作用
oh-my-zshzsh 配置框架,主题 + 插件管理
git大量 gst / gco / gp 别名 + 提示
zsh-syntax-highlighting合法命令变绿、非法变红——输错当下就知道
zsh-autosuggestions按历史灰字提示,→ 一键采纳
zsh-completions补全 kubectl / docker / aws 等额外命令

最小可用组合:oh-my-zsh + git + zsh-syntax-highlighting + zsh-autosuggestions。Windows 原生 PowerShell 走自己体系(PSReadLineposh-git),不通用。

参考

  1. SSH 官方文档
  2. scp 命令使用指南
  3. 腾讯云轻量应用服务器
  4. 阿里云轻量应用服务器