Linux: 综合实战——从零搭建 Web 开发服务器
这是本课程的最终项目。你将综合运用全部 25 课学到的技能——从一台裸机开始,搭建一台完整可用的 Web 开发服务器。
📋 前置知识:需要先掌握以下内容
1. 你将学到
- 服务器初始化全流程
- LEMP 栈搭建
- 部署 Node.js/Python 应用
- HTTPS 证书配置
- 监控与告警体系
2. 小明的"明天上线"挑战
(1) 痛点:新服务器,明天就要上线
小明的公司买了一台云服务器,老板说:"明天上线。"小明面对一台只有 IP 和 root 密码的裸机,之前学的所有知识都需要综合运用了。
(2) 从裸机到可用的 10 步流程
小明制定了计划:
1. SSH 登录 → 6. 部署 Node.js 应用
2. 用户创建 + SSH 加固 → 7. 配置 HTTPS 证书
3. 防火墙配置 → 8. 配置 PM2 进程管理
4. 安装 Nginx → 9. 自动备份
5. 配置反向代理 → 10. 健康检查 + 告警
(3) 收益:3 小时内交付
小明从下午 2 点开始,按计划逐步执行,下午 5 点完成了全部部署。老板测试后回复:"很好,可以上线。"
3. 知识点讲解
(1) 服务器初始化清单
□ SSH 登录(root 密码)
□ 更新系统(apt update && apt upgrade)
□ 创建普通用户(useradd -m -s /bin/bash)
□ 配置 sudo(usermod -aG sudo)
□ SSH 密钥认证
□ 禁用 root + 密码登录
□ 防火墙(ufw: 22/80/443)
□ fail2ban 防护
□ 自动安全更新
(2) LEMP 栈(Linux + Nginx + MySQL + PHP/Node.js/Python)
# Nginx
sudo apt install nginx
sudo systemctl enable --now nginx
# 如果使用 MySQL
sudo apt install mysql-server
sudo mysql_secure_installation
# 应用部署方式对比
| 方式 | 适合 | 优点 | 缺点 |
|---|---|---|---|
| systemd service | 任何语言 | 系统原生、成熟稳定 | 配置稍繁琐 |
| PM2 | Node.js | 零配置、自带监控 | 只支持 Node.js |
| Gunicorn/uWSGI | Python | 性能好、WSGI 标准 | 需要 Nginx 配合 |
| Docker Compose | 复杂应用 | 环境一致、易扩展 | 需要 Docker 基础 |
▶ 示例:部署 Node.js 应用到 Nginx
#!/bin/bash
# 部署 Node.js 应用到生产环境
# 1. 创建应用目录
sudo mkdir -p /opt/webapp
sudo chown -R alice:alice /opt/webapp
# 2. 拷贝应用文件(假设已开发好)
git clone https://github.com/example/webapp.git /opt/webapp
# 3. 安装依赖和构建
cd /opt/webapp
npm install
npm run build
# 4. 配置 PM2
npm install -g pm2
pm2 start server.js --name webapp -i max
pm2 save
pm2 startup
# 5. 配置 Nginx 反向代理
sudo tee /etc/nginx/sites-available/webapp << 'EOF'
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
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;
}
location /static/ {
alias /opt/webapp/public/;
expires 30d;
}
}
EOF
sudo ln -sf /etc/nginx/sites-available/webapp /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
输出:
TEXT 📖 仅展示npm WARN deprecated package@1.0.0 added 245 packages in 12s Building production bundle... [PM2] Process webapp started ┌────┬──────────┬─────────┬─────────┐ │ id │ name │ status │ cpu │ ├────┼──────────┼─────────┼─────────┤ │ 0 │ webapp │ online │ 0% │ └────┴──────────┴─────────┴─────────┘ nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
▶ 示例:HTTPS(Let's Encrypt + certbot)
sudo certbot renew --dry-run 测试续期流程是否正常。同时建议在日历上设置提醒,在证书到期前 30 天(约第 60 天)手动确认续期是否成功,避免因配置变动导致证书过期。
# 安装 certbot
sudo apt install certbot python3-certbot-nginx -y
# 获取证书(会自动修改 Nginx 配置)
sudo certbot --nginx -d example.com -d www.example.com
# 查看证书
sudo certbot certificates
# 验证自动续期
sudo certbot renew --dry-run
# 证书会自动续期(certbot 会添加 systemd timer)
sudo systemctl list-timers | grep certbot
输出:
TEXT 📖 仅展示Saving debug log to /var/log/letsencrypt/letsencrypt.log Requesting a certificate for example.com and www.example.com Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem Found the following certs: Certificate Name: example.com Expiry Date: 2026-10-05 10:23:45+00:00 (VALID: 89 days) Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/example.com/fullchain.pem certbot.timer certbot.service Sat 2026-07-08 00:00:00 UTC 13h left
▶ 示例:健康检查脚本
#!/bin/bash
# health-check.sh - 多服务健康检查
check_service() {
local name="$1"
local url="$2"
local expect="${3:-200}"
local status=$(curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null)
if [ "$status" = "$expect" ]; then
echo "[✓] $name: $status (正常)"
return 0
else
echo "[✗] $name: $status (异常)"
return 1
fi
}
echo "=== 系统健康检查 ==="
echo "时间: $(date)"
echo ""
# 系统资源
echo "CPU: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}')%"
echo "内存: $(free -h | grep Mem | awk '{print $3 "/" $2}')"
echo "磁盘: $(df -h / | tail -1 | awk '{print $3 "/" $2 " (" $5 ")"}')"
echo ""
# Web 服务
check_service "Nginx" "http://localhost/nginx_status" 200
check_service "WebApp" "http://localhost:3000/health" 200
check_service "HTTPS" "https://example.com/" 200
echo ""
echo "=== 检查完成 ==="
输出:
TEXT 📖 仅展示=== 系统健康检查 === 时间: Tue Jul 7 10:30:00 UTC 2026 CPU: 2.3% 内存: 1.2Gi/3.9Gi 磁盘: 12G/50G (24%) [✓] Nginx: 200 (正常) [✓] WebApp: 200 (正常) [✓] HTTPS: 200 (正常) === 检查完成 ===
▶ 示例:完整的部署脚本
curl -fsSL URL | bash - 模式将远程脚本直接在本地执行,存在供应链攻击风险——如果源站被入侵或 DNS 被劫持,你可能执行的是恶意代码。生产环境中,更安全的做法是先下载脚本审查内容,确认安全后再执行:curl -fsSL URL -o setup.sh && less setup.sh && bash setup.sh。
#!/bin/bash
# setup-server.sh - 从零搭建 Web 开发服务器
# 用法: sudo ./setup-server.sh example.com
set -euo pipefail
DOMAIN="${1:-example.com}"
APP_DIR="/opt/webapp"
APP_PORT=3000
ADMIN_USER="admin"
echo "========================================"
echo " 从零搭建 Web 开发服务器"
echo " 域名: $DOMAIN"
echo "========================================"
# 1. 系统更新
echo ""
echo ">>> 1/10 更新系统..."
apt update && apt upgrade -y
# 2. 创建普通用户
echo ""
echo ">>> 2/10 创建管理用户..."
if ! id "$ADMIN_USER" &>/dev/null; then
useradd -m -s /bin/bash "$ADMIN_USER"
usermod -aG sudo "$ADMIN_USER"
echo "请为 $ADMIN_USER 设置密码:"
passwd "$ADMIN_USER"
# 注意:请手动将你的 SSH 公钥添加到 /home/$ADMIN_USER/.ssh/authorized_keys
mkdir -p /home/$ADMIN_USER/.ssh
cp /root/.ssh/authorized_keys /home/$ADMIN_USER/.ssh/ 2>/dev/null || true
chown -R $ADMIN_USER:$ADMIN_USER /home/$ADMIN_USER/.ssh
chmod 700 /home/$ADMIN_USER/.ssh
chmod 600 /home/$ADMIN_USER/.ssh/authorized_keys
fi
# 3. SSH 加固
echo ""
echo ">>> 3/10 SSH 加固..."
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config
systemctl restart sshd
# 4. 防火墙
echo ""
echo ">>> 4/10 配置防火墙..."
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
# 5. fail2ban
echo ""
echo ">>> 5/10 安装 fail2ban..."
apt install -y fail2ban
cat > /etc/fail2ban/jail.d/sshd.conf << EOF
[sshd]
enabled = true
maxretry = 3
bantime = 86400
findtime = 600
EOF
systemctl enable --now fail2ban
# 6. 安装 Nginx
echo ""
echo ">>> 6/10 安装 Nginx..."
apt install -y nginx
systemctl enable --now nginx
# 7. 安装 Node.js
echo ""
echo ">>> 7/10 安装 Node.js..."
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
npm install -g pm2
# 8. 配置 Nginx 反向代理
echo ""
echo ">>> 8/10 配置 Nginx..."
cat > /etc/nginx/sites-available/$DOMAIN << EOF
server {
listen 80;
server_name $DOMAIN www.$DOMAIN;
location / {
proxy_pass http://127.0.0.1:$APP_PORT;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host \$host;
proxy_cache_bypass \$http_upgrade;
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;
}
}
EOF
ln -sf /etc/nginx/sites-available/$DOMAIN /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx
# 9. HTTPS 证书
echo ""
echo ">>> 9/10 配置 HTTPS..."
apt install -y certbot python3-certbot-nginx
certbot --nginx --non-interactive --agree-tos \
--email admin@$DOMAIN \
-d $DOMAIN -d www.$DOMAIN \
|| echo "⚠️ certbot 失败,请手动运行: sudo certbot --nginx -d $DOMAIN"
# 10. 健康检查脚本
echo ""
echo ">>> 10/10 配置健康检查..."
mkdir -p /opt/scripts
cat > /opt/scripts/health-check.sh << 'EOF'
#!/bin/bash
WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK"
for svc in nginx sshd fail2ban; do
if ! systemctl is-active --quiet "$svc"; then
echo "[$(date)] ❌ $svc 异常" >> /var/log/health.log
fi
done
DISK=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
[ "$DISK" -gt 85 ] && echo "[$(date)] ⚠️ 磁盘 ${DISK}%" >> /var/log/health.log
EOF
chmod +x /opt/scripts/health-check.sh
# 加入 cron
(crontab -l 2>/dev/null; echo "*/10 * * * * /opt/scripts/health-check.sh > /dev/null 2>&1") | crontab -
echo ""
echo "========================================"
echo "✅ 服务器搭建完成!"
echo ""
echo "部署信息:"
echo " 管理用户: $ADMIN_USER"
echo " Nginx: http://$DOMAIN"
echo " HTTPS: https://$DOMAIN(如果 certbot 成功)"
echo " Node.js: $(node --version)"
echo " PM2: $(pm2 --version)"
echo ""
echo "后续步骤:"
echo " 1. 将应用代码部署到 $APP_DIR"
echo " 2. 启动应用: pm2 start $APP_DIR/server.js --name webapp"
echo " 3. 从 $ADMIN_USER 用户登录(禁止 root 直接登录)"
echo "========================================"
输出:
TEXT 📖 仅展示======================================== 从零搭建 Web 开发服务器 域名: example.com ======================================== >>> 1/10 更新系统... ... ======================================== ✅ 服务器搭建完成! 管理用户: admin Nginx: http://example.com Node.js: v20.11.0 ========================================
▶ 综合示例:完整的部署验收
#!/bin/bash
# verify-deploy.sh - 部署完成后验证
echo "========================================"
echo " 部署验证"
echo " 时间: $(date)"
echo "========================================"
echo ""
errors=0
check() {
local desc="$1"
shift
if "$@" &>/dev/null; then
echo " [✓] $desc"
else
echo " [✗] $desc"
errors=$((errors + 1))
fi
}
echo "1. 系统服务"
echo "-----------"
check "Nginx 运行" systemctl is-active nginx
check "SSH 运行" systemctl is-active sshd
check "fail2ban 运行" systemctl is-active fail2ban
echo ""
echo "2. 网络"
echo "--------"
check "端口 80 监听" ss -tlnp | grep -q ":80 "
check "端口 443 监听" ss -tlnp | grep -q ":443 "
check "ufw 已启用" ufw status | grep -q active
echo ""
echo "3. HTTP 服务"
echo "-------------"
check "本地 Nginx 响应" curl -s -o /dev/null -w "%{http_code}" http://localhost | grep -q 200
check "应用进程运行" pm2 list 2>/dev/null | grep -q "online" || pgrep -f "node server" > /dev/null
echo ""
echo "4. 安全"
echo "--------"
check "root SSH 已禁用" grep "^PermitRootLogin" /etc/ssh/sshd_config | grep -q "no"
check "密码登录已禁用" grep "^PasswordAuthentication" /etc/ssh/sshd_config | grep -q "no"
echo ""
echo "5. 资源"
echo "--------"
echo " CPU: $(top -bn1 | grep 'Cpu(s)' | awk '{print $2"%"}' )"
echo " 内存: $(free -h | grep Mem | awk '{print $3"/"$2}')"
echo " 磁盘: $(df -h / | tail -1 | awk '{print $3"/"$2"("$5")"}')"
echo ""
echo "========================================"
if [ $errors -eq 0 ]; then
echo "✅ 全部验证通过!"
else
echo "❌ $errors 项检查失败,请排查"
fi
echo "========================================"
输出:
TEXT 📖 仅展示======================================== 部署验证 时间: Tue Jul 7 10:45:00 UTC 2026 ======================================== 1. 系统服务 ----------- [✓] Nginx 运行 [✓] SSH 运行 [✓] fail2ban 运行 2. 网络 -------- [✓] 端口 80 监听 [✓] 端口 443 监听 [✓] ufw 已启用 3. HTTP 服务 ------------- [✓] 本地 Nginx 响应 [✓] 应用进程运行 4. 安全 -------- [✓] root SSH 已禁用 [✓] 密码登录已禁用 5. 资源 -------- CPU: 2.3% 内存: 1.2Gi/3.9Gi 磁盘: 12G/50G(24%) ======================================== ✅ 全部验证通过! ========================================
❓ 常见问题
Q: 服务器部署第一件事应该做什么? A: \1
Q: Nginx 反向代理和应用的关系是什么? A: Nginx 是"大门",应用是"里面的人"。用户访问 Nginx 的 80/443 端口 → Nginx 决定把请求转发到哪个后端应用。Nginx 处理静态文件、SSL 终结、负载均衡,应用只专注业务逻辑。
Q: HTTPS 证书需要定期续期吗? A: Let's Encrypt 证书有效期 90 天。certbot 会自动添加 systemd timer 定期续期。验证:
systemctl list-timers | grep certbot。手动续期:sudo certbot renew。
Q: 服务器监控看哪些指标? A: 核心指标:CPU 使用率、内存用量、磁盘空间(>80% 告警)、磁盘 IO、网络流量、服务是否运行、SSL 证书是否过期。
Q: 部署完成后怎么验证安全? A: 运行安全扫描工具:1)
sudo ufw status检查端口。2)ss -tlnp检查服务监听地址。3)grep "Failed password" /var/log/auth.log | wc -l检查攻击量。4)用 https://www.ssllabs.com/ssltest/ 测试 SSL 配置。
📖 小节
- 服务器初始化的 10 步流程:系统更新 → 用户 → SSH 加固 → 防火墙 → fail2ban → Nginx → 应用 → HTTPS → 备份 → 监控
- Nginx 反向代理:
proxy_pass http://127.0.0.1:3000 - certbot:
--nginx -d example.com自动 HTTPS - PM2:
pm2 start app.js -i max多进程管理 - 健康检查:
curl -o /dev/null -w "%{http_code}" http://localhost/health
📝 作业
- 基础题(难度⭐):用虚拟机或云服务器,从零执行
setup-server.sh完整脚本,部署一个简单的 Node.js 或 Python Web 应用到服务器,通过 Nginx 反向代理访问 - 进阶题(难度⭐⭐):配置 Let's Encrypt HTTPS 证书(可用
--dry-run测试),并编写和部署健康检查脚本,配置告警通知(邮件或 webhook) - 挑战题(难度⭐⭐⭐⭐⭐):配置完整的备份策略(cron + rsync 远程备份)并验证备份可恢复,然后编写自动化部署验证脚本,检查所有服务状态、安全配置和性能指标,输出格式化验收报告