Project Laser 博客系统部署文档

基于 Astro Cactus 主题 + 1Panel + 子域名架构的完整部署指南


📋 目录

  1. 架构概述
  2. 环境准备
  3. 项目部署
  4. 站点配置
  5. 1Panel 网站配置
  6. Nginx 配置详解
  7. 部署脚本
  8. 日常维护
  9. 目录结构总览

架构概述

域名结构

域名 用途 对应内容
updn.pub 主站首页 /dist/index.html
blog.updn.pub 博客文章 /dist/posts/
about.updn.pub 关于页面 /dist/about/
note.updn.pub 动态/笔记 /dist/notes/

技术栈

  • 框架: Astro 5.x
  • 主题: Astro Cactus
  • 样式: Tailwind CSS 4.x
  • 面板: 1Panel
  • Web服务: OpenResty (Nginx)
  • 部署方式: 静态文件托管

设计理念

  • 单项目多子域名: 一个 Astro 项目,四个子域名各自指向不同内容
  • 性能优先: 纯静态文件,Nginx 直接托管
  • 统一维护: 换主题只需改一处,所有子站同步更新

环境准备

1. 清理旧环境(可选)

# 停止并删除不需要的 Docker 容器
docker stop <container_name>
docker rm <container_name>

# 清理无用镜像
docker image prune

2. 安装 Node.js 22.x

# 添加 NodeSource 仓库
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -

# 安装 Node.js
apt-get install -y nodejs

# 验证安装
node -v  # 应显示 v22.x.x
npm -v   # 应显示 10.x.x

3. 安装 pnpm

# 全局安装 pnpm
npm install -g pnpm

# 验证安装
pnpm -v  # 应显示 10.x.x

项目部署

1. 创建项目目录

mkdir -p /opt/updn-sites
cd /opt/updn-sites

2. 克隆 Astro Cactus 主题

git clone https://github.com/chrismwilliams/astro-theme-cactus.git cactus
cd cactus

3. 安装依赖

pnpm install

4. 修改站点配置

编辑 /opt/updn-sites/cactus/src/site.config.ts

import type { AstroExpressiveCodeOptions } from "astro-expressive-code";
import type { SiteConfig } from "@/types";

export const siteConfig: SiteConfig = {
    author: "AK",
    date: {
        locale: "zh-CN",
        options: {
            day: "numeric",
            month: "short",
            year: "numeric",
        },
    },
    description: "Game not over.",
    lang: "zh-CN",
    ogLocale: "zh_CN",
    title: "Project Laser",
    url: "https://updn.pub",
};

// 导航菜单 - 使用绝对 URL 指向子域名
export const menuLinks: { path: string; title: string }[] = [
    { path: "https://updn.pub", title: "首页" },
    { path: "https://about.updn.pub", title: "关于" },
    { path: "https://blog.updn.pub", title: "博客" },
    { path: "https://note.updn.pub", title: "动态" },
];

// 代码块配置(保持默认)
export const expressiveCodeOptions: AstroExpressiveCodeOptions = {
    styleOverrides: {
        borderRadius: "4px",
        codeFontFamily:
            'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
        codeFontSize: "0.875rem",
        codeLineHeight: "1.7142857rem",
        codePaddingInline: "1rem",
        frames: {
            frameBoxShadowCssValue: "none",
        },
        uiLineHeight: "inherit",
    },
    themeCssSelector(theme, { styleVariants }) {
        if (styleVariants.length >= 2) {
            const baseTheme = styleVariants[0]?.theme;
            const altTheme = styleVariants.find((v) => v.theme.type !== baseTheme?.type)?.theme;
            if (theme === baseTheme || theme === altTheme) return `[data-theme='${theme.type}']`;
        }
        return `[data-theme="${theme.name}"]`;
    },
    themes: ["dracula", "github-light"],
    useThemedScrollbars: false,
};

5. 首次构建

