1. 网站信息设置之图标设置

在当前后端项目中,网站图标(Favicon)的处理方式为“动态生成外部 URL 链接”。

以下是具体的处理逻辑:

1.1. 图标 URL 的生成逻辑 (utils/faviconUtils.js)

后端不再将图标下载到本地服务器,而是根据网站域名生成指向第三方图标服务的 URL:

  • 优先使用 DuckDuckGo 服务:生成的格式为 https://icons.duckduckgo.com/ip3/{domain}.ico
  • Google 服务兜底:如果 URL 解析出现异常,会退而使用 Google 的图标 API:https://www.google.com/s2/favicons?sz=64&domain_url={websiteUrl}
  • 支持自定义:如果用户手动提供了图标 URL,后端会优先采用用户提供的地址。

1.2. 业务层的处理流程 (services/websiteService.js)

  • 创建网站时:系统会自动调用 fetchFavicon 方法,根据用户输入的网站地址生成对应的图标 URL,并将其存入数据库。
  • 更新网站时
    • 如果用户修改了网站的 url(导致域名变化),或者当前记录中缺失图标,系统会重新生成图标 URL。
    • 如果域名未发生变化,则继续沿用现有的图标 URL,避免不必要的更新。
  • 删除网站时:由于不再存储本地物理文件,删除操作仅需清理数据库记录,无需处理文件删除逻辑(相关方法已变更为 no-op)。

1.3. 数据存储

图标信息直接以字符串形式存储在 SQLite 数据库 websites 表的 favicon_url 字段中。

1.4. 自定义设置技巧(可选操作,可以不填,自动获取)

1.4.1. 方式一:使用网络图片 URL

  • GitHub 图片的正确地址格式:
    • Raw 格式(推荐):https://raw.githubusercontent.com/你的用户名/仓库名/main/图片路径(main也可能是master,看仓库主支名字)
    • jsDelivr CDN 格式(更快): https://cdn.jsdelivr.net/gh/你的用户名/仓库名@main/图片路
  • 示例:
    • 假设你的 GitHub 用户名是 zhangsan,仓库名是 my-icons,图片在仓库根目录叫 logo.png,那么填写:https://raw.githubusercontent.com/zhangsan/my-icons/main/logo.png
    • 或者用 CDN 加速:https://cdn.jsdelivr.net/gh/zhangsan/my-icons@main/logo.png
    • 在添加网站的表单中,找到"图标地址"或"Favicon"输入框,粘贴上述地址即可。
  • 获取网站的真实favicon地址
    • 2026-03-20-sitebox前端部署指南-方法-2026-03-22-20-36-43

1.4.2. 方式二:存放在项目后端服务中(仅仅对非cf部署情况有效)

  • 在图标地址栏输入相对路径,如 /data/icons/custom.ico
  • 要使用这个相对路径,需要确保,后端服务器/data目录下有相应的文件或者文件夹。可以在部署的时候将/data/incos/这个文件夹挂载到本地某个具有图片资源的文件夹

2. nginx配置模版

2.1. ✅ 优化后的完美模板

