Ubuntu Nginx站点部署实录:从配置详解到自动化脚本

前言
最近为了把跑在内网 8090 端口的博客服务发布到公网,我折腾了一番 Nginx。
目标很简单:通过域名 blog.twopair.cn 访问,由 HTTP 自动跳转 HTTPS,且以后要能轻松管理多个站点。
这里的记录涵盖了从环境安装、配置文件原理详解,到最终封装自动化脚本的全过程。

一、 起步:环境与基础

在 Ubuntu 20.04/22.04 上,第一步永远是把环境铺好。

# 1. 更新源并安装 Nginx 和解压工具
sudo apt update
sudo apt install nginx unzip -y

# 2. 确认防火墙放行 HTTP/HTTPS,否则外网白搭
sudo ufw allow 'Nginx Full'


二、 核心逻辑:Nginx 的“仓库”与“柜台”

Ubuntu 下 Nginx 的目录结构设计非常巧妙,理解这个逻辑是手动配置的基础:

  • /etc/nginx/sites-available/ (仓库)
    存放配置文件的原稿。写在这里的文件 Nginx 是不读的,相当于“草稿箱”。
  • /etc/nginx/sites-enabled/ (柜台)
    存放指向仓库文件的软链接(快捷方式)。Nginx 启动时只加载这里的内容。

我的管理逻辑

  • 上线:用 ln -s 把仓库里的文件链接到柜台。
  • 下线:用 rm 删掉柜台里的链接(原稿保留,随时可恢复)。

三、 深度解析:Nginx 配置文件写了什么?

在使用脚本“一键生成”之前,必须搞懂配置文件里每一行的含义。以我的 blog.twopair.cn 为例,一个标准的HTTPS + 反向代理配置如下:

1. 证书存放规范

为了不乱,我统一将证书存放在 /etc/nginx/cert/<域名>/ 目录下:

  • .pem / .crt:公钥/证书链。
  • .key:私钥(注意权限保护)。

2. 配置文件拆解

通常包含两个 server 块。

第一部分:HTTP 强制跳转 HTTPS

拦截所有 80 端口请求,将其扔给 443 端口。

server {
    listen 80;
    server_name blog.twopair.cn; # 匹配我的域名

    # 301 永久重定向到 HTTPS,保留原本的请求路径
    return 301 https://$host$request_uri;
}

第二部分:HTTPS 核心配置

server {
    # --- 基础监听 ---
    listen 443 ssl;
    server_name blog.twopair.cn;

    # --- SSL 证书配置 ---
    # 这里指向我解压后的证书路径
    ssl_certificate     /etc/nginx/cert/blog.twopair.cn/fullchain.pem;
    ssl_certificate_key /etc/nginx/cert/blog.twopair.cn/privkey.key;

    # --- 关键:解决上传报错 ---
    # 默认 Nginx 限制上传 1MB,博客传大图会报 413 Too Large
    # 手动改成了 100M
    client_max_body_size 100M; 

    # --- 反向代理设置 (连接后端) ---
    location / {
        proxy_pass http://127.0.0.1:8090; # 转发给本地 8090 端口

        # --- 请求头传递 (Header) ---
        # 如果不加下面这几行,后端服务拿到的 IP 全是 127.0.0.1
        # 这会导致日志分析和 IP 限制功能失效
        proxy_set_header Host $host;                      # 传递原始域名
        proxy_set_header X-Real-IP $remote_addr;          # 传递用户真实IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        proxy_set_header X-Forwarded-Proto $scheme;       # 告诉后端原本是 https
    }
}


四、 终极方案:自动化管理脚本

为了以后不再手动复制粘贴上述配置,我让AI写了一个脚本 vhost_manager.sh
它会自动部署站点:解压证书 -> 生成上述配置 -> 建立软链接 -> 重载 Nginx

1. 脚本代码

保存为 vhost_manager.sh 并赋予执行权限 chmod +x vhost_manager.sh

#!/bin/bash
# Nginx 站点管理工具