cd /opt/updn-sites/cactus
pnpm build

构建成功后,静态文件输出到 /opt/updn-sites/cactus/dist/ 目录。


站点配置

DNS 解析配置

在域名管理后台添加以下 A 记录(以 updn.pub 为例):

主机记录 记录类型 记录值
@ A 服务器IP
blog A 服务器IP
about A 服务器IP
note A 服务器IP

或使用泛解析:

主机记录 记录类型 记录值
@ A 服务器IP
* A 服务器IP

SSL 证书

建议申请泛域名证书 *.updn.pub,可通过 1Panel 的证书管理功能申请 Let’s Encrypt 免费证书。


1Panel 网站配置

1. 创建四个静态网站

在 1Panel 面板中:网站创建静态网站

依次创建:

主域名 代号
updn.pub updn.pub
blog.updn.pub blog.updn.pub
about.updn.pub about.updn.pub
note.updn.pub note.updn.pub

2. 配置 HTTPS

每个站点:配置HTTPS → 启用并选择证书

3. 部署静态文件

1Panel 创建的站点目录结构:

/opt/1panel/apps/openresty/openresty/www/sites/
├── updn.pub/
│   ├── index/      ← 静态文件放这里
│   ├── log/
│   └── ssl/
├── blog.updn.pub/
│   ├── index/
│   ├── log/
│   └── ssl/
├── about.updn.pub/
│   └── ...
└── note.updn.pub/
    └── ...

复制构建产物到各站点:

