最佳实践
应用目录布局
遵循一致的目录布局以确保可维护性和兼容性。所有非嵌入式应用(包括官方和第三方应用)均安装在存储卷上,路径为 /Volume*/@apps/<appid>/。
标准目录布局:
/Volume*/@apps/<appid>/
├── <binary> # 应用可执行文件
├── config.ini # 应用配置文件
├── <appid>.lang # 语言文件
├── images/ # 图标资源
├── webui.bz2 # 前端页面压缩包(WebUI 应用)
├── nginx/ # Nginx 配置(外部打开应用)
├── init.d/ # Systemd 服务文件
├── data/ # 运行时数据(缓存、临时文件,可写)
└── logs/ # 应用日志
说明:
/Volume*/中的*表示用户安装时选择的卷号(例如 Volume1、Volume2)。
数据存储建议:
- 运行时数据(
/Volume*/@apps/<appid>/data/)— 应用生成的缓存、临时文件和运行时状态。此类数据可以安全地重新生成。 - 日志(
/Volume*/@apps/<appid>/logs/)— 应用日志文件。确保配置日志轮转。 - 用户业务数据 — 必须存储在
/Volume*/下的共享文件夹中(例如/Volume*/<appid>/),以便用户通过 SMB/NFS 访问。
数据持久化
理解数据类型:
| 数据类型 | 路径 | 描述 |
|---|---|---|
| 运行时数据 | /Volume*/@apps/<appid>/data/ | 缓存、临时文件、运行时状态(可重新生成) |
| 用户数据 | /Volume*/<appid>/(共享文件夹) | 持久化业务数据(必须能在应用升级后保留) |
Deb 应用:
- 运行时数据存储在
/Volume*/@apps/<appid>/data/中 - 用户数据必须存储在应用创建的共享文件夹中:
# 在 postinst 中 — 为用户数据创建共享文件夹
ter_share_add -name <appid> -owner <appid> - 为保持兼容性,应用可创建符号链接:
ln -s /Volume*/<appid> /Volume*/@apps/<appid>/data - 共享文件夹
/Volume*/<appid>/可供用户通过 SMB/NFS 访问
Docker 应用:
- 将配置和运行时数据挂载到
/Volume*/DockerAppData/<appid>/:Volumes:
- /Volume*/DockerAppData/<appid>/config:/config
- /Volume*/DockerAppData/<appid>/cache:/cache - 用户数据必须存储在共享文件夹中:
Volumes:
- /Volume*/<appid>:/data - 禁止在容器文件系统中存储数据
- 配置和数据使用独立卷,以支持独立备份
说明:
/Volume*/中的*表示用户安装时选择的卷号(例如 Volume1、Volume2)。
- 运行时数据可以安全删除,不会丢失用户业务数据
- 用户数据(共享文件夹)必须在应用升级前备份
日志
Deb 应用:
# 使用 systemd 日志(推荐)
# 服务的所有 stdout/stderr 自动被捕获
# 查看日志:journalctl -u <appid>
# 或写入文件
exec >> /Volume*/@apps/<appid>/logs/app.log 2>&1
Docker 应用:
services:
myapp:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
说明: 每个容器日志文件最大 10MB,保留 3 个文件,总日志大小上限为 30MB。
最佳实践:
- 使用结构化日志(推荐 JSON 格式)
- 每条日志包含时间戳、级别和上下文
- 轮转日志防止磁盘耗尽
- 禁止在日志中记录敏感信息(密码、Token、个人数据)
日志保留与清理:
| 日志类型 | 最长保留时间 | 清理方式 |
|---|---|---|
| 应用日志(文件) | 30 天 | Logrotate:每日轮转,保留 30 个文件 |
| Systemd 日志 | 平台管理 | 通过 journald 限制自动管理 |
| Docker 容器日志 | 每文件 10MB,共 3 文件 | Docker 日志驱动配置 |
Logrotate 配置:
/Volume*/@apps/<appid>/logs/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
copytruncate
}
资源限制
| 资源 | Deb 应用(systemd) | Docker 应用(compose) |
|---|---|---|
| 内存 | MemoryMax=512M | memory: 512M |
| CPU | CPUQuota=200% | cpus: '2.0' |
| 文件描述符 | LimitNOFILE=65536 | N/A(容器级别) |
| 进程数 | LimitNPROC=256 | N/A(容器级别) |
| 磁盘 | N/A(使用配额) | 卷大小限制 |
指导原则:
- 根据预期工作负载设置资源限制,而非最大可能用量
- 在典型用量基础上预留 20-30% 的峰值缓冲
- 在 README.md 中记录资源需求
健康检查
Deb 应用:
# 在 systemd 服务文件中
[Service]
StartLimitBurst=3
StartLimitIntervalSec=60
# 看门狗(如应用支持)
WatchdogSec=30
Docker 应用:
services:
myapp:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
升级与迁移
Deb 应用:
- 在
postinst中始终检查旧版本:if [ -n "$2" ]; then
# 从 $2 升级 — 运行迁移
/Volume*/@apps/<appid>/bin/migrate --from "$2"
fi - 升级过程中绝不删除用户数据
- 修改配置格式前先备份
- 迁移逻辑应可逆以支持回滚
- 建议用户将数据存储在
/Volume*/@apps/<appid>/data/内,或者/Volume*/内,确保升级后数据不丢失
Docker 应用:
- 使用入口脚本检测和迁移旧数据格式:
#!/bin/bash
if [ -f /config/version ]; then
OLD_VERSION=$(cat /config/version)
if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
/app/migrate.sh "$OLD_VERSION" "$NEW_VERSION"
fi
fi
echo "$NEW_VERSION" > /config/version - 至少测试最近2个大版本的升级路径
安全加固
Deb 应用:
[Service]
# 丢弃所有能力,仅添加所需
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
# 文件系统保护
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/Volume*/@apps/<appid>/data /Volume*/@apps/<appid>/logs
# 网络命名空间(可选)
# PrivateNetwork=true # 仅当不需要网络时
# 用户命名空间
# PrivateUsers=true
说明: 如果应用需要写入
/etc下的配置文件,必须使用ReadWritePaths显式声明可写路径。
Docker 应用:
services:
myapp:
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # 仅当需要绑定1024以下端口时
read_only: true
tmpfs:
- /tmp
- /run
必须(所有提交必须包含):
NoNewPrivileges=trueProtectSystem=strictProtectHome=trueReadWritePaths(仅显式路径)- 非 root
User/Group建议(强烈建议):
AmbientCapabilities(仅需的能力)LimitNOFILE、LimitNPROCPrivateTmp=truePrivateDevices=true可选(高级加固):
PrivateNetwork=true(仅在不需要网络时)PrivateUsers=trueMemoryDenyWriteExecute=true
应用端口分配
规则:
- 优先在推荐范围 8000-19999 内选择端口(共 12000 个端口,大幅降低冲突概率)
- 若推荐范围端口被占用,可使用 49152-65535(动态端口范围) 作为备选。
- 选择前检查常用端口避免冲突,通过环境变量使端口可配置
- 在 README.md 中文档化端口使用
端口范围说明:
- 8000-19999:为 TOS 7 应用推荐端口段,避开系统核心服务端口(如22/80/443/8181),且数量充足,可满足绝大多数应用的端口需求
- 49152-65535:为 IANA 定义的动态/私有端口段,适合临时或备用场景使用
常用端口参考(避免使用):
| 端口 | 应用 |
|---|---|
| 22 | SSH |
| 80 | TOS Web(HTTP) |
| 443 | TOS Web(HTTPS) |
| 445 | SMB |
| 3306 | MySQL |
| 5050 | TOS 守护进程 |
| 5432 | PostgreSQL |
| 6379 | Redis |
| 8096 | Jellyfin |
| 8181 | TOS Nginx |
| 8443 | TOS HTTPS |
| 9000 | Portainer |
| 9090 | Prometheus |