fix: 修复 Docker 持久化目录权限

This commit is contained in:
3127647737@qq.com 2026-07-17 18:51:31 +08:00
parent 87abbc418e
commit 92f8920387
4 changed files with 77 additions and 13 deletions

View File

@ -18,6 +18,7 @@ RUN python -m pip install --upgrade pip "setuptools>=83" \
COPY app ./app
COPY migrations ./migrations
COPY deploy/backup.py ./deploy/backup.py
COPY deploy/prepare-volumes.sh ./deploy/prepare-volumes.sh
RUN mkdir -p /app/data /app/secrets /app/backups \
&& chown -R fluxip:fluxip /app/data /app/secrets /app/backups

View File

@ -313,14 +313,25 @@ AWS 与 DNS 的原子事务。需要人工接管时,先禁用相关实例组
## Docker Compose
Docker Compose 默认把 WebUI 发布到 `127.0.0.1:8787`,并使用三个独立命名卷保存
数据库、主密钥和备份:
Docker Compose 默认把 WebUI 发布到 `127.0.0.1:8787`,并使用项目目录下三个独立的
宿主机目录保存数据库、主密钥和备份:
```text
data/fluxip-data/
data/fluxip-key/
data/fluxip-backups/
```
部署需要 Docker Compose v2使用 `docker compose` 命令)。启动时,一次性的
`fluxip-init` 服务会拒绝挂载目录中的符号链接或特殊文件,把目录权限收紧并交给
UID/GID `10001` 后退出;长期运行的 `fluxip` 服务仍是非 root 用户。已有数据库、
主密钥和备份不会被初始化服务删除或改写内容。
```bash
cp deploy/fluxip.env.example .env
# 编辑 .env至少设置高熵 ROTATOR_BOOTSTRAP_TOKEN
docker compose up -d --build
docker compose ps
docker compose ps -a
curl http://127.0.0.1:8787/readyz
```
@ -340,8 +351,8 @@ docker compose restart fluxip
docker compose down
```
`docker compose down` 不删除命名卷。除非已验证备份并确定要销毁全部数据,否则不要
执行 `docker compose down -v`
`docker compose down` 不删除上述宿主机目录。不要手工删除 `data/fluxip-key/master.key`
数据库存在但主密钥丢失时,已保存的云端凭据将无法解密
## Linux systemd 与 HTTPS
@ -437,6 +448,11 @@ systemd 定时备份示例为 `deploy/fluxip-backup.service` 和
- **任务待清理**:新地址通常已经生效,但旧地址尚未成功释放,应尽快处理以避免费用。
- **客户端短暂掉线**Static IP 替换会终止原 TCP 连接,这是当前架构的预期边界。
- **主密钥缺失**:恢复与数据库匹配的主密钥,不要删除数据库让程序生成新密钥。
- **Docker 启动提示 `/app/secrets/master.key` 无权限**:拉取最新代码后执行
`docker compose down`,再执行 `docker compose up -d --build --force-recreate`,确认
`docker compose ps -a``fluxip-init``Exited (0)`。这两个命令不会删除持久化
目录。旧版本可先停止服务,再将 `data/fluxip-data``data/fluxip-key`
`data/fluxip-backups` 的所有者递归改为 `10001:10001`;不要删除或单独替换已有主密钥。
## 安全清单

25
deploy/prepare-volumes.sh Normal file
View File

@ -0,0 +1,25 @@
#!/bin/sh
set -eu
readonly FLUXIP_UID=10001
readonly FLUXIP_GID=10001
prepare_directory() {
directory=$1
mkdir -p "$directory"
unsafe_entry=$(find "$directory" -xdev ! -type d ! -type f -print -quit)
if [ -n "$unsafe_entry" ]; then
echo "Refusing unsafe volume entry: $unsafe_entry" >&2
exit 1
fi
find "$directory" -xdev -exec \
chown --no-dereference "$FLUXIP_UID:$FLUXIP_GID" {} +
find "$directory" -xdev -type d -exec chmod 0700 {} +
find "$directory" -xdev -type f -exec chmod 0600 {} +
}
prepare_directory /app/data
prepare_directory /app/secrets
prepare_directory /app/backups
echo "FluxIP volume permissions prepared for UID $FLUXIP_UID"

View File

@ -1,4 +1,31 @@
services:
fluxip-init:
build:
context: .
dockerfile: Dockerfile
image: fluxip:local
user: "0:0"
command:
- /bin/sh
- /app/deploy/prepare-volumes.sh
volumes:
- ./data/fluxip-data:/app/data
- ./data/fluxip-key:/app/secrets
- ./data/fluxip-backups:/app/backups
read_only: true
network_mode: none
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- FOWNER
security_opt:
- no-new-privileges:true
healthcheck:
disable: true
restart: "no"
fluxip:
build:
context: .
@ -7,6 +34,9 @@ services:
container_name: fluxip
restart: unless-stopped
init: true
depends_on:
fluxip-init:
condition: service_completed_successfully
ports:
- "${FLUXIP_BIND_ADDRESS:-127.0.0.1}:${FLUXIP_PORT:-8787}:8787"
environment:
@ -52,11 +82,3 @@ services:
options:
max-size: 10m
max-file: "3"
volumes:
fluxip-data:
name: fluxip-data
fluxip-key:
name: fluxip-key
fluxip-backups:
name: fluxip-backups