pve下非特权容器权限处理方案

非特权容器(Unprivileged Container) 权限映射问题及解决方法 在Proxmox VE (PVE) 中直接使用 LXC 运行应用(或者直接将 OCI/Docker 镜像转为 LXC 运行,而不套娃安装 Docker进程),是非常轻量且高效的做法。但这种做法最常遇到的就是无特权容器(Unprivileged Container)的权限与挂载问题。 为了安全,PVE 默认创建的是无特权 LXC。它的核心机制是UID/GID 映射偏移(User Namespace): LXC 容器内的 root (UID 0) = PVE 宿主机的 100000 LXC 容器内的普通用户 (如 UID 1000) = PVE 宿主机的 101000 当你在 PVE 宿主机上把一个硬盘目录通过 Bind Mount(挂载点)映射给 LXC 时,LXC 内部的 比如Syncthing 会因为宿主机目录的属主是 PVE 的 root (0),而容器内的 root 实际上是 100000,从而导致没有读写权限(Permission Denied)。 UID 映射断层场景分析 第一种情况 root@N3150:~# ls -lh /mnt/sdb/Download/ -rw-rw-r-- 1 root root 1.8G Mar 5 08:29 proxmox-ve_9.1-1.iso 在宿主机看来:文件属于 root (UID 0)。 在容器内部看来: 在标准的 PVE 非特权容器中,如果一个文件在宿主机上属于真正的 root (UID 0),在容器内部 ls -l 看它,所有者通常不会显示为 root,而是会显示为 nobody(或者 nogroup / 65534)。因为容器内的 root (0) 已经被映射成了 100000,所以宿主机的真实 root (0) 对容器来说属于“映射范围之外的未知用户”,系统统统会将其显示为 nobody。 第二种情况 root@N3150:~# ls -lh /mnt/sdb/Download/ -rw-rw-r-- 1 root root 1.8G Mar 5 08:29 proxmox-ve_9.1-1.iso -rw-r--r-- 1 100000 100000 0 Mar 28 16:55 /mnt/sdb/Download/test 在宿主机看来:文件属于 lxc容器用户 (UID 100000)。 在容器内部看来: 在容器内部 ls -l 看它,所有者会显示为 root。 为什么 Download 能动,而 Compressed 动不了? root@N3150:~# ls -lhd /mnt/sdb/Download drwxrwxrwx 13 root root 4.0K Mar 28 16:55 /mnt/sdb/Download root@N3150:~# ls -lhd /mnt/sdb/Download/Compressed/ drwxrwxr-x 9 root root 4.0K Mar 26 17:55 /mnt/sdb/Download/Compressed/ 看目录权限位: ...

2026年3月28日 · 8 分钟 · 冇文化

sitebox一体化部署

非容器模式 前端部署 后端部署 容器模式 在一个 VPS 上部署前后端时,最科学、最省资源的方案是:利用前端容器自带的 Nginx 兼职做全站反代。 在这种情况下,只需要 一个 Nginx(即前端容器里的那个) 就可以处理所有事情:发送 HTML、解决 SPA 路由、转发 API 请求。 以下是针对“同机部署”的两种模板: 方案一:本地构建模式 (Build 模式) 适用场景:你在 VPS 上拉取了源码,想直接根据源码生成镜像并运行。 📂 目录结构 /opt/sitebox/ ├── frontend/ # 前端源码 (含 Dockerfile 和 nginx.conf) ├── backend/ # 后端源码 (含 Dockerfile 和 server.node.js) └── docker-compose.yml 🚀 docker-compose.yml (Build) version: '3.8' services: # 前端:既是网页服务器,也是 API 网关 frontend: build: context: ./frontend dockerfile: Dockerfile container_name: sitebox-frontend restart: always ports: - "80:80" # 外部通过 80 端口访问整个项目 environment: - BACKEND_PROTO=http - BACKEND_ADDR=backend:3000 # 使用内部服务名,流量不走公网,安全且快 - BACKEND_HOST=backend networks: - sitebox-net # 后端:纯 API 服务 backend: build: context: ./backend dockerfile: Dockerfile container_name: sitebox-backend restart: always expose: - "3000" # 端口只对容器开放 # ports: # - "3000:3000" # 端口对公网开放,比如给插件使用 environment: - PORT=3000 - DB_PATH=/app/data/db/sitebox.db - DEPLOY_MODE=docker # 如果要同步到github这下面三个参数是必填项 - GITHUB_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx - GITHUB_REPO=xxxxxx/yyyyyyyy - GITHUB_PATH=backup_json/backup.json volumes: - ./data/db:/app/data/db # 持久化数据库 networks: - sitebox-net networks: sitebox-net: driver: bridge 方案二:远程镜像模式 (Image 模式) 适用场景:已经在本地打包好镜像推送到 Docker Hub,VPS 只需要一行命令直接起飞。 ...

2026年3月20日 · 2 分钟 · 冇文化

sitebox后端部署指南

1. 什么是 wrangler.toml backend/wrangler.toml 是 Worker 项目的部署配置文件,相当于 Cloudflare 的“项目清单”。 当前项目示例: name = "sitebox-backend" main = "server.mjs" compatibility_date = "2024-01-01" compatibility_flags = ["nodejs_compat"] [[d1_databases]] binding = "DB" database_name = "sitebox" database_id = "148bb43e-fb40-4dc5-94e0-f2e689194b4b" [vars] DEPLOY_MODE = "cloudflare" GITHUB_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxx" GITHUB_REPO="xxxxxx/yyyyyyyy" GITHUB_PATH="backup_json/backup.json" 各字段含义: name:Worker 服务名(最终会生成可用地址 <name>.<subdomain>.workers.dev) main:入口文件(本项目是 server.mjs,ES Module) compatibility_date:Cloudflare 运行时兼容日期 compatibility_flags:运行时特性开关(这里启用 nodejs_compat) [[d1_databases]]:D1 数据库绑定 binding = "DB" 表示代码里通过 env.DB 访问数据库 database_id 指向具体 D1 数据库 [vars]:普通环境变量(非敏感) 注意:database_id 通常是资源标识,不是密钥;真正敏感的是 API Token / Secret。 2. 使用 Wrangler CLI 部署(推荐) 适用于当前这套 SiteBox 后端,最稳妥。 2.1. 前提 Node.js >= 18 Cloudflare 账户 已在 backend/ 中准备好 wrangler.toml 2.2. 部署步骤 cd SiteBox/backend npm install npx wrangler login npm run deploy:cf 部署成功后会输出 Worker 地址,如: ...

2026年3月20日 · 5 分钟 · 冇文化

sitebox前端部署与使用指南

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地址 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. 💡 变量赋值示例(供参考验证) 当使用这个完美模板时,针对两种场景,环境变量应该这样传: ...

2026年3月20日 · 3 分钟 · 冇文化