Files
g82tt 68be41e7a2 初始提交:浏览器首页 MyHomePage 全栈项目
# 项目概述
个人浏览器首页导航应用,支持书签分类管理、搜索引擎快捷搜索、
必应每日壁纸轮播、前后端分离部署,适配 1Panel 服务器(Docker 模式)。

# 技术栈
- 前端:Vue 3 + TypeScript + Vite + Pinia + Capacitor(Android 打包)
- 后端:.NET 8 + SqlSugar(多数据库) + SQLite/MySQL + Swashbuckle
- 部署:1Panel 应用商店自定义应用(Docker Compose 模式)

# 项目结构
- backend/    .NET 8 API 后端(8 个 Controller + 15 个 Service)
- frontend/   Vue 3 前端(19 个组件 + 9 个 API 模块 + 5 个 Store)
- docker/     Docker 部署文件(后端镜像 + Nginx 反代)
- docs/       部署手册(1Panel 实战版)
- scripts/    E2E 测试脚本

# 已实现功能
- 书签管理:增删改查 + 树形分类 + 拖拽排序 + 主色自适应
- 搜索引擎:8 个内置引擎 + 自定义引擎 + favicon 自动抓取
- 必应壁纸:每日轮播 + 多分辨率自动选择 + 1.6MP 质量优先
- 全局设置:主题/行为/数据/工具 4 分类 + 跨设备同步
- 文件上传:图标/书签/通用(容器持久化 + 跨域 URL 拼接)
- 同步:基于变更日志的设备间数据同步
- 跨域部署:前后端分离 + runtime config.json 无需重新编译

# 进度记录
- 已完成 P0~P52 共 53 个开发节点(详细见 说明文档.md)
- 当前版本:v1.0 部署就绪

# 部署文档
- README.md:项目说明 + 快速开始
- 说明文档.md:完整开发进度(中文)
- docs/DEPLOY.md:1Panel 部署手册(Docker 模式)
2026-07-05 05:09:56 +08:00

12 KiB
Raw Permalink Blame History

MyHomePage 1Panel 部署手册

适用环境:服务器已装 1Panelv2.x+ 1Panel 内置 MySQL(已部署并启动) 全程不碰 Docker / nginx.conf / systemd —— 全部交给 1Panel 面板管理