server {
    listen 80;
    server_name localhost; # 监听域名,可以根据需要修改

    root /usr/share/nginx/html; # 前端静态文件根目录
    index index.html;
    # =======================================================
    # 处理 favicon.ico 请求(直接提供文件)
    location = /favicon.ico {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
    # =======================================================
    # 个人导航主站 (必须放在特定的 location 后面)
    location / {
        try_files $uri $uri/ /index.html; # SPA 应用,处理路由问题
    }

    location /api/ {
        # 直接代理到变量地址,完美支持 IP 或 域名
        proxy_pass ${BACKEND_PROTO}://${BACKEND_ADDR};

        # 强制设置 Host 头,对云服务/外部域名极其重要
        proxy_set_header Host ${BACKEND_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;

        # 开启 SNI 支持:如果是 https 域名,这行保命;如果是 http IP,这行无副作用
        proxy_ssl_server_name on;
    }
}

2.2. 💡 变量赋值示例(供参考验证)

当使用这个完美模板时,针对两种场景,环境变量应该这样传:

2.2.1. 场景 1:后端是局域网 IP(比如你 PVE 里的另一个容器)

  • BACKEND_PROTO = http
  • BACKEND_ADDR = 192.168.3.165:8080
  • BACKEND_HOST = 192.168.3.165:8080 (或者直接用 $host

3. docker-compose

前端容器启动后,其内置的 Nginx 会充当反向代理,将请求跨过互联网转发给后端的 VPS。

3.1. 🚀 远程镜像模式 (docker-compose.yml)

version: '3.8'
services:
  sitebox-frontend:
    image: your-username/sitebox-frontend:latest
    container_name: sitebox-frontend
    restart: always
    ports:
      - "80:80"
    environment:
      # 【关键】这里填后端 VPS 的公网 IP 或域名
      - BACKEND_PROTO=http
      - BACKEND_ADDR=1.2.3.4:3000  # 替换为后端 VPS 的真实公网 IP
      - BACKEND_HOST=1.2.3.4       # 对应 IP

      # 如果后端 VPS 套了 Nginx 且有域名和 HTTPS,则改为:
      # - BACKEND_PROTO=https
      # - BACKEND_ADDR=api.yourdomain.com
      # - BACKEND_HOST=api.yourdomain.com

运行命令:

# 启动
docker-compose up -d
# 查看日志
docker-compose logs -f

3.2. 🛠️ 本地构建模式 (docker-compose.build.yml)

在前端 VPS 上直接从源码构建:

version: '3.8'
services:
  sitebox-frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    container_name: sitebox-frontend
    restart: always
    ports:
      - "80:80"
    environment:
      - BACKEND_PROTO=http
      - BACKEND_ADDR=1.2.3.4:3000
      - BACKEND_HOST=1.2.3.4

运行命令:

# 启动
docker-compose -f docker-compose.build.yml up -d --build
# 查看日志
docker-compose logs -f

4. 容器环境部署的时候的环境变量

4.1. 地址变量(可选)

参见

可选的原因

  • 可以在浏览器直接设置地址,如果设置了就不走nginx去往后端
  • 镜像内默认使用
    • ENV BACKEND_PROTO=http
    • ENV BACKEND_ADDR=localhost:3000
    • ENV BACKEND_HOST=localhost

4.2. nginx规则文件(可选)

没有特殊需求,可以不修改配置文件

4.2.1. 常规docker容器

  • 先在宿主机/mnt/pve/app/npm/目录下新建文件default.conf.template

  • 然后将宿主机:/mnt/pve/app/npm/ 挂载到 容器内:/etc/nginx/templates/

  • 权限检查

4.2.2. PVE-9.1版本lxc直接运行镜像部署方案

对于pve9.1版本开始的,原生运行 OCI/Docker 镜像到 LXC 容器 的新特性,不需要安装 Docker 引擎,直接用镜像构建 LXC 根文件系统。

  • 预设我们在id=106的lxc容器内部署镜像

  • 挂载目录:pct set 106 -mp0 /mnt/pve/app/npm/,mp=/etc/nginx/templates/

  • 权限设置:chown -R 100000:100000 /mnt/pve/app/npm/

  • 配置文件创建:/mnt/pve/app/npm/目录下新建文件default.conf.template

  • 检查权限ls -lh /mnt/pve/app/npm/

  • 原因:lxc容器的root对应到pve宿主机,也只是一个特殊的普通用户

5. 非容器环境部署

cd ./frontend
npm install
npx http-server  -p 8080

6. 前端后端地址设置(重点)

前端支持在页面右下角「后端地址设置」中配置 API 主机地址。

6.1. 填写规则

  • 只填主机地址,不要填 /api
  • 正确示例:
    • https://api.example.com
    • http://192.168.1.10:3000
    • https://sb.sb.dpdns.org
  • 错误示例:
    • https://api.example.com/api(会重复拼接)
    • https://api.example.com/v1(不支持带业务路径)

系统会自动拼接 /api

6.2. 具体场景分析

  • 场景 A:使用域名 + HTTPS
services:
  frontend-nginx:
    build: ./frontend
    ports:
      - "80:80"
    environment:
      - BACKEND_ADDR=sb.nuaa.dpdns.org
      - BACKEND_PROTO=https
      - BACKEND_HOST=sb.nuaa.dpdns.org
  • 场景 B:使用域名 + HTTP
environment:
  - BACKEND_ADDR=sb.nuaa.dpdns.org:80
  - BACKEND_PROTO=http
  - BACKEND_HOST=sb.nuaa.dpdns.org
  • 场景 C:使用 IP + HTTP
environment:
  - BACKEND_ADDR=192.168.1.100:3000
  - BACKEND_PROTO=http
  - BACKEND_HOST=192.168.1.100
  • 场景 D:使用 IP + HTTPS
environment:
  - BACKEND_ADDR=192.168.1.100:443
  - BACKEND_PROTO=https
  - BACKEND_HOST=192.168.1.100

关键点说明

环境变量说明示例值
BACKEND_ADDR后端地址(域名或IP:端口)sb.nuaa.dpdns.org192.168.1.100:3000
BACKEND_PROTO协议httphttps
BACKEND_HOSTHost 头(通常与 BACKEND_ADDR 域名部分相同)sb.nuaa.dpdns.org192.168.1.100

6.3. 清空设置后行为

  • 清空会移除 localStorage 中的 backendUrl
  • 前端回退到默认 /api

6.4. 对于nginx已经设置了地址的情况

  • 首次打开页面的时候还是会检查缓存,如果没有地址,就会有设置界面弹出
  • 如果在设置界面设置了地址,就会根据设置的地址进行请求,nginx的地址将会无效原理
  • 如果继续使用nginx的地址,界面不设置地址,关闭之后,会缓存backendSettingDismissed=true,记录到本页面曾打开过,后续刷新页面不再弹窗显示,直到清空浏览器缓存

6.5. 对于前端部署在cf或者远端vps无法访问本地docker的情况

  • 提供docker实时信息是否获取设置按钮,会记录选择缓存到本地,清空浏览器缓存需要重新设置

6.6. 浏览器填写地址对于nginx的影响

情景说明:

  • 前端部署在192.168.3.165
  • 后端部署在192.168.3.166

6.6.1. 默认情况(不填写地址):走 Nginx 代理

config.js代码逻辑是:export const backendUrl = '/api';

  • 浏览器请求地址: http://192.168.3.165/api/xxxxxxxx
  • 谁处理: 浏览器发现请求的是 .165(即前端 Nginx 所在的服务器)。
  • Nginx 行为: 匹配到 location /api/,根据 proxy_pass 把请求转发给 .166
  • 结论: Nginx 代理生效。

6.6.2. 手动填写地址后:绕过 Nginx

在设置页面填了 http://192.168.3.166:8080,你的代码逻辑变为:backendUrl = 'http://192.168.3.166:8080/api';

  • 浏览器请求地址: http://192.168.3.166:8080/api/xxxxxxxx
  • 谁处理: 浏览器发现这个请求的目的地是 .166,于是它直接通过网络把数据包发给 .166
  • Nginx 行为: 部署在 .165 上的 Nginx 根本看不见这个请求,因为它压根没经过 .165
  • 结论: Nginx 代理被跳过(不起作用)。

7. 常见问题

7.1. 防火墙开放端口 (Firewall)

在后端 VPS 上,你必须通过云服务商的控制台(安全组)或 Linux 自带命令开放 3000 端口,否则前端没法访问。

7.2. 关于跨域 (CORS) 与安全

由于前端和后端 IP 不同,浏览器会认为这是跨域请求。 好消息: 如果你的前端容器里有一个 Nginx 反向代理,浏览器发出的请求是发给前端 IP 的 /api,由前端 Nginx 在后台去请求后端 IP。 结果: 浏览器认为这是“同源”的,你不需要在 Node.js 后端专门去配置复杂的 CORS 跨域规则。这就是使用 Nginx 模板代理的最大好处。

7.3. HTTPS 的必要性

如果前端 VPS 使用了域名并配置了 HTTPS(比如 https://site.com)。 根据浏览器安全策略,你的后端也必须使用 HTTPS,否则请求会被以 Mixed Content 错误拦截。 建议方案: 在后端 VPS 前面也套一个轻量级的 Nginx (或者使用 Caddy/Nginx Proxy Manager) 来申请 SSL 证书。