🖥️ 第二课:传统云服务器手工部署

预计阅读时间:15 分钟  |  难度:入门 ⭐⭐

📋 本课目标:亲手走完一套完整的手工部署流程——从一台"光杆"云服务器,到跑着 HTTPS 的线上 Web 应用。这堂课是部署入门的"核心肌肉训练",理解它能帮你更好地理解后面容器化和 CI/CD 的意义。

1 准备工作

你需要以下材料:

💡 没有云服务器?可以用 VirtualBox 安装 Ubuntu Server 虚拟机代替。流程一模一样。

2 第一步:服务器初始化

2.1 创建云服务器并 SSH 登录

在云厂商控制台创建实例时注意这几点:

拿到服务器公网 IP 后,在本地终端连接:

# 方法一:如果你在创建时绑定了密钥对
ssh -i ~/.ssh/my-key.pem ubuntu@你的服务器IP

# 方法二:默认的密钥路径(云厂商通常自动注入)
ssh ubuntu@你的服务器IP

# 首次登录成功后会看到类似这样的提示
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-xx-generic x86_64)
⚠️ 常见误区:忘记配置安全组就创建实例。创建后可以在控制台补配,但建议创建时一次性配好。
安全组参考:阿里云安全组文档 | 腾讯云安全组文档

2.2 系统更新与基础组件

SSH 连上后,第一件事是更新系统包并安装基础工具:

# 更新包索引和已安装的包
sudo apt update && sudo apt upgrade -y

# 安装常用工具
sudo apt install -y curl wget git vim ufw

# 检查时间是否同步(时区设为 Asia/Shanghai)
sudo timedatectl set-timezone Asia/Shanghai
timedatectl status

2.3 加固 SSH 安全

这是最重要的一步。服务器暴露在公网上后,几小时内就会有自动脚本扫描并尝试暴力破解 SSH。

如果你没有在创建时绑定密钥对,先手动设置:

# 在本地生成 SSH 密钥对(如果还没有)
# 本地终端执行,不是服务器上
ssh-keygen -t ed25519 -C "your-email@example.com"

# 将公钥复制到服务器
ssh-copy-id ubuntu@你的服务器IP
# 或者手动复制:cat ~/.ssh/id_ed25519.pub | ssh ubuntu@IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

然后修改 SSH 配置禁用密码登录:

# 编辑 SSH 配置文件
sudo vim /etc/ssh/sshd_config

# 确保以下三个设置正确(去掉前面的 # 注释)
Port 22 # 可改为其他端口减少扫描,但不必须
PermitRootLogin no # 禁止 root 直接登录
PasswordAuthentication no # 禁用密码登录
PubkeyAuthentication yes # 启用密钥登录

# 重启 SSH 服务使配置生效
sudo systemctl restart sshd
⚠️ 致命误区:修改 SSH 配置后没有测试新终端能否登录就关闭了当前会话——如果配置有误,你会把自己锁在门外。
正确做法:重启 SSH 后,先开一个新的终端窗口测试能否 SSH 连上,确认没问题再关当前的。

3 第二步:安装 Web 服务器(Nginx)

Nginx 是目前最主流的 Web 服务器和反向代理服务器。安装和基本配置:

3.1 安装 Nginx

sudo apt install -y nginx

# 检查 Nginx 版本和服务状态
nginx -v
sudo systemctl status nginx

# 如果防火墙开着,放行 HTTP 和 HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable # 如果提示确认,输入 y
sudo ufw status # 检查规则列表

此时在浏览器输入你的服务器 IP,应该能看到"Nginx 欢迎页"——如果看不到,检查安全组是否开放了 80 端口。

3.2 配置 Nginx 站点

Nginx 的站点配置文件在 /etc/nginx/sites-available/,启用则链接到 /etc/nginx/sites-enabled/

# 创建一个站点配置
sudo vim /etc/nginx/sites-available/myapp

一个典型的 Node.js 应用反向代理配置:

# /etc/nginx/sites-available/myapp