case "$1" in
    deploy)
        # 部署模式:需要 域名、端口、证书zip包
        DOMAIN=$2; PORT=$3; ZIP_PATH=$4
        CERT_DIR="/etc/nginx/cert/$DOMAIN"
        CONF_PATH="/etc/nginx/sites-available/$DOMAIN"
        
        echo ">>> [1/4] 准备证书目录: $CERT_DIR"
        sudo mkdir -p "$CERT_DIR"
        sudo unzip -j -o "$ZIP_PATH" -d "$CERT_DIR" > /dev/null
        
        # 智能识别证书文件 (无论文件名叫什么)
        PEM=$(sudo find "$CERT_DIR" -name "*.pem" -o -name "*.crt" | head -n 1)
        KEY=$(sudo find "$CERT_DIR" -name "*.key" | head -n 1)
        
        if [ -z "$PEM" ] || [ -z "$KEY" ]; then
            echo "错误:ZIP 包中未找到 .pem/.crt 或 .key 文件!"
            exit 1
        fi
        
        echo ">>> [2/4] 生成 Nginx 配置..."
        sudo bash -c "cat > $CONF_PATH <<EOF
server {
    listen 80;
    server_name $DOMAIN;
    return 301 https://\$host\$request_uri;
}
server {
    listen 443 ssl;
    server_name $DOMAIN;
    
    ssl_certificate $PEM;
    ssl_certificate_key $KEY;
    
    ssl_session_timeout 5m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    
    # 允许最大上传 100M
    client_max_body_size 100M;
    
    location / {
        proxy_pass http://127.0.0.1:$PORT;
        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;
    }
}
EOF"
        echo ">>> [3/4] 激活站点..."
        sudo ln -sf "$CONF_PATH" "/etc/nginx/sites-enabled/"
        
        echo ">>> [4/4] 重载服务..."
        sudo nginx -t && sudo systemctl reload nginx
        echo ">>> 成功!https://$DOMAIN 现在指向本地端口 $PORT"
        ;;

    enable)
        # 上线:恢复软链接
        sudo ln -sf "/etc/nginx/sites-available/$2" "/etc/nginx/sites-enabled/"
        sudo nginx -t && sudo systemctl reload nginx
        echo ">>> 站点 $2 已重新上线"
        ;;

    disable)
        # 下线:断开软链接,保留配置
        sudo rm -f "/etc/nginx/sites-enabled/$2"
        sudo systemctl reload nginx
        echo ">>> 站点 $2 已下线 (配置保留)"
        ;;

    remove)
        # 销毁:彻底清理所有相关文件
        sudo rm -f "/etc/nginx/sites-enabled/$2"
        sudo rm -f "/etc/nginx/sites-available/$2"
        sudo rm -rf "/etc/nginx/cert/$2"
        sudo systemctl reload nginx
        echo ">>> 站点 $2 已彻底移除"
        ;;
    
    status)
        echo "--- [已上线站点] ---"
        ls /etc/nginx/sites-enabled/
        ;;
    *)
        echo "用法: $0 {deploy|enable|disable|remove|status} ..."
        ;;
esac


五、 实战演示:我的博客部署过程

假设我已经把申请好的 SSL 证书压缩包 blog_cert.zip 上传到了服务器,且博客程序已经在 8090 端口运行。

1. 一键部署

运行脚本,填入我的域名和端口:

./vhost_manager.sh deploy blog.twopair.cn 8090 ./blog_cert.zip

执行后,脚本会自动解压证书、写入上面的那套配置、并重载Nginx部署站点。

2. 日常维护

  • 临时维护博客
    ./vhost_manager.sh disable blog.twopair.cn
    (此时用户访问会挂掉,但配置和证书都在)
  • 维护完毕上线
    ./vhost_manager.sh enable blog.twopair.cn
  • 以后不再用这个站了
    ./vhost_manager.sh remove blog.twopair.cn
    (彻底删除干净)

六、 避坑指南

在折腾过程中遇到过几个坑,特此记录:

  1. 413 Request Entity Too Large
  • 现象:博客上传图片稍微大点就报错。
  • 原因:Nginx 默认限制 1MB。
  • 解决:脚本里我已经加了 client_max_body_size 100M;