Skip to content

VUE 项目打包为 Debian 包与 Nginx 自动配置

postrm 脚本的清理逻辑与 purge 陷阱示意图

在前一章中,我们将 Golang 后端项目打包成了标准的 Debian 包。本章将视角切换到前端,把一个 VUE 项目打包为 .deb 包,并实现与 Nginx 的自动化集成。

与后端打包不同,VUE 项目的打包关注点在于:

  • 静态资源部署:将 dist 目录部署到正确的位置
  • Nginx 配置管理:自动配置 Nginx 站点,实现前后端联调
  • 无状态清理removepurge 的区别相对简单

整体方案概述

VUE 打包 vs Golang 打包

对比维度Golang 后端VUE 前端
打包内容二进制文件 + systemd 服务静态资源(HTML/CSS/JS)+ Nginx 配置
核心依赖systemdnginx
postinst 职责启动服务重载 Nginx
prerm 是否需要✅ 需要(停止服务)❌ 通常不需要(无状态)
postrm 职责清理 systemd 残留清理部署目录 + 恢复 Nginx 配置

最终交付物

out/debian/cms-manager-1.7.0-amd64.deb

这个 .deb 包包含:

  • ✅ VUE 项目构建产物(dist/ 目录)
  • ✅ Nginx 站点配置文件
  • ✅ postinst / postrm 维护者脚本

项目目录结构

text
<cms-manager>/
├── docker/
│   └── debian/
│       ├── builder.Dockerfile          # Docker 构建文件
│       ├── dist/ -> ../../dist         # 构建产物软链接
│       ├── nginx/ -> ../../nginx/debian # Nginx 配置软链接
│       └── scripts/
│           ├── postinst                 # 安装后脚本
│           └── postrm                   # 卸载后脚本
├── dist/                               # VUE 构建产物
│   ├── index.html
│   └── assets/
├── nginx/
│   └── debian/
│       └── cms-manager.nginx.conf      # Nginx 站点配置
├── .dockerignore
└── Makefile

📌 命名约定:本文以 cms-manager 作为项目名称示例,你可以替换为实际的项目名称。

第一步:创建目录结构

bash
# 创建 Debian 打包构建目录
mkdir -p docker/debian

# 进入目录
cd docker/debian

第二步:配置 Nginx 站点

创建 Nginx 配置目录(软链接)

bash
# 在 docker/debian 目录下执行
ln -s ../../nginx/debian ./nginx

Nginx 站点配置文件

创建 nginx/debian/cms-manager.nginx.conf

nginx
server {
    listen       80;
    listen       [::]:80;
    server_name  cms.server;

    # VUE 项目静态资源
    location / {
        try_files $uri $uri/ @router;
        root   /var/www/html/cms-manager/dist;
        index  index.html;
    }

    # 代理后端 API 接口
    location /api/ {
        proxy_set_header Host $http_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;
        proxy_pass http://127.0.0.1:9400/v1/api/;
    }

    # 代理后端静态资源
    location /resource/ {
        proxy_set_header Host $http_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;
        proxy_pass http://127.0.0.1:9400/static/;
    }

    # 代理 WebSocket 接口
    location /websocket/ {
        proxy_set_header Host $http_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;
        proxy_set_header Connection Upgrade;
        proxy_set_header Upgrade websocket;
        proxy_pass http://127.0.0.1:9400/v1/websocket/;
    }

    # 解决 SPA 路由刷新 404 问题
    location @router {
        rewrite ^.*$ /index.html last;
    }
}

💡 关键点try_files $uri $uri/ @routerlocation @router 是 VUE/React SPA 应用的核心配置,解决了前端路由刷新时的 404 问题。

第三步:构建产物目录

创建 dist 软链接

bash
# 在 docker/debian 目录下执行
ln -s ../../dist ./dist

⚠️ 重要:在运行 Docker 构建之前,必须先执行 npm run build 生成 dist 目录。

第四步:维护者脚本

与后端服务不同,前端项目的维护者脚本不需要 prerm(因为静态资源不需要"停止"),只需要 postinstpostrm

postinst(安装后脚本)

bash
#!/bin/sh
set -e