server {
    listen 80;
    server_name example.com www.example.com;

    root /var/www/myapp;
    index index.html;

    # 前端静态文件
    location / {
        try_files $uri $uri/ /index.html;
    }

    # API 反向代理到 Node.js
    location /api/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
# 创建静态资源目录
sudo mkdir -p /var/www/myapp
sudo chown -R ubuntu:ubuntu /var/www/myapp

# 启用站点(创建软链接)
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/

# 测试配置是否正确(重要!)
sudo nginx -t

# 重载 Nginx 使配置生效
sudo systemctl reload nginx
⚠️ 常见误区:修改配置后直接重启 Nginx 而不是先测试。nginx -t 可以帮你发现语法错误,避免服务中断。
参考:Nginx 官方 proxy 模块文档 | Nginx Beginner's Guide

4 第三步:部署应用

4.1 安装 Node.js 运行环境

# 使用 NodeSource 安装 Node.js 18 LTS(推荐)
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs

# 验证安装
node -v # 输出 v18.x.x
npm -v # 输出 9.x.x

4.2 从 Git 拉取应用并部署

# 克隆代码(假设你的项目在 GitHub)
cd /var/www/myapp
git clone https://github.com/your-username/your-project.git .

# 安装依赖
npm install

# 构建(如果前端项目需要)
npm run build

# 如果不需要构建,直接启动测试
node index.js &

4.3 使用 Systemd 守护进程

node app.js & 启动的应用在 SSH 断开后就死了。生产环境必须用进程管理器。Systemd 是 Linux 内置的方案,不需要额外安装:

# 创建 Systemd 服务文件
sudo vim /etc/systemd/system/myapp.service
# /etc/systemd/system/myapp.service
[Unit]
Description=My App
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node /var/www/myapp/index.js
Restart=always
RestartSec=3
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target
# 启动服务并设置开机自启
sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl enable myapp

# 常用管理命令
sudo systemctl status myapp # 查看状态
sudo systemctl restart myapp # 重启
sudo systemctl stop myapp # 停止
sudo journalctl -u myapp -f # 实时查看日志
⚠️ 常见误区:node app.js 直接启动就关终端了。必须用进程管理器!Systemd、PM2、Supervisor 都可以。
参考:Systemd 服务单元文档

5 第四步:配置 HTTPS(Let's Encrypt + Certbot)

这是生产环境绝对不能省略的一步。没有 HTTPS,所有流量明文传输,用户密码、API 密钥一览无余。

5.1 安装 Certbot 并获取证书

# 先确保你的域名已解析到服务器 IP
# 用 dig 检查确认后再继续
dig example.com +short

# 安装 Certbot 的 Nginx 插件
sudo apt install -y certbot python3-certbot-nginx

# 自动获取证书并配置 Nginx
sudo certbot --nginx -d example.com -d www.example.com

# 按照提示输入邮箱并同意协议即可
# Certbot 会自动修改 Nginx 配置,添加 SSL 相关指令

执行完成后,再访问你的网站就会自动跳转到 HTTPS。Certbot 还会配置定时任务自动续期证书(Let's Encrypt 证书有效期 90 天):

# 测试自动续期是否正常工作
sudo certbot renew --dry-run

5.2 验证 HTTPS 配置

使用以下工具验证你的 SSL 配置是否安全:

配置完成后,你的 Nginx SSL 配置大致长这样(Certbot 生成的):

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # ... 其它配置
}
⚠️ 常见误区:用 Certbot 后就不再管了。Let's Encrypt 证书只有 90 天有效期,务必确认自动续期配置正确。certbot renew --dry-run 应该在定时任务中定期执行。
参考:Certbot 官方文档 | Let's Encrypt 入门

6 完整部署检查清单

✅ 部署完成后逐项检查:

  1. ☐ 浏览器访问 https://你的域名 显示正常
  2. ☐ HTTP 自动跳转到 HTTPS
  3. ☐ 应用重启后能自动恢复(sudo reboot 测试)
  4. ☐ SSH 只能通过密钥登录,密码登录已禁用
  5. ☐ UFW 防火墙已启用,只开放 22/80/443 端口
  6. ☐ 云厂商安全组同样只开放上述端口
  7. ☐ 数据库端口(3306/5432)只绑定到 127.0.0.1 或内网 IP
  8. sudo certbot renew --dry-run 运行成功
  9. ☐ 日志轮转已配置(/etc/logrotate.d/

7 小测验

Q1: 修改 Nginx 配置后,第一步应该做什么?

Q2: 禁用 SSH 密码登录之前,必须确认什么?

Q3: 使用 certbot 配置 HTTPS 后,关于证书续期的正确理解是?

📖 推荐官方文档

📌 第三课预告

第三课:Docker 容器化部署实战

手工部署很好,但每次换服务器都要重来一遍?这一课我们用 Docker 把整个应用和环境一起打包,做到"一次构建,到处运行"。