一、部署架构

                        [公网/局域网]
                              │
              ┌───────────────┴───────────────┐
              │                               │
        域名 A(前端)                  域名 B(后端,可选)
              │                               │
              ▼                               ▼
     1Panel 静态网站                    1Panel .NET 运行时
     Nginx 反代)                        Kestrel
              │                               │
              │   /api/* 反代到 127.0.0.1:8080 │
              └──────────────┐  ┌──────────────┘
                             ▼  ▼
                       1Panel MySQL
                       (本机 127.0.0.1:3306

一句话总结:MySQL 已部署 + 前端走静态网站 + 后端走 .NET 运行环境 = 三步上线。


二、前置准备

2.1 服务器侧

条件 说明
1Panel v2.x 已装好(主人的情况)
MySQL 实例 1Panel 应用商店装的 MySQL,已 running
域名 可选:解析 A 记录到服务器 IP;没域名也能用 IP+端口
1Panel 防火墙 默认放行 80/443;后端用 8080 需手动放行

2.2 本地编译

2.2.1 编译后端

cd d:\Code\MyHomePage\backend
dotnet publish -c Release -o ..\publish\backend

产物:publish\backend\(约 80MB,含 .dll / appsettings.json / wwwroot/ 等)。

2.2.2 编译前端

cd d:\Code\MyHomePage\frontend
npm install        # 首次或依赖变化时
npm run build

产物:frontend\dist\(约 400KB,含 index.html / assets/)。

2.3 上传产物到服务器

方式 1:1Panel 文件管理(推荐,Web 拖拽)

  • 1Panel → 文件 → 进入 /opt/1panel/apps/
  • 新建两个文件夹:myhomepage-backend / myhomepage-frontend
  • 分别拖入编译产物

方式 2:scp 上传(打 zip 后传一次)

cd d:\Code\MyHomePage
Compress-Archive -Path publish\backend,frontend\dist -DestinationPath myhomepage.zip
scp myhomepage.zip root@your-server:/opt/1panel/apps/

服务器侧:

cd /opt/1panel/apps/
unzip myhomepage.zip
mv publish/backend myhomepage-backend
mv frontend/dist myhomepage-frontend

三、第一步:1Panel 准备 MySQL

3.1 创建数据库

  • 1Panel → 数据库 → MySQL → 你的实例 → 创建数据库
  • 数据库名:myhomepage
  • 字符集:utf8mb4
  • 排序规则:utf8mb4_unicode_ci

3.2 创建用户并授权

  • 1Panel → 数据库 → MySQL → 你的实例 → 创建用户
  • 用户名:myhomepage_user
  • 密码:自定义或自动生成(复制保存!)
  • 主机:localhost(只允许本机连接,禁止公网)
  • 授权:库 myhomepage,权限 ALL

3.3 记录连接信息

字段
host 127.0.0.1
port 3306
database myhomepage
user myhomepage_user
password (你刚设的)

四、第二步:部署后端

4.1 上传后端文件

publish\backend\所有文件传到 /opt/1panel/apps/myhomepage-backend/

最终目录结构(参考):

/opt/1panel/apps/myhomepage-backend/
├── MyHomePage.Api.dll
├── appsettings.json
├── appsettings.Production.json
├── web.config                # 1Panel 运行环境会自动生成
├── Uploads/                  # 后面建
├── wwwroot/                  # 后端静态资源(如果有)
└── ...

4.2 创建 .NET 网站

  • 1Panel → 网站创建网站
  • 类型:选择「运行环境」标签 → 选 .NET(如果应用商店没装 .NET Runtime,先去应用商店搜 .NET 安装)
  • 主域名:填后端域名(如 api.example.com),或留空用 IP:8080
  • 端口:8080
  • 代号:myhomepage-api
  • 网站目录:/opt/1panel/apps/myhomepage-backend
  • 启动命令:dotnet MyHomePage.Api.dll --urls http://0.0.0.0:8080

4.3 配置环境变量

在创建好的网站详情页 → 「环境变量」或「配置文件」tab,添加:

变量名 说明
ASPNETCORE_ENVIRONMENT Production 启用生产配置
Database__Provider MySql 切换到 MySQL
Database__ConnectionString server=127.0.0.1;port=3306;database=myhomepage;user=myhomepage_user;password=你的密码;charset=utf8mb4; 连接串
Upload__Path /opt/1panel/apps/myhomepage-backend/Uploads 上传文件落盘路径
Upload__BaseUrl https://你的前端域名/uploads 前端拼接 URL 前缀
Cors__Origins__0 https://你的前端域名 允许跨域的白名单(必须)

双下划线 __ 是 ASP.NET Core 配置嵌套的语法,等价于 JSON 里的 { "Cors": { "Origins": [ ... ] } }。 如果主人在前端用 VITE_API_BASE=https://api.example.com 直接走独立域名,跨域问题更彻底。

4.4 创建上传目录

  • 1Panel → 文件 → 在 /opt/1panel/apps/myhomepage-backend/ 下新建 Uploads/
  • 权限 755(默认即可)

4.5 启动后端

  • 网站详情页 → 启动 按钮
  • 等 5-10 秒 → 日志 tab 应该看到:
    Now listening on: http://0.0.0.0:8080
    Application started.
    

4.6 本地验证

# 服务器侧
curl http://127.0.0.1:8080/health
# 期望:OK

看到 200 = 后端已就绪


五、第三步:部署前端

5.1 上传前端文件

frontend\dist\所有文件传到 /opt/1panel/apps/myhomepage-frontend/

5.2 创建静态网站

  • 1Panel → 网站创建网站
  • 类型:选择「静态网站」标签
  • 主域名:填前端域名(如 home.example.com
  • 端口:80HTTP)或 443HTTPS
  • 代号:myhomepage-web
  • 网站目录:/opt/1panel/apps/myhomepage-frontend

5.3 申请 SSL(强烈推荐)

  • 网站详情页 → SSL申请 → Let's Encrypt
  • 1Panel 自动续期

5.4 配置反向代理(关键!)

网站详情页 → 反向代理 或直接编辑 配置文件Nginx),加这段:

# /api/* 转发到后端
location /api/ {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    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;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 60s;
}

# /uploads/* 转发到后端(用户上传图片)
location /uploads/ {
    proxy_pass http://127.0.0.1:8080;
}

如果前端 .env.production 配了 VITE_API_BASE=https://api.example.com跳过本节(前后端走不同域名更干净)。

5.5 验证前端

浏览器打开 https://你的前端域名/ → 看到首页 = 成功


六、第四步:联调验证

6.1 必查清单

  • 浏览器打开前端 → 首页正常渲染
  • DevTools → Network → 5 个 API 请求(settings / categories / bookmarks / search-engines / wallpaper全部 200
  • 新建一个分类 + 一个链接 → 刷新页面看是否持久化
  • 切换主题 / 主色调 → 刷新看是否持久化
  • 上传一张图片 → 看是否显示
  • 360 壁纸功能(在设置里启用)→ 切换间隔生效

6.2 Android APP 后端地址

主人后续会打包 Android。.env.production 或 Capacitor 配置里填:

# 同域名反代
https://你的前端域名/api

# 或独立后端域名
https://api.example.com

七、日常运维

7.1 看日志

  • 1Panel → 网站 → 你的网站 → 日志 tab
  • 实时滚动 / 可下载 .log 文件
  • 排错先看这里

7.2 重启服务

  • 1Panel → 网站 → 你的网站 → 重启 按钮
  • 5-10 秒生效

7.3 备份数据库

  • 1Panel → 数据库 → MySQL → 你的实例 → 备份
  • 1Panel 默认每天自动备份到本地目录
  • 也可「立即备份」→ 下载到本地双保险

7.4 更新后端

# 本地
cd d:\Code\MyHomePage\backend
dotnet publish -c Release -o ..\publish\backend
  • 1Panel → 文件 → /opt/1panel/apps/myhomepage-backend/ → 覆盖上传所有文件
  • 1Panel → 网站 → myhomepage-api → 重启

7.5 更新前端

# 本地
cd d:\Code\MyHomePage\frontend
npm run build
  • 1Panel → 文件 → /opt/1panel/apps/myhomepage-frontend/ → 覆盖上传所有文件
  • 静态网站无需重启,浏览器 Ctrl+F5 强刷即可

7.6 紧急回滚

想回滚 操作
后端代码 1Panel → 文件 → 把后端目录回退到上一版 → 重启
前端代码 1Panel → 文件 → 把前端目录回退到上一版 → 强刷
数据库 1Panel → 数据库 → 选昨天的备份 → 恢复(会覆盖当前数据

八、常见问题

Q1:前端打开是白屏

  • 1Panel → 网站 → 静态网站 → 日志查 404
  • 大概率是 index.html 没传,或 assets/ 目录没传全

Q2API 全部 404

  • 检查第五步 5.4 的反向代理是否生效
  • 服务器本地 curl http://127.0.0.1:8080/health 验证后端活着

Q3CORS 跨域报错

  • 检查第四步 4.3 的 Cors__Origins__0 是否设了前端完整域名(含 https://
  • 重启后端

Q4:数据库连接失败

  • 1Panel → 数据库 → MySQL → 看实例 running
  • 服务器本地 mysql -u myhomepage_user -p 验证能登
  • 检查连接串的 password= 是不是带特殊字符(需要 URL encode)

Q5:上传图片 500

  • 检查 /opt/1panel/apps/myhomepage-backend/Uploads/ 权限 755
  • 服务器 df -h 看磁盘

Q6:移动端 / Android APP 访问不到

  • 1Panel 防火墙放行 8080(如果不走反代)
  • 或在 Android 里直接填 https://你的前端域名/api(走反代最稳)

Q7360 壁纸不显示

  • 后端环境变量里 Upload__BaseUrlCors__Origins__0 都填前端完整域名
  • 服务器能访问外网(curl https://wallpaper.apc.360.cn 验证)

附录 A:环境变量速查表

变量 必填 示例值 说明
ASPNETCORE_ENVIRONMENT Production 启用生产配置
Database__Provider MySql 固定值
Database__ConnectionString server=127.0.0.1;port=3306;database=myhomepage;user=myhomepage_user;password=xxx;charset=utf8mb4; MySQL 连接串
Upload__Path /opt/1panel/apps/myhomepage-backend/Uploads 上传落盘绝对路径
Upload__BaseUrl https://home.example.com/uploads 前端拼接 URL 前缀
Cors__Origins__0 https://home.example.com 跨域白名单(多域名时加 Cors__Origins__1

附录 B:目录结构速查

/opt/1panel/apps/
├── myhomepage-backend/
│   ├── MyHomePage.Api.dll
│   ├── appsettings.json
│   ├── appsettings.Production.json
│   ├── Uploads/                  # 用户上传
│   └── ...
└── myhomepage-frontend/
    ├── index.html
    ├── assets/
    │   ├── index-xxxxxx.js
    │   └── index-xxxxxx.css
    └── ...