pve内基础环境搭建

  • 挂载硬盘到目录

    • 手动挂载:
      • mount /dev/disk/by-uuid/787ca85e-83cb-4111-88e8-c1dcd38c07f3 /mnt/sdb
    • 永久挂载:
      • cp -a /etc/fstab /etc/fstab.bak
      • nano /etc/fstab 底部加入UUID=787ca85e-83cb-4111-88e8-c1dcd38c07f3 /mnt/sdb ext4 defaults 0 2
      • 更完整的命令:UUID=787ca85e-83cb-4111-88e8-c1dcd38c07f3 /mnt/sdb ext4 rw,noatime,nofail,noexec,nodev,nosuid 0 2
        • rw:读写权限(仅宿主机层面,容器层面会通过 ACL/mpX 参数二次限制)
        • noatime:不记录文件访问时间,减少磁盘写入
        • nofail:硬盘故障时跳过挂载,不影响宿主机开机
        • noexec,nodev,nosuid:禁止在该盘执行二进制文件、创建设备文件、使用 SUID 提权位,生产环境必须加
        • 0 2:不做 dump 备份(因为这是备份盘本身),开机后第二个检查(根分区是第一个)
  • 安装ACL应对文件权限处理

    • apt install acl
  • 设置涉及到lxc挂载的目录权限 前提是这些容器内的id都是100000,可以使用ps -auxn | grep syncthing来确认具体id。

    • aria2-pro:/mnt/sdb

      setfacl -R  -m u:100000:rwx /mnt/sdb/
      setfacl -R -d -m u:100000:rwx /mnt/sdb/
      
    • syncthing:/var/lib/vz/dump

      setfacl -R  -m u:100000:rwx /var/lib/vz/dump
      setfacl -R -d -m u:100000:rwx /var/lib/vz/dump
      
    • openlist:/mnt/sdb

      setfacl -R  -m u:101001:rwx /mnt/sdb/
      
      setfacl -R -d -m u:101001:rwx /mnt/sdb/
      

openlist

元信息

比如目录结构:/test/test2/test3/test4

  • 当对/test这个目录设置规则:
    • 可读admin
      • 如果不设置应用子文件夹,那对于非 admin用户,他将不能访问test但是他能访问从test2开始的全部子目录
      • 如果设置应用子文件夹,那对于非 admin用户,他将不能访问全部
    • 隐藏.*
      • 如果不设置应用子文件夹,那用户不能看到test2这个层级的全部内容,但是可以看到test3test4这个层级的内容
      • 如果设置为应用子文件夹,那就不能访问全部

基于sing-box部署隔离局域网

局域网隔离架构

sing-box

基于pve-91版本lxc直接部署oci容器sing-box


s-ui

基于pve-91版本lxc直接部署oci容器s-ui

境内家宽公网IP+PVE+sing-box合规部署方案 vless节点配置 hysteria2节点配置 已知问题:

  • wireguard的peer端点信息错位
  • 二维码地址拼接错误

wiregurad-tools

基础安装配置

把Alpine LXC 容器作为 WireGuard 服务端,用于远程访问家中局域网,需要开启 IP 转发NAT 流量转发

以下是完整步骤:

1. 确保 PVE 宿主机已准备好(非常重要)

  • PVE 宿主机上编辑 /etc/pve/lxc/容器ID.conf,添加:
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
  • 在 PVE 宿主机上执行,确认模块已加载:lsmod | grep wireguard
  • 如果没有输出,手动加载:modprobe wireguard

2. 在 Alpine 容器内开启内核转发

作为服务端,它必须能够把来自外网的流量转发到家里的其他设备。

  • 编辑 /etc/sysctl.conf
vi /etc/sysctl.conf
  • 添加(或修改)以下内容:
net.ipv4.ip_forward = 1
  • 保存后使其立即并且永久生效:
sysctl -p
rc-update add sysctl boot

3. 安装 iptables (用于流量转换)

要访问局域网,通常需要做 NAT 映射:

apk add iptables

4. 生成服务器密钥

cd /etc/wireguard
umask 077
wg genkey | tee server_privatekey | wg pubkey > server_publickey
wg genkey | tee client_privatekey | wg pubkey > client_publickey

现在有了服务器和客户端的两对密钥。


5. 编写服务端配置文件 wg0.conf

这是关键。我们需要在启动 VPN 时自动设置防火墙规则。