log() {
    logger -t "cms-manager-postinst" "$@"
}

case "$1" in
    configure)
        log "Starting cms-manager configuration"

        # 1. 设置 dist 目录权限
        DIST_DIR="/var/www/html/cms-manager/dist"
        if [ -d "$DIST_DIR" ]; then
            log "Setting $DIST_DIR permissions to 755"
            chmod 755 "$DIST_DIR" || {
                log "Failed to set $DIST_DIR permissions"
                exit 1
            }
        else
            log "$DIST_DIR does not exist, skipping permission setup"
        fi

        # 2. 重载 Nginx(优雅生效)
        log "Attempting to reload nginx"
        if command -v systemctl >/dev/null 2>&1; then
            if systemctl is-active --quiet nginx; then
                systemctl reload nginx && log "nginx reloaded successfully" || {
                    log "Failed to reload nginx"
                    exit 1
                }
            else
                log "nginx is not running, skipping reload"
            fi
        elif command -v service >/dev/null 2>&1; then
            service nginx reload && log "nginx reloaded successfully" || {
                log "Failed to reload nginx"
                exit 1
            }
        else
            nginx -s reload && log "nginx reloaded successfully" || {
                log "Failed to reload nginx"
                exit 1
            }
        fi

        log "cms-manager configuration completed"
        ;;
    *)
        log "Unknown operation: $1"
        ;;
esac

exit 0

postrm(卸载后脚本)

bash
#!/bin/bash
set -e

case "$1" in
  remove|purge)
    echo "[cms-manager] Removing /etc/nginx/sites-enabled/default and restoring soft link..." >&2

    # 1. 删除当前 default 配置(由本包覆盖的)
    if [ -e /etc/nginx/sites-enabled/default ]; then
      rm -f /etc/nginx/sites-enabled/default
    fi

    # 2. 删除部署目录
    if [ -e /var/www/html/cms-manager ]; then
      rm -rf /var/www/html/cms-manager
    fi

    # 3. 恢复系统默认 Nginx 配置
    if [ -f /etc/nginx/sites-available/default ]; then
      ln -sf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
      echo "[cms-manager] Default soft link restored" >&2
    fi

    # 4. 重载 Nginx
    if command -v systemctl >/dev/null 2>&1; then
      systemctl reload nginx || true
    elif command -v service >/dev/null 2>&1; then
      service nginx reload || true
    else
      nginx -s reload || true
    fi
    ;;
  upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
    # No action needed
    ;;
  *)
    echo "postrm called with unknown argument \`$1'" >&2
    exit 1
    ;;
esac

exit 0

⚠️ 注意postrm 中我们操作的是 /etc/nginx/sites-enabled/default,这意味着每个服务器只能部署一个前端项目。如果需要在同一台服务器部署多个前端项目,应该使用独立的配置文件(如 sites-available/cms-manager.conf),而非覆盖 default

第五步:Docker 构建文件(builder.Dockerfile)

与 Golang 版本类似,VUE 打包也采用多阶段 Docker 构建,但只有打包阶段(因为 VUE 构建通常在宿主机或 CI 中完成)。

dockerfile
# ============================================================
# 全局构建参数
# ============================================================
ARG VERSION
ARG APPNAME=cms-manager

# ============================================================
# Stage: Debian 打包环境
# ============================================================
FROM ubuntu:20.04

ARG VERSION
ARG APPNAME

ENV VERSION=$VERSION
ENV APPNAME=$APPNAME
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai

# 配置国内镜像源
RUN sed -i \
    -e 's|http://.*archive.ubuntu.com|http://mirrors.aliyun.com|g' \
    -e 's|http://.*security.ubuntu.com|http://mirrors.aliyun.com|g' \
    /etc/apt/sources.list

# 配置时区
RUN apt-get update && \
    apt-get install -y --no-install-recommends tzdata && \
    ln -fs /usr/share/zoneinfo/$TZ /etc/localtime && \
    dpkg-reconfigure --frontend noninteractive tzdata

# 安装打包工具
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        dpkg-dev \
        ca-certificates \
        curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /workspace

# 复制 Nginx 配置文件(覆盖 default)
COPY docker/debian/nginx/${APPNAME}.nginx.conf /etc/nginx/sites-enabled/default
RUN chmod 644 /etc/nginx/sites-enabled/default

# 复制 VUE 构建产物
COPY docker/debian/dist /var/www/html/${APPNAME}/dist
RUN chmod -R 755 /var/www/html/${APPNAME}/dist

# 复制维护者脚本
COPY docker/debian/scripts/postinst docker/debian/scripts/postrm /tmp/
RUN chmod +x /tmp/postinst /tmp/postrm

# ============================================================
# 构建 Debian 包目录结构
# ============================================================
RUN mkdir -p package && \
    # Nginx 配置
    mkdir -p package/etc/nginx/sites-enabled/ && \
    cp /etc/nginx/sites-enabled/default package/etc/nginx/sites-enabled/ && \
    # VUE 静态资源
    mkdir -p package/var/www/html/${APPNAME}/ && \
    cp -r /var/www/html/${APPNAME}/dist package/var/www/html/${APPNAME}/ && \
    # 维护者脚本
    mkdir -p package/DEBIAN && \
    mv /tmp/postinst package/DEBIAN/ && \
    mv /tmp/postrm package/DEBIAN/

# 生成 control 文件
RUN echo "Package: ${APPNAME}" > package/DEBIAN/control && \
    echo "Version: ${VERSION}" >> package/DEBIAN/control && \
    echo "Architecture: amd64" >> package/DEBIAN/control && \
    echo "Maintainer: Applyfly <[email protected]>" >> package/DEBIAN/control && \
    echo "Description: A ${APPNAME} VUE3 Debian package" >> package/DEBIAN/control && \
    echo "Installed-Size: $(du -s package/var/ | cut -f1)" >> package/DEBIAN/control && \
    echo "Size: $(du -s package | cut -f1)" >> package/DEBIAN/control && \
    echo "Depends: nginx" >> package/DEBIAN/control && \
    echo "Pre-Depends: debconf" >> package/DEBIAN/control && \
    echo "Section: utils" >> package/DEBIAN/control && \
    echo "Priority: optional" >> package/DEBIAN/control

# 打包
RUN dpkg-deb --build package && \
    mv package.deb /${APPNAME}-${VERSION}-amd64.deb

# 输出
VOLUME /workspace
CMD ["sh", "-c", "cp /${APPNAME}-${VERSION}-amd64.deb /output/"]

Dockerfile 关键点解读

步骤操作说明
配置源替换为阿里云镜像加速 apt 包下载
时区设置TZ=Asia/Shanghai确保日志时间正确
安装工具dpkg-dev提供 dpkg-deb 打包命令
复制配置覆盖 default将 Nginx 配置放入 sites-enabled
复制静态资源dist//var/www/html/部署到标准 Web 目录
打包dpkg-deb --build生成 .deb 文件

第六步:.dockerignore

txt
.git
*.md
tmp/
node_modules
out

💡 注意node_modules 必须被排除,否则会大幅增加构建上下文大小。

第七步:Makefile 自动化构建

makefile
OUTPUT_DIR ?= ./out

.PHONY: builder-debian

builder-debian:
ifndef VERSION
	$(error VERSION is required. Usage: make builder-debian VERSION=1.7.0)
endif
	@echo "Building Debian package..."
	@mkdir -p $(OUTPUT_DIR)/debian
	DOCKER_BUILDKIT=1 docker build \
		-f docker/debian/builder.Dockerfile \
		-t cms-manager-builder:$(VERSION) \
		--build-arg VERSION=$(VERSION) \
		.
	@docker run --rm -v $(abspath $(OUTPUT_DIR)/debian):/output cms-manager-builder:$(VERSION)
	@echo "Package built: $(OUTPUT_DIR)/debian/cms-manager-$(VERSION)-amd64.deb"

执行构建

bash
# 先构建 VUE 项目
npm run build

# 再打包为 Debian 包
make builder-debian VERSION=1.7.0

⚠️ 注意:VUE 打包不需要 SSH agent(不像 Golang 需要拉取私有仓库),所以 Makefile 中省略了 ssh-agent 相关命令。

