Skip to content

AstrNest 安装与配置指南

面向运维/开发的落地说明:列出必须填的环境变量、文件路径、初始化脚本与部署要点。建议按顺序完成,最后再启动 Docker Compose 或本地进程。

1. 快速清单

项目必填内容修改文件/位置
数据库连接主机、端口、库名、账号、密码.env / backend/src/main/resources/application.yml / docker-compose.yml (mysqlbackend 服务环境变量) / backend/db/init.sql
管理员账号用户名、初始密码、昵称、邮箱.env + backend/db/init.sql (INSERT INTO users ...)
上传路径本地磁盘目录、对外访问前缀.env (ASTRNEST_STORAGE_ROOT/ASTRNEST_STORAGE_PUBLIC),必要时在 Nginx 中反代 /upload/** 到后端
站点域名前端站点地址、图片直链域名、API 域名.env (PUBLIC_SITE_URL/PUBLIC_ASSET_URL/BACKEND_API_PUBLIC_URL),后台"系统配置"里的 asset_domain
后端地址前端访问的 API 地址frontend/.env 或编译期传入 VITE_API_BASE_URL
图片访问地址未配置 asset_domain 时默认 https://{当前域名}/upload/{yyyy}/{MM}/文件Nginx/网关 /upload/** 反向代理到 backend:8080,或在 .env 中给 ASTRNEST_ASSET_DOMAIN/VITE_PUBLIC_ASSET_BASE 明确域名
邮件服务SMTP Host/Port/账号/授权码/发件人启动后在后台「设置 > 邮件服务」里填写,或在 backend/db/init.sqlchenxi_mail_config 段改占位值
AI 内容审核腾讯云 SecretId/SecretKey、Region、Bucket.env 中的 ASTRNEST_AI_TENCENT_* 或在后台「系统配置 > AI 智能审核」配置
视频缩略图FFmpeg 路径、截图偏移、质量.env 中的 ASTRNEST_VIDEO_THUMBNAIL_* 或后台配置

1.1 文件路径速查

文件路径需确认/修改的参数适用场景
.env(根目录)MYSQL_*ASTRNEST_DB_*ASTRNEST_STORAGE_*ASTRNEST_ADMIN_*PUBLIC_SITE_URLPUBLIC_ASSET_URLBACKEND_API_PUBLIC_URLASTRNEST_ASSET_DOMAINVITE_API_BASE_URLVITE_PUBLIC_ASSET_BASEVITE_SITE_NAMESMTP_*ASTRNEST_AI_TENCENT_*ASTRNEST_VIDEO_THUMBNAIL_*Docker Compose 及本地 shell 的统一入口,docker compose --env-file .env up -d 会读取这些值
docker-compose.ymlservices.mysql.environment.*(数据库名/账号/密码)、services.backend.environment.*(后端连接串、管理员、存储路径)、services.frontend.environment.*(前端访问后端/图片地址)如需为某环境写死参数,可直接在对应服务的 environment 块覆盖 .env
backend/src/main/resources/application.ymlspring.datasource.*astrnest.storage.*astrnest.admin.*裸机运行或 IDE 调试时的兜底配置,所有键均可被环境变量覆盖
backend/db/init.sqlCREATE DATABASE/USERGRANTINSERT INTO usersINSERT INTO chenxi_mail_configUPDATE system_config初始化数据库结构、管理员信息与 SMTP 占位;部署前请替换库名/账号、管理员邮箱与密码哈希
backend/db/init_windows.sql同上,但移除了 DELIMITER 等 Windows/Navicat 不兼容语法Windows 环境下推荐使用
frontend/.env.development / .env.production / .env.exampleVITE_API_BASE_URLVITE_PUBLIC_ASSET_BASEVITE_SITE_NAME控制前端向哪台后端发起请求以及生成图片直链的域名/路径
frontend/src/services/http.jsaxios.create({ baseURL: ... })若不依赖 .env,可在此处直接写死后端请求地址

📦 建议做法:先复制 .env.example.env,确认每一项都贴合目标环境,再依次调整 application.ymlinit.sqlfrontend/.env.production

2. 环境变量样例 (.env)

bash
cp .env.example .env
# 编辑 .env 后生效在 docker compose / shell 中

.env 同时被 docker-compose.ymlbackend/src/main/resources/application.yml 以及前端构建脚本读取,务必在启动前替换掉所有占位值:

  • 先写对数据库主机、端口、库名、账号、密码,保证 MYSQL_*ASTRNEST_DB_* 指向同一个实例;
  • 再设置管理员用户名/密码/邮箱,以便初始化脚本创建正确的超级管理员;
  • 根据部署拓扑写入站点域名、图片访问域名、后端公开地址,并在 Nginx 或负载均衡层做好 /upload/** 映射;
  • 如需发邮件,提前准备好 SMTP 主机、端口与授权码;
  • 如需 AI 审核,准备好腾讯云 COS CI 的 SecretId/SecretKey;
  • 最后把前端访问后端的 VITE_API_BASE_URL、图片直链 VITE_PUBLIC_ASSET_BASE 调整为公网域名。

重点变量:

  • MYSQL_ROOT_PASSWORD / MYSQL_DATABASE / MYSQL_USER / MYSQL_PASSWORDmysql 容器初始化所需的库名与账号密码,也方便 DBA 直接照抄到现有 MySQL 主机。
  • ASTRNEST_DB_URL / ASTRNEST_DB_USERNAME / ASTRNEST_DB_PASSWORD:后端 JDBC 连接串、账号、密码;Docker 模式下可直接写 jdbc:mysql://mysql:3306/${MYSQL_DATABASE}?...,裸机部署时改为真实主机。
  • ASTRNEST_STORAGE_ROOT:容器内/宿主机映射的真实目录,示例 ./storage/upload:/storage/upload。系统会自动在目录下创建 YYYY/MM 子目录。
  • ASTRNEST_STORAGE_PUBLIC:对外路径前缀,默认为 /upload,因此直链为 https://站点/upload/{yyyy}/{MM}/{文件名}
  • ASTRNEST_STORAGE_STRATEGY:存储策略,可选 LOCALALIYUN_OSSTENCENT_COSS3_COMPATIBLEUPYUN_USSONEDRIVE 等。
  • ASTRNEST_ASSET_DOMAIN + PUBLIC_SITE_URL / PUBLIC_ASSET_URL / BACKEND_API_PUBLIC_URL:若要把资产托管到 CDN,请在这里写实际域名,并在 Nginx/Caddy 中增加 /upload/** 反代;PUBLIC_SITE_URL 用于在邮件等场景拼接站点主页。
  • ASTRNEST_MULTIPART_MAX_FILE_SIZE / ASTRNEST_MULTIPART_MAX_REQUEST_SIZE:必须保持 20MB 以内,否则会与数据库 CHECK (size <= 20971520) 冲突。
  • ASTRNEST_ADMIN_*:首次启动自动落库的管理员信息;密码落库前会以 bcrypt 存储。
  • SMTP_*:与 init.sql 中的 chenxi_mail_config 占位值保持一致,方便后续导入。
  • ASTRNEST_AI_TENCENT_*:腾讯云 AI 审核配置,包括 SecretId、SecretKey、Region、Bucket、检测场景、置信度阈值等。
  • ASTRNEST_VIDEO_THUMBNAIL_*:视频缩略图配置,包括 enabled、ffmpeg-path、capture-offset、quality 等。
  • VITE_API_BASE_URL / VITE_PUBLIC_ASSET_BASE / VITE_SITE_NAME:前端构建期注入,用于 axios、复制直链按钮与浏览器标签标题。

3. 后端配置 (application.yml)

  • 位置:backend/src/main/resources/application.yml
  • 默认已经引用上述环境变量;若需写死,可以改为纯字符串:
yaml
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/astrnest?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: astrnest
    password: astrnestPass!
  servlet:
    multipart:
      max-file-size: 20MB
      max-request-size: 20MB

astrnest:
  storage:
    strategy: LOCAL
    local:
      root: /storage/upload
      public-base-url: /upload
  admin:
    username: admin
    password: chenxi123
    display-name: 超级管理员
    email: admin@example.com

重要public-base-url 只能使用相对路径(以 /upload 开头),否则 Spring 的静态资源映射不起作用;若要使用 CDN 域名,请在后台"系统配置"中填写 asset_domain

4. 数据库初始化

4.1 Linux / macOS(推荐执行方式)

bash
mysql -u root -p < backend/db/init.sql

4.2 Windows(Navicat / GUI 导入兼容说明)

在 Windows 上使用 Navicat "导入 SQL 文件"时,可能会因为以下原因失败:

  • 权限不足(CREATE USER / GRANT / FLUSH PRIVILEGES 需要高权限账号);
  • DELIMITER / 多语句 / PREPARE ... EXECUTE ... 动态 SQL 在某些导入模式下会被拆分导致语法错误。

为此项目已提供 Windows/Navicat 友好版脚本backend/db/init_windows.sql

  • 该脚本用于"新库初始化"更稳定(移除了大量动态迁移段、触发器改为不依赖 DELIMITER 的写法)。
  • 注意init_windows.sql 默认不做 CREATE USER/GRANT,避免普通连接账号导入时报错;因此需要你额外手工授权(见 4.3)。

推荐导入流程(Navicat)

  1. root(或 DBA)在 Navicat 先手动创建数据库 astrnest(字符集 utf8mb4)。
  2. 选中库 astrnest 后导入并执行 backend/db/init_windows.sql
  3. 如导入时报"没有 CREATE VIEW / CREATE TRIGGER 权限",请用更高权限账号执行导入,或临时注释掉 CREATE VIEW / CREATE TRIGGER 段。

4.3 常见启动报错:1044 / 42000(账号能登录但无库权限)

如果你在命令行能 mysql -u astrnest -p 登录,但后端启动报错:

  • SQL Error: 1044, SQLState: 42000
  • Access denied for user 'astrnest'@'localhost' to database 'astrnest'

说明:账号/密码正确,但 astrnest@host 没有 astrnest.* 的权限。用 root(或 DBA)执行下面 SQL:

sql
CREATE DATABASE IF NOT EXISTS astrnest CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

CREATE USER IF NOT EXISTS 'astrnest'@'localhost' IDENTIFIED BY 'chenxi123';
CREATE USER IF NOT EXISTS 'astrnest'@'%' IDENTIFIED BY 'chenxi123';

GRANT ALL PRIVILEGES ON astrnest.* TO 'astrnest'@'localhost';
GRANT ALL PRIVILEGES ON astrnest.* TO 'astrnest'@'%';

FLUSH PRIVILEGES;

说明:MySQL 用户是按 用户@Host 匹配的,常见坑是只授权了 astrnest@'%',但实际连接被识别成 astrnest@'localhost'(或反过来)。

验证方式:

sql
SHOW GRANTS FOR 'astrnest'@'localhost';
SHOW GRANTS FOR 'astrnest'@'%';
USE astrnest;
SHOW TABLES;

5. 前端环境文件

  • 位置:frontend/.env.development / frontend/.env.production(可自建),亦可在构建命令行注入。
  • 推荐内容:
bash
VITE_API_BASE_URL=https://api.astrnest.com
VITE_PUBLIC_ASSET_BASE=https://cdn.astrnest.com/upload
VITE_SITE_NAME=AstrNest

6. 上传与静态资源

  1. 目录结构LocalStorageHandler 会把每个文件写入 ${ASTRNEST_STORAGE_ROOT}/{yyyy}/{MM}/文件名
  2. 默认访问:若 asset_domain 为空,后台会返回 /upload/{yyyy}/{MM}/文件名,浏览器会基于当前域名访问。
  3. 反向代理:需要在 Nginx/网关层补上一段:
nginx
location /upload/ {
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080/upload/;
}
  1. CDN/自定义域:在后台 -> 系统配置填入 https://cdn.xxx.com,或在数据库 system_config.asset_domain 中直接写;API 会把图片 URL 改为 https://cdn.xxx.com/upload/{...}

7. AI 内容审核配置

7.1 腾讯云 COS CI 配置

.env 中配置:

bash
ASTRNEST_AI_TENCENT_SECRET_ID=your-secret-id
ASTRNEST_AI_TENCENT_SECRET_KEY=your-secret-key
ASTRNEST_AI_TENCENT_REGION=ap-beijing
ASTRNEST_AI_TENCENT_BUCKET=your-bucket-1250000000
ASTRNEST_AI_TENCENT_DETECT_SCENES=web,camera,album,news
ASTRNEST_AI_BLOCK_CONFIDENCE=90
ASTRNEST_AI_REVIEW_CONFIDENCE=60
ASTRNEST_AI_LABEL_MIN_CONFIDENCE=60

或在后台「系统配置 > AI 智能审核」中填写:

  • SecretId/SecretKey:腾讯云 API 密钥
  • Region:存储桶所在地域,如 ap-beijing
  • Bucket:存储桶名称,如 your-bucket-1250000000
  • 检测场景:web,camera,album,news
  • 拦截阈值:建议 90(置信度 >=90 直接拦截)
  • 复核阈值:建议 60(置信度 60-90 需人工复核)
  • 标签阈值:建议 60(置信度 >=60 的标签会保存)

官方参考:https://cloud.tencent.com/document/product/460/37318

8. 视频缩略图(FFmpeg)

8.1 安装 FFmpeg

  • Debian/Ubuntu:sudo apt-get install -y ffmpeg
  • CentOS/RHEL:sudo yum install -y ffmpeg(或 dnf
  • macOS:brew install ffmpeg
  • Windows:下载官方 build,将 bin 加入 PATH;或者使用 chocolatey / winget 安装(choco install ffmpegwinget install ffmpeg

8.2 配置

.env 中配置:

bash
ASTRNEST_VIDEO_THUMBNAIL_ENABLED=true
ASTRNEST_VIDEO_THUMBNAIL_FFMPEG_PATH=ffmpeg
ASTRNEST_VIDEO_THUMBNAIL_CAPTURE_OFFSET=5
ASTRNEST_VIDEO_THUMBNAIL_QUALITY=80
ASTRNEST_VIDEO_THUMBNAIL_TIMEOUT_SECONDS=30
ASTRNEST_VIDEO_THUMBNAIL_COVER_DIRECTORY=/storage/upload/covers
ASTRNEST_VIDEO_THUMBNAIL_MAX_LOAD_AVERAGE=4.0

8.3 常见日志:找不到 ffmpeg(不影响服务启动)

如果日志出现类似:

  • Cannot run program "ffmpeg": error=2, No such file or directory

说明后端在生成视频封面/缩略图时找不到 ffmpeg,一般不影响后端启动,但会导致视频封面生成失败。

  • 解决方案 A(推荐):安装 ffmpeg 并确保命令行可直接执行 ffmpeg
  • 解决方案 B:如果你暂时不需要视频封面,设置环境变量 ASTRNEST_VIDEO_THUMBNAIL_ENABLED=false

9. 邮件设置

  • 启动后:后台「设置 > 邮件服务」填 SMTP 主机/端口/账号/授权码/发件人。
  • 若希望脚本写入真实值:编辑 backend/db/init.sqlINSERT INTO chenxi_mail_config 段。

10. Docker Compose 部署

  1. cp .env.example .env 并填好所有占位。
  2. 执行:
bash
docker compose --env-file .env up -d
  1. 默认行为:启动 MySQL、导入 init.sql、启动 backend(8080) 与 frontend(80),挂载 ./storage/upload
  2. 如需 JVM/调试参数:在 .env 设置 JAVA_OPTS,Compose 会透传。

11. 传统部署

  • 后端:cd backend && ./mvnw clean package && java -jar target/backend-0.0.1-SNAPSHOT.jar
  • 前端:cd frontend && npm run build,将 dist/ 交给 Nginx/CDN。

11.1 Windows 启动命令

Windows 下建议使用 Maven Wrapper:

  • 编译/运行:cd backend && .\mvnw.cmd spring-boot:run
  • 打包:cd backend && .\mvnw.cmd clean package

说明:如果直接使用 mvn 报 "不是内部或外部命令",说明你本机没有安装 Maven 或未加入 PATH;使用项目自带的 mvnw.cmd 可以避免这个问题。

11.2 Windows 控制台中文日志乱码(UTF-8 编码)

如果你看到日志里中文变成类似 鏈娴... 的乱码,通常不是业务问题,而是 终端编码与 Java 输出编码不一致

推荐做法(Windows Terminal / PowerShell)

  1. 先把当前会话切到 UTF-8:
powershell
chcp 65001
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
  1. 再启动后端:
powershell
cd backend
.\mvnw.cmd spring-boot:run

IDE 控制台(IntelliJ IDEA)

  • Settings > Editor > File Encodings 设置为 UTF-8;
  • 运行配置(Run/Debug Configuration)里确保控制台编码为 UTF-8(不同版本位置略有差异)。

示例:这条乱码日志的原文一般是 未检测到激活的存储策略,沿用配置文件默认值: LOCAL

12. 收尾检查

  • .envapplication.ymlfrontend/.env* 均已替换真实地址/账号。
  • backend/db/init.sql(或 Windows 下的 backend/db/init_windows.sql)中管理员邮箱/SMTP/资产域名已调整。
  • 访问健康检查:http://{server}:8080/actuator/health 应为 UP/upload/{yyyy}/{MM}/... 能返回 200/404(不应 502)。

12.1 常见"能跑但日志报错"的说明(排障速查)

12.1.1 No converter for ApiErrorResponse with preset Content-Type 'video/mp4'

如果你在日志里看到类似:

  • HttpMessageNotWritableException: No converter for [class ...ApiErrorResponse] with preset Content-Type 'video/mp4'

含义:你请求的是视频/资源(响应本来应该是 video/mp4 或二进制流),但中途抛异常后框架想返回 JSON 错误体;由于响应头 Content-Type 已经是 video/mp4,就会出现"无法用 mp4 的 Content-Type 写 JSON"这种报错。

处理建议(按优先级):

  • 先看触发该报错的请求路径:通常是访问视频直链或资源接口(例如 /upload/**/api/uploads/** 等)。
  • 确认资源文件确实存在、存储路径配置正确(本地存储是否挂载到正确目录)。
  • 若你是在浏览器/播放器里访问,尽量避免手动强行设置 Accept: video/mp4 后再去请求会返回 JSON 的接口。

这类报错通常不影响服务启动,但会导致那一次请求返回失败。

13. Nginx 反向代理与静态加速示例

13.1 基本反代(前端 + 后端 + 上传)

nginx
# 前端 SPA(dist 部署)
server {
    listen 80;
    server_name example.com;
    root /var/www/astrnest/dist;

    location / {
        try_files $uri $uri/ /index.html;
    }

    # 上传直链透传后端(若使用本地存储)
    location /upload/ {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:8080/upload/;
        expires 7d;
        add_header Cache-Control "public";
    }

    # 后端 API
    location /api/ {
        proxy_set_header Host $host;
        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:8080/api/;
    }

    # OpenAPI / Swagger
    location /swagger-ui/ {
        proxy_pass http://127.0.0.1:8080/swagger-ui/;
    }
}

13.2 HTTPS/HTTP2 与常用优化

nginx
server {
    listen 443 ssl http2;
    server_name example.com;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_session_cache shared:SSL:10m;
    ssl_protocols TLSv1.2 TLSv1.3;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header Referrer-Policy strict-origin-when-cross-origin;
    add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";

    gzip on;
    gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml;
    gzip_vary on;

    # 其余 location 同 13.1,可复用
}

14. CDN / 直链域名配置

  • 在后台"系统配置"填写 asset_domain(如 https://cdn.example.com),前端复制直链会自动拼成 asset_domain + /upload/{yyyy}/{MM}/...
  • 如使用前端环境变量控制:设置 VITE_PUBLIC_ASSET_BASE=https://cdn.example.com/upload
  • Nginx 只需把 /upload/ 回源到后端或对象存储源站;如走 OSS/COS,请在 CDN 源站指向对应桶域名或自建反代。

15. 对象存储配置示例

15.1 阿里云 OSS(application.yml 片段)

yaml
astrnest:
  storage:
    strategy: ALIYUN_OSS
    oss:
      enabled: true
      endpoint: https://oss-cn-shanghai.aliyuncs.com
      bucket: astrnest-prod
      access-key: ${ALIYUN_ACCESS_KEY}
      secret-key: ${ALIYUN_SECRET_KEY}
      cdn-host: https://cdn.example.com   # 可选

CDN 生效后,前端建议同时设置 VITE_PUBLIC_ASSET_BASE=https://cdn.example.com/upload

15.2 腾讯云 COS

yaml
astrnest:
  storage:
    strategy: TENCENT_COS
    cos:
      enabled: true
      endpoint: https://cos.ap-shanghai.myqcloud.com
      region: ap-shanghai
      bucket: astrnest-1250000000
      access-key: ${TENCENT_SECRET_ID}
      secret-key: ${TENCENT_SECRET_KEY}
      path-style: true
      accelerate: false
      multipart-threshold-mb: 5120
      part-size-mb: 25
      cdn-host: https://cos-cdn.example.com   # 可选

15.3 通用 S3 兼容

yaml
astrnest:
  storage:
    strategy: S3_COMPATIBLE
    s3:
      enabled: true
      endpoint: https://s3.us-east-1.amazonaws.com
      region: us-east-1
      bucket: astrnest-archive
      access-key: ${AWS_ACCESS_KEY}
      secret-key: ${AWS_SECRET_KEY}
      path-style: true

若供应商要求 virtual-host 模式,关闭 path-style 并确保域名已做 CNAME。

15.4 又拍云 USS

yaml
astrnest:
  storage:
    strategy: UPYUN_USS
    upyun:
      enabled: true
      bucket: astrnest
      operator: ${UPYUN_OPERATOR}
      password: ${UPYUN_OPERATOR_PASSWORD}
      endpoint: https://v0.api.upyun.com
      cdn-host: https://static.example.com

15.5 OneDrive / SharePoint

yaml
astrnest:
  storage:
    strategy: ONEDRIVE
    onedrive:
      enabled: true
      drive-type: business   # personal / business
      tenant-id: ${AZURE_TENANT_ID}
      client-id: ${AZURE_CLIENT_ID}
      client-secret: ${AZURE_CLIENT_SECRET}
      drive-id: ${ONEDRIVE_DRIVE_ID}
      site-id: ${SHAREPOINT_SITE_ID}
      refresh-token: ${ONEDRIVE_REFRESH_TOKEN}  # 个人盘常用
      base-url: https://graph.microsoft.com/v1.0

drive-id 优先级高于 site-id;未配置 refresh token 时企业盘可用 client credentials 获取 Token。

16. 前端/后端分域部署示例

  • 前端域名https://console.example.com(托管 dist)
  • API 域名https://api.example.com(反代后端)
  • 直链/CDN 域名https://cdn.example.com/upload
  • 前端环境:
env
VITE_API_BASE_URL=https://api.example.com
VITE_PUBLIC_ASSET_BASE=https://cdn.example.com/upload
VITE_SITE_NAME=AstrNest
  • 后端系统配置:asset_domain=https://cdn.example.com
  • Nginx:前端站点只需静态托管;API 与 /upload 由 api 域名回源后端或对象存储。

完成以上补充后,可直接按本文示例配置并上线。