nano /etc/wireguard/wg0.conf

写入以下内容(注意修改 eth0 为你容器实际的网卡名,通过 ip addr 查看):

[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <这里填 server_privatekey 的内容>

# 核心:以下规则允许流量通过这个容器转发到局域网
# 假设容器网卡是 eth0
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# 以下是手机或笔记本客户端
[Peer]
PublicKey = <这里填 client_publickey 的内容>
AllowedIPs = 10.0.0.2/32

如果使用nftables:

PostUp = nft add table inet wireguard; nft add chain inet wireguard forward { type filter hook forward priority 0 \; }; nft add rule inet wireguard forward iifname "wg0" accept; nft add table inet nat; nft add chain inet nat postrouting { type nat hook postrouting priority 100 \; }; nft add rule inet nat postrouting oifname "eth0" masquerade
PostDown = nft delete table inet wireguard; nft delete table inet nat

6. 启动并设置自启动

开机自启命令:

# 创建服务软链接
ln -s /etc/init.d/wg-quick /etc/init.d/wg-quick.wg0

# 启动服务
rc-service wg-quick.wg0 start

# 设置开机自启
rc-update add wg-quick.wg0 default

7. 客户端(手机/电脑)配置

在手机 WireGuard App 上新建一个配置:

[Interface]
PrivateKey = <这里填 client_privatekey 的内容>
Address = 10.0.0.2/24
DNS = 223.5.5.5

[Peer]
PublicKey = <这里填 server_publickey 的内容>
Endpoint = <你家里的公网IP>:51820
# 关键:如果你想访问家里所有设备,这里要包含家里的网段
# 比如家里网段是 192.168.1.x,那就写下面的内容:
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

8. 最后一步:路由器端口转发 (Port Forwarding)

由于你的 PVE 在路由器后面,你需要在 家里的主路由器 上做端口转发:

  • 外部端口: 51820
  • 内部端口: 51820
  • 协议: UDP (WireGuard 只使用 UDP)
  • 内部 IP: 这个 Alpine LXC 容器在局域网的 IP (比如 192.168.1.100)

常见操作场景

  • 我想增加一个客户端: 编辑 /etc/wireguard/wg0.conf,再加一个 [Peer] 区块,然后 rc-service wg-quick.wg0 restart
  • 查看连接状态: 在容器内输入 wg show
  • 无法访问家里的设备:
    1. 检查 Alpine 里的 net.ipv4.ip_forward 是否为 1。
    2. 检查 iptables 规则是否正确加载(输入 iptables -L -n -v 查看)。
    3. 检查容器的网卡名是否真的是 eth0

进阶设置,自动生成手机客户端配置文件

自动生成客户端的 私钥/公钥,分配 IP 地址,生成 .conf 配置文件,甚至直接在终端显示 二维码,方便手机扫码导入。

第一步:安装必要的工具

在 Alpine 容器内执行,安装二维码生成工具:

apk add libqrencode
apk add libqrencode-tools

第二步:创建脚本文件

创建一个脚本,例如叫 add_client.sh

vi /etc/wireguard/add_client.sh

复制并粘贴以下代码:

#!/bin/bash

# 配置基础变量
WG_PATH="/etc/wireguard"
SERVER_CONF="$WG_PATH/wg0.conf"
SERVER_PUB_KEY=$(cat $WG_PATH/server_publickey)
# --- 请修改以下两项 ---
ENDPOINT="你的公网IP或DDNS域名:51820"
LAN_SUBNET="192.168.1.0/24"  # 你家里的局域网网段
# --------------------

echo "请输入新客户端的名称 (例如: phone, laptop):"
read CLIENT_NAME

if [ -z "$CLIENT_NAME" ]; then
    echo "错误: 名称不能为空"
    exit 1
fi

# 生成客户端密钥
CLIENT_PRIV_KEY=$(wg genkey)
CLIENT_PUB_KEY=$(echo "$CLIENT_PRIV_KEY" | wg pubkey)

# 自动分配一个没被占用的 IP (从 10.0.0.2 开始)
for i in {2..254}; do
    CLIENT_IP="10.0.0.$i"
    if ! grep -q "$CLIENT_IP" "$SERVER_CONF"; then
        break
    fi
done

# 1. 生成客户端配置文件
CLIENT_FILE="$WG_PATH/$CLIENT_NAME.conf"
cat <<EOF > "$CLIENT_FILE"
[Interface]
PrivateKey = $CLIENT_PRIV_KEY
Address = $CLIENT_IP/24
DNS = 223.5.5.5, 8.8.8.8

[Peer]
PublicKey = $SERVER_PUB_KEY
Endpoint = $ENDPOINT
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF

# 2. 将客户端公钥添加到服务端配置
cat <<EOF >> "$SERVER_CONF"

# Client: $CLIENT_NAME
[Peer]
PublicKey = $CLIENT_PUB_KEY
AllowedIPs = $CLIENT_IP/32
EOF

# 3. 重启 WireGuard 服务以生效
rc-service wg-quick.wg0 restart

echo "------------------------------------------------"
echo "客户端 $CLIENT_NAME 已创建!"
echo "客户端 IP: $CLIENT_IP"
echo "配置文件位置: $CLIENT_FILE"
echo "------------------------------------------------"
echo "请使用手机 WireGuard App 扫描下方二维码导入配置:"
echo "------------------------------------------------"

# 4. 生成二维码显示在终端
qrencode -t ansiutf8 < "$CLIENT_FILE"
#如果你发现生成的二维码在你的终端里显示得“太宽”或者乱码(因为有些终端的行间距问题),可以尝试在脚本里把最后一行改为:
#qrencode -t ansiutf8 -m 2 < "$CLIENT_FILE"
# -m 2 是增加边距,有时能提高手机扫描的识别率。

第三步:运行脚本

  1. 赋予执行权限

    chmod +x /etc/wireguard/add_client.sh
    
  2. 修改脚本内的公网 IP: 记得用 vi 修改脚本里的 ENDPOINT="你的公网IP或DDNS域名:51820" 这一行。

  3. 执行脚本

    /etc/wireguard/add_client.sh
    

如何使用

  1. 运行脚本后,输入名字(比如 iphone)。
  2. 屏幕上会直接出现一个巨大的二维码
  3. 打开手机上的 WireGuard App
  4. 点击 + 号(添加隧道),选择 扫描二维码 (Scan from QR code)
  5. 对准电脑屏幕扫码,配置就直接进手机了。

进阶说明

  • AllowedIPs = 0.0.0.0/0:这意味着手机开启 VPN 后,所有流量(包括刷抖音、看网页)都会经过家里的宽带。

    • 好处:绝对安全,且能像在家里一样翻墙(如果你家里有梯子)。
    • 坏处:如果家里宽带上传速度慢,手机上网会变慢。
  • 如果你只想访问家里设备,不想让手机所有流量都走家里,把脚本里的 AllowedIPs = 0.0.0.0/0 改为 AllowedIPs = 10.0.0.0/24, 192.168.1.0/24(后面这个是你家里的局域网段)。

  • 端口号的选择是由网络协议(UDP/TCP)决定的,它的有效范围是 1 到 65535

  • 如果修改了端口,记得修改这三个地方

    • 服务端配置文件 (/etc/wireguard/wg0.conf)

      [Interface]
      ListenPort = 8989
      ...
      
    • 生成脚本 (add_client.sh): 要把脚本里的 ENDPOINT="你的公网IP:51820" 改成 ENDPOINT="你的公网IP:8989"。这样以后生成的二维码才是对的。

    • 路由器端口转发: 路由器上的 UDP 转发规则也必须同步修改:

      • 外部端口:8989
      • 内部端口:8989
      • 协议:UDP

如果你想把文件导出来

如果你不方便扫码,生成的配置文件在 /etc/wireguard/客户端名.conf。你可以用 cat /etc/wireguard/phone.conf 查看内容,复制到手机上保存为 .conf 文件即可。

ghcr.io/monstercjz/upsnap:1.0.8

  • 点击选项->环境变量

    • 添加HOME=/root
      • 如果不添加会报错
      • 通过在pve内执行lxc-start -n 244 -F捕获启动失败原因
    • 添加TZ=Asia/Shanghai
      • 如果不添加,定时任务就会使用非本地正确时间
  • 自定义ping:nc -z -w 3 192.168.3.130 4899

    • 通过自定义检查4899端口来确定是否开机,因为在lxc里进行转发,地址是lxc的,但是会转发到lxc对应的windows系统电脑。
    • 这种模式适配的是当前网络布局,lxc双ip,游戏主机隐藏在lxc背后
    • 如果不使用自定义命令,而是使用页面中必填项中的ip和子网掩码,upsnap会向lxc容器发送响应命令,但是端口不是4899,lxc就会正常响应,而不会把upsnap的命令转发给对应的windows系统电脑。从而也就无法知道真实的是否在线状态
    • 命令有效的前提是,4899端口已经在/etc/nftables.d/singbox-rules.nft做了转发处理。
      • ip saddr { 192.168.3.3, 192.168.3.241 } ip daddr 192.168.81.2 tcp dport { 4899, 22000 } accept comment "Allow Radmin & Syncthing TCP"
      • ip daddr 192.168.3.130 tcp dport 4899 dnat to 192.168.81.2:4899
  • 自定义唤醒:/bin/sh -c "echo 'wake' | nc -u -w1 192.168.3.130 9"或者echo wake | nc -u -w1 192.168.3.130 9

    • 向具体的lxc的ip发送唤醒udp包,lxc会根据端口9号,和包的ip是否是lxc本机,来决定是否触发唤醒对应的windows系统电脑。
    • 能正确实现的前提是,socat已经安装运行,并且/etc/init.d/wol-relay是否正常创建且运行,同时做了预设定。
      • command_args="-u UDP4-LISTEN:9,bind=192.168.3.130,reuseaddr,fork EXEC:/usr/local/bin/wake-win.sh"
    • 如果不用自定义命令,而是使用页面中必填项中的ip和子网掩码,upsnap依然会向192.168.3.255或者255.255.255.255发送广播报,如果这个时候,lxc没有做ip绑定判断,就会导致一个唤醒动作,就唤醒起了局域网的全部电脑
  • 当设置了自定义ping和自定义唤醒之后,在当前这种网络布局中,页面中的ipMAC地址子网掩码其实已经没有具体作用了

ghcr.io/v2raya/v2raya:v2.2.7.5

  • 点击选项->环境变量
    • 添加V2RAYA_V2RAY_BIN=/usr/local/bin/v2ray
    • 或者添加V2RAYA_V2RAY_BIN=/usr/local/bin/xray
    • v2ray支持均衡负载,xray似乎设置无效

jeessy/ddns-go

如果需要指定配置文件:

  • 点击选项 -> entrypoint 在原有命令后面添加-c /root/.ddns_go_config.yaml
  • 如果不需要把网页设置配置文件挂载出来,就无需修改,安装完毕直接在管理页面进行对应域名的设置即可

syncthing/syncthing

  • puidpgid 改为0,适配pve里对目录赋予100000的权限
  • 在配置文件中添加下面这一行挂载代码
  //nano /etc/pve/lxc/id.conf
  mp0: /var/lib/vz/dump,mp=/mnt/dump-local

ghcr.io/wg-easy/wg-easy

  • 镜像版本选择15

    • ghcr.io/wg-easy/wg-easy:15
  • 进入选项设置

    • 修改HOST为真实的值:比如192.168.1.2
    • 修改insecure为true,否则需要https登入,对于局域网ip登入就会失败
    • 修改INIT_ENABLED为true,就会初始化这些变量
    • 修改DISABLE_IPV6为true,禁用ipv6
  • 进入lxc执行ip转发设置

    • 永久开启:
    echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
    
    • 实际情况,由于这个容器并没有启动标准的 Linux 初始化系统(没有运行 OpenRC 或 Systemd)。它开机后,内核直接把 PID 1 交给了 Entrypoint 里的命令。也就是说,它根本不会去读取 /etc/local.d 或者 /etc/init.d 里的任何自启动脚本。所以上面设置的开启转发并没有在启动的时候加载
    • 为了加载转发设置,需要执行sysctl -p
      • 在 PVE 网页端,双击Entrypoint那一行进行编辑
      • 将原本的内容:docker-entrypoint.sh /usr/bin/dumb-init node server/index.mjs
      • 修改为(利用 shell 将两个命令串联):/bin/sh -c "sysctl -p; exec docker-entrypoint.sh /usr/bin/dumb-init node server/index.mjs"
  • 页面设置

    • 自定义域名:
      • 面板管理-网络配置,主机
      • 面板管理-网络配置,端口
      • 网络配置里的端口修改之后,接口配置里的端口也应该修改,并且两者需要保持一致
      • 域名不需要前缀比如https://
      • 最终Endpoint = 域名:端口
      • 端口修改之后,应该去路由器里修改对应的端口

ghcr.io/metacubex/metacubexd

chishin/nginx-proxy-manager-zh

  • 如果不需要把证书挂载出来,就无需修改,安装完毕直接在管理页面进行对应域名的设置即可

sitebox-backend

  • 点击选项 -> Environment 修改GITHUB_TOKEN,GITHUB_REPO,GITHUB_PATH对应的值
  • 具体参见

p3terx/aria2-pro

修改参数

2026-03-28-lxc容器项目创建-20260328173326-2026-03-28-17-33-30

挂载下载目录

在配置文件中添加下面这一行挂载代码

  //nano /etc/pve/lxc/id.conf
  mp0: /mnt/sdb/Download,mp=/downloads

修改move.sh

#!/usr/bin/env bash
#
# https://github.com/P3TERX/aria2.conf
# File name:move.sh
# Description: Move files after Aria2 download is complete
# Version: 3.0
#
# Copyright (c) 2018-2021 P3TERX <https://p3terx.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#

CHECK_CORE_FILE() {
    CORE_FILE="$(dirname $0)/core"
    if [[ -f "${CORE_FILE}" ]]; then
        . "${CORE_FILE}"
    else
        echo "!!! core file does not exist !!!"
        exit 1
    fi
}

TASK_INFO() {
    echo -e "
-------------------------- [${YELLOW_FONT_PREFIX}Task Infomation${FONT_COLOR_SUFFIX}] --------------------------
${LIGHT_PURPLE_FONT_PREFIX}Task GID:${FONT_COLOR_SUFFIX} ${TASK_GID}
${LIGHT_PURPLE_FONT_PREFIX}Number of Files:${FONT_COLOR_SUFFIX} ${FILE_NUM}
${LIGHT_PURPLE_FONT_PREFIX}First File Path:${FONT_COLOR_SUFFIX} ${FILE_PATH}
${LIGHT_PURPLE_FONT_PREFIX}Task File Name:${FONT_COLOR_SUFFIX} ${TASK_FILE_NAME}
${LIGHT_PURPLE_FONT_PREFIX}Task Path:${FONT_COLOR_SUFFIX} ${TASK_PATH}
${LIGHT_PURPLE_FONT_PREFIX}Aria2 Download Directory:${FONT_COLOR_SUFFIX} ${ARIA2_DOWNLOAD_DIR}
${LIGHT_PURPLE_FONT_PREFIX}Custom Download Directory:${FONT_COLOR_SUFFIX} ${DOWNLOAD_DIR}
${LIGHT_PURPLE_FONT_PREFIX}Source Path:${FONT_COLOR_SUFFIX} ${SOURCE_PATH}
${LIGHT_PURPLE_FONT_PREFIX}Destination Path:${FONT_COLOR_SUFFIX} ${DEST_PATH}
${LIGHT_PURPLE_FONT_PREFIX}.aria2 File Path:${FONT_COLOR_SUFFIX} ${DOT_ARIA2_FILE}
-------------------------- [${YELLOW_FONT_PREFIX}Task Infomation${FONT_COLOR_SUFFIX}] --------------------------
"
}

OUTPUT_MOVE_LOG() {
    LOG="${MOVE_LOG}"
    LOG_PATH="${MOVE_LOG_PATH}"
    OUTPUT_LOG
}

DEFINITION_PATH() {
    SOURCE_PATH="${TASK_PATH}"
    if [[ "${DOWNLOAD_DIR}" != "${ARIA2_DOWNLOAD_DIR}" && "${DOWNLOAD_DIR}" =~ "${ARIA2_DOWNLOAD_DIR}" ]]; then
        DEST_PATH="${DEST_DIR}${DEST_PATH_SUFFIX%/*}"
        #DEST_PATH="${DEST_DIR}"
    else
        DEST_PATH="${DEST_DIR}"
    fi
}
DEFINITION_PATHS() {
    local SUB_DIR="$1"  # 接收传递的 SUB_DIR 参数,根据分类重新构建目标目录
    SOURCE_PATH="${TASK_PATH}"
    if [[ "${DOWNLOAD_DIR}" != "${ARIA2_DOWNLOAD_DIR}" && "${DOWNLOAD_DIR}" =~ "${ARIA2_DOWNLOAD_DIR}" ]]; then
        # DEST_PATH="${DEST_DIR}/${SUB_DIR}/${DEST_PATH_SUFFIX%/*}" # 如果不添加subdir这个变量,就是直接把文件夹复制到comlete目录下
        DEST_PATH="${DEST_DIR}${DEST_PATH_SUFFIX%/*}"
    else
        DEST_PATH="${DEST_DIR}/${SUB_DIR}"
    fi
}

MOVE_FILE() {
    echo -e "$(DATE_TIME) ${INFO} Start move files ..."
    TASK_INFO
    mkdir -p "${DEST_PATH}"

    # 获取要移动的文件列表
    IFS=$'\n' read -d '' -r -a FILES < <(find "${SOURCE_PATH}" -type f)

    for FILE in "${FILES[@]}"; do
        # 获取文件扩展名
        EXTENSION="${FILE##*.}"
        EXTENSION_LOWER=$(echo "$EXTENSION" | tr '[:upper:]' '[:lower:]')
        # 根据文件类型设置目标子文件夹
        case "$EXTENSION_LOWER" in
            "exe"|"msi"|"lua"|"py"|"sh"|"vbs"|"js"|"bat"|"cmd"|"pl"|"apk"|"jar"|"class"|"c"|"cpp"|"h"|"java"|"php"|"go"|"rs"|"ts"|"swift"|"m"|"mm"|"cs"|"vb"|"ps1")
                SUB_DIR="Programs"
                ;;
            "pdf"|"doc"|"docx"|"txt"|"csv"|"xls"|"xlsx"|"odt"|"ods"|"rtf"|"md")
                SUB_DIR="Documents"
                ;;
            "zip"|"tar"|"gz"|"tgz"|"bz2"|"rar"|"7z"|"xz")
                SUB_DIR="Compressed"
                ;;
            "mp4"|"avi"|"mkv"|"mov"|"wmv"|"flv"|"mpg"|"mpeg"|"m4v"|"webm"|"3gp"|"3g2"|"mts"|"m2ts"|"ts")
                SUB_DIR="Video"
                ;;
            "mp3"|"wav"|"flac"|"aac"|"ogg"|"wma"|"m4a"|"opus"|"alac"|"aiff"|"dsd"|"ape"|"cue"|"tak"|"wv"|"tta"|"ra"|"spx")
                SUB_DIR="Music"
                ;;
            *)
                SUB_DIR="other"
                ;;
        esac

        # 创建目标子文件夹
        DEFINITION_PATHS "${SUB_DIR}"  # 传递 SUB_DIR 参数
        # DEST_SUB_DIR="${DEST_PATH}/${SUB_DIR}"
        mkdir -p "${DEST_PATH}"

        # 移动文件
        mv -vf "${FILE}" "${DEST_PATH}"
        MOVE_EXIT_CODE=$?
        if [ ${MOVE_EXIT_CODE} -eq 0 ]; then
            MOVE_LOG+="$(DATE_TIME) ${INFO} Move done: ${FILE} -> ${DEST_PATH}\n"
        else
            MOVE_LOG+="$(DATE_TIME) ${ERROR} Move failed: ${FILE}\n"
        fi
    done

    OUTPUT_MOVE_LOG
    DELETE_EMPTY_DIR
}

CHECK_CORE_FILE "$@"
CHECK_PARAMETER "$@"
CHECK_FILE_NUM
CHECK_SCRIPT_CONF
GET_TASK_INFO
GET_DOWNLOAD_DIR
CONVERSION_PATH
DEFINITION_PATH
CLEAN_UP
MOVE_FILE
exit 0

pve里设置下载目录权限确认

  • lxc容器里的root对应就是pve里的100000
  • 如果不使用ACL设置权限,就会导致pve里的root在lxc里看到的是nobody,没有读写权限
  • getfacl /mnt/sdb/Download/检查权限,结果如下
    getfacl: Removing leading '/' from absolute path names
    # file: mnt/sdb/Download/
    # owner: root
    # group: root
    user::rwx
    user:100000:rwx <-- 这就确认有rws权限
    group::rwx
    mask::rwx
    other::rwx
    default:user::rwx <-- 这就确认继承者有rws权限
    default:user:100000:rwx
    default:group::rwx
    default:mask::rwx
    default:other::rwx

结尾