第八步:部署与验证

上传到服务器

bash
scp out/debian/cms-manager-1.7.0-amd64.deb username@host:/tmp/

安装软件包

bash
# 使用 apt(推荐)
sudo apt install /tmp/cms-manager-1.7.0-amd64.deb

# 或使用 dpkg
sudo dpkg -i /tmp/cms-manager-1.7.0-amd64.deb

验证部署

bash
# 检查文件是否部署成功
ls -la /var/www/html/cms-manager/dist/

# 检查 Nginx 配置
cat /etc/nginx/sites-enabled/default

# 重载 Nginx(postinst 已自动执行)
systemctl status nginx

# 访问测试
curl http://localhost/

查看 postinst 日志

bash
# postinst 使用 logger 记录日志
tail -f /var/log/syslog | grep cms-manager

卸载与清理

普通卸载(保留配置)

bash
sudo apt remove cms-manager

执行 remove 时,postrm 会:

  • 删除 /var/www/html/cms-manager/ 目录
  • 恢复 Nginx 默认配置
  • 重载 Nginx

彻底清除

bash
sudo apt purge cms-manager

purgeremove 在前端项目中的行为基本一致(因为没有配置文件需要额外清理)。

常见问题排查

问题1:安装后访问页面 404

bash
# 检查 dist 目录是否存在
ls -la /var/www/html/cms-manager/dist/

# 检查 Nginx 配置是否正确
nginx -t

# 查看 Nginx 错误日志
tail -f /var/log/nginx/error.log

问题2:Nginx 重载失败

bash
# 检查 Nginx 配置语法
nginx -t

# 查看详细错误
systemctl status nginx -l

问题3:前端路由刷新 404

检查 Nginx 配置中是否包含:

nginx
location / {
    try_files $uri $uri/ @router;
}

location @router {
    rewrite ^.*$ /index.html last;
}

问题4:多个前端项目冲突

如果需要在同一台服务器部署多个前端项目,不应覆盖 default 配置,而应使用独立的配置文件:

nginx
# /etc/nginx/sites-available/cms-manager.conf
server {
    listen 80;
    server_name cms.example.com;
    # ...
}

然后创建软链接:

bash
ln -s /etc/nginx/sites-available/cms-manager.conf /etc/nginx/sites-enabled/

VUE vs Golang 打包对比总结

对比维度Golang 后端VUE 前端
核心产物二进制文件静态资源(dist/)
服务管理systemd 服务Nginx 站点配置
postinst 职责启用服务 + 启动设置权限 + 重载 Nginx
prerm 是否需要✅ 需要(停止服务)❌ 不需要
postrm 职责清理 systemd 残留清理部署目录 + 恢复 Nginx
依赖包systemdnginx
构建工具go buildnpm run build

总结

通过本章,你将 VUE 前端项目打包为标准的 Debian 包,实现了:

目标实现方式
✅ 静态资源部署复制 dist//var/www/html/
✅ Nginx 自动配置覆盖 /etc/nginx/sites-enabled/default
✅ 安装后自动生效postinst 重载 Nginx
✅ 卸载时自动清理postrm 删除部署目录 + 恢复配置
✅ 标准化交付输出 .deb 包,支持 apt/dpkg 管理

专题总结

至此,Debian 打包专题的六篇文章已全部完成:

章节核心内容
第零章Debian 打包入门:control、rules、changelog
第一章postinst 脚本完整解读与最佳实践
第二章prerm 脚本的作用与正确使用姿势
第三章postrm 脚本的清理逻辑与 purge 陷阱
第四章Golang 项目打包为 Debian 包完整指南
第五章VUE 项目打包为 Debian 包与 Nginx 自动配置

从维护者脚本的理论基础,到后端服务和前端静态资源的实战打包,这套专题覆盖了 Debian 打包的完整知识体系。希望这套指南能帮助你在实际项目中构建出规范、稳定、易维护的 Debian 软件包。

最后更新2026/07/25 14:21
如果你觉得这篇文章有帮助,或者想聊聊技术、工作,欢迎通过下面方式联系我:
contact fishfinal