# 主站
cp -r /opt/updn-sites/cactus/dist/* /opt/1panel/apps/openresty/openresty/www/sites/updn.pub/index/

# 博客
cp -r /opt/updn-sites/cactus/dist/* /opt/1panel/apps/openresty/openresty/www/sites/blog.updn.pub/index/

# 关于
cp -r /opt/updn-sites/cactus/dist/* /opt/1panel/apps/openresty/openresty/www/sites/about.updn.pub/index/

# 动态
cp -r /opt/updn-sites/cactus/dist/* /opt/1panel/apps/openresty/openresty/www/sites/note.updn.pub/index/

Nginx 配置详解

主站 updn.pub

无需额外配置,使用 1Panel 默认生成的配置即可。

博客 blog.updn.pub

进入 1Panel → 网站 → blog.updn.pub → 配置文件,修改为:

server {
    listen 80;
    listen 443 ssl http2;
    server_name blog.updn.pub;
    index index.php index.html index.htm default.php default.htm default.html;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $server_name;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    access_log /www/sites/blog.updn.pub/log/access.log main;
    error_log /www/sites/blog.updn.pub/log/error.log;

    location ^~ /.well-known/acme-challenge {
        allow all;
        root /usr/share/nginx/html;
    }

    root /www/sites/blog.updn.pub/index;

    # 关键配置:访问根路径时显示 posts 内容
    location = / {
        try_files /posts/index.html =404;
    }

    error_page 404 /404.html;

    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }

    ssl_certificate /www/sites/blog.updn.pub/ssl/fullchain.pem;
    ssl_certificate_key /www/sites/blog.updn.pub/ssl/privkey.pem;
    ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    error_page 497 https://$host$request_uri;
    proxy_set_header X-Forwarded-Proto https;
    add_header Strict-Transport-Security "max-age=31536000";
}

关于 about.updn.pub

# 在 root 行后添加:
location = / {
    try_files /about/index.html =404;
}

动态 note.updn.pub

# 在 root 行后添加:
location = / {
    try_files /notes/index.html =404;
}

修改后点击「保存并重载」


部署脚本

创建一键部署脚本 /opt/updn-sites/deploy.sh

#!/bin/bash
# 🚀 Project Laser 一键部署脚本

set -e

echo "📦 开始构建..."
cd /opt/updn-sites/cactus
pnpm build

echo "🚀 部署到所有站点..."
cp -r dist/* /opt/1panel/apps/openresty/openresty/www/sites/updn.pub/index/
cp -r dist/* /opt/1panel/apps/openresty/openresty/www/sites/blog.updn.pub/index/
cp -r dist/* /opt/1panel/apps/openresty/openresty/www/sites/about.updn.pub/index/
cp -r dist/* /opt/1panel/apps/openresty/openresty/www/sites/note.updn.pub/index/

echo "✅ 部署完成!"
echo "   - https://updn.pub"
echo "   - https://blog.updn.pub"
echo "   - https://about.updn.pub"
echo "   - https://note.updn.pub"

添加执行权限:

chmod +x /opt/updn-sites/deploy.sh

使用方法:

/opt/updn-sites/deploy.sh

日常维护

添加博客文章

/opt/updn-sites/cactus/src/content/post/ 目录下创建 .md 文件:

---
title: "文章标题"
description: "文章描述"
publishDate: "2026-01-12"
tags: ["标签1", "标签2"]
---

正文内容...

添加动态/笔记

/opt/updn-sites/cactus/src/content/note/ 目录下创建 .md 文件:

---
title: "动态标题"
publishDate: "2026-01-12T12:00:00Z"
---

动态内容...

注意: Note 的 publishDate 需要完整的 ISO 8601 格式(带时间)。

部署更新

修改内容后执行:

/opt/updn-sites/deploy.sh

查看语法参考

保留的示例文件:

cat /opt/updn-sites/cactus/src/content/post/markdown-elements/index.md

目录结构总览

/opt/
├── updn-sites/
│   ├── cactus/                          # Astro 项目
│   │   ├── src/
│   │   │   ├── content/
│   │   │   │   ├── post/                # 博客文章
│   │   │   │   │   ├── hello-world.md
│   │   │   │   │   └── markdown-elements/
│   │   │   │   └── note/                # 动态/笔记
│   │   │   │       └── welcome.md
│   │   │   ├── pages/
│   │   │   │   └── about.astro          # 关于页面
│   │   │   └── site.config.ts           # 站点配置
│   │   ├── dist/                        # 构建输出
│   │   ├── astro.config.ts
│   │   └── package.json
│   └── deploy.sh                        # 部署脚本
│
├── 1panel/
│   └── apps/
│       └── openresty/
│           └── openresty/
│               └── www/
│                   └── sites/
│                       ├── updn.pub/
│                       │   ├── index/   # 静态文件
│                       │   ├── log/
│                       │   └── ssl/
│                       ├── blog.updn.pub/
│                       ├── about.updn.pub/
│                       └── note.updn.pub/
│
└── bots/                                # TG Bot(可选)
    ├── common.env
    └── astropub_bot/
        ├── .env
        └── astropub_bot.py

常见问题

Q: 访问显示 404

排查步骤

  1. 检查文件是否已复制到 index/ 目录
  2. 检查 Nginx 配置是否正确
  3. 检查是否点击了「保存并重载」

Q: 子域名无法访问

排查步骤

  1. 检查 DNS 解析是否生效:dig blog.updn.pub +short
  2. 检查 SSL 证书是否配置
  3. 检查 1Panel 站点状态是否「已启动」

Q: 构建报错 Invalid datetime

Note 的 publishDate 需要完整格式:

# ❌ 错误
publishDate: "2026-01-12"

# ✅ 正确
publishDate: "2026-01-12T12:00:00Z"

Q: 菜单跳转不正确

确保 site.config.ts 中的 menuLinks 使用完整的 URL:

{ path: "https://blog.updn.pub", title: "博客" }

版本信息

组件 版本
Ubuntu 22.04 LTS
Node.js 22.x
pnpm 10.x
Astro 5.x
Astro Cactus 6.x
1Panel 1.10.x
OpenResty 1.21.x

文档版本: 1.0 | 更新日期: 2026-01-12

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注