Docker Development
Overview
Docker applications run in containers managed by the TOS 7 Docker Engine.
Prerequisite: Docker Engine is not pre-installed in TOS 7. It is provided as an application in the TOS App Center and must be installed and enabled by the user. When users install a Docker-based application, the platform automatically checks for Docker Engine and prompts installation if it is missing or disabled — no additional action is required from the developer.
Core Requirements:
- Must provide a
docker-compose.ymlcompatible with Compose Spec 3.8+ - Data must be persisted to NAS-accessible directories via volume mounts
- Privileged mode is strictly prohibited
- System core ports (22, 80, 443, 8181, 5050) must not be occupied
Package Structure (.tar.gz Archive)
The Docker application is submitted as a .tar.gz archive. The archive must contain exactly the following files at the root level:
<appid>.tar.gz
├── config.ini
├── <appid>.lang
├── <appid>.svg
└── docker-compose.yml
File descriptions:
| File | Required | Description |
|---|---|---|
config.ini | ✅ Yes | Application metadata configuration |
<appid>.lang | ✅ Yes | Multilingual file (14 languages) |
<appid>.svg | ✅ Yes | Application icon (SVG format) |
docker-compose.yml | ✅ Yes | Container orchestration configuration |
Important Notes:
- The
config.ini.iconfield must point to/images/icons/<appid>.svg. The platform handles the mapping during installation.- The package name follows the format defined in Chapter 3:
<appid>.tar.gz- For Docker applications with a UI, the
docker-compose.ymlmust include thex-app-metasection (see Section 9.3).- For Docker applications without a UI, the
x-app-metasection is not required.
docker-compose.yml Specification
version: "3.8"
services:
<appid>:
image: <registry>/<image>:<tag> # Images limited to Docker Hub only
container_name: <appid>
restart: unless-stopped
Volumes:
- /Volume*/DockerAppData/<appid>/config:/config
- /Volume*/DockerAppData/<appid>/data:/data
ports:
- "<host_port>:<container_port>"
environment:
- TZ=Asia/Shanghai
user: "1000:1000"
x-app-meta:
web:
port: <host_port>
protocol: http
Note:
*in/Volume*/represents the volume number (e.g., Volume1, Volume2) chosen by the user during installation.
Rules:
- Version: Must be compatible with Compose Spec 3.8 or higher
- x-app-meta: For Docker applications with a UI, the
x-app-metatag must be appended at the end of thedocker-compose.ymlfile (after the services block), containingweb.port(Web UI port number) andweb.protocol(request protocol, typicallyhttp).x-app-meta:
web:
port: 8080
protocol: http - Data Persistence: All data directories must be mounted to host paths. Data stored only inside the container will be lost when the container is removed.
- Port Mapping:
- Disabled ports: 22, 80, 443, 8181, 5050 (system services)
- Recommended range: 8000-19999
- Verify that the selected port is not in use on the TNAS before submission
- Privileged Mode: Strictly prohibited. The
userfield must be used to specify UID/GID. - Timezone: Default configuration
TZ=Asia/Shanghai. Users may modify as needed. - Container Name: Must match the application
id - Restart Policy: Use
unless-stoppedfor normal services - Network Mode:
network_mode: hostis strictly prohibited, except for system-level network tools. System-level network tools must clearly state the rationale at submission and may only use it after approval. Regular applications are strictly prohibited. Using host network mode breaks container isolation and poses security risks. Use port mapping instead:ports:
- "8080:8080" - Timezone: Container timezone must be explicitly configured:
environment:
- TZ=Asia/Shanghai
- TZ=${TZ:-Asia/Shanghai} # Allow user override
Do not leave the timezone empty — inconsistent timestamps can cause data corruption in time-sensitive applications.
Image and Security Requirements
-
Image Source (Docker Hub Only): All Docker images must come from Docker Hub. Non-Docker Hub images will be rejected outright. Images must be hosted on Docker Hub (hub.docker.com). Other image registries (such as ghcr.io, quay.io, self-hosted private registries, etc.) are not supported.
Priority Source Example 1 (Preferred) Docker Hub official project images nginx,postgres2 Docker Hub verified publishers Docker Hub images with Verified badge 3 Docker Hub well-known community images linuxserver/jellyfin(100M+ pulls, actively maintained)❌ Rejected Images from non-Docker Hub sources Private registries, ghcr.io, quay.io, etc. ❌ Rejected Unverified personal images on Docker Hub Docker Hub images with few pulls, no documentation Mandatory Requirement: Images must be hosted on Docker Hub. Image source will be verified during review. Using non-Docker Hub images will result in immediate rejection.
Images from non-Docker Hub sources or unverified Docker Hub images will be rejected during security review.
-
Image Size: Use multi-stage builds or Alpine base images to reduce size.
-
Sensitive Information: Hardcoding passwords, tokens, or secrets in images or compose files is prohibited. Use environment variables or
.envfiles. -
Security Scanning: Run
docker scanortrivybefore submission to check for known vulnerabilities. -
User Permissions: Running as root is strictly prohibited, and
--privilegedmode is strictly prohibited. A non-root user must be specified via theuserfield.
Complete Example
Application Overview:
- ID:
myapp-docker - Type: Docker application
- Image:
linuxserver/myapp:latest - Port: 8080
- Dependency: DockerEngine
config.ini
{
"id": "myapp-docker",
"icon": "/images/icons/myapp-docker.svg",
"publisher": "Developer Name",
"path": "http://${ip}:8080",
"exec": true,
"open_path": true,
"resize": true,
"maxmin": true,
"width": 0,
"height": 0,
"help": "https://github.com/example/myapp/wiki",
"version": "1.0.0",
"recommend": false,
"beta": false,
"low_version": "TOS7.0",
"category": ["Utilities"],
"depend": ["DockerEngine"],
"relation": ["docker", "DockerEngine"],
"platform": "x86_64",
"official": "https://example.com",
"application_type": "docker",
"system_id": "",
"package": "",
"compose_project": "myapp-docker",
"user": "myapp",
"all_user_display": true,
"allow_open_in_mobile": false
}
docker-compose.yml
version: "3.8"
services:
myapp-docker:
image: linuxserver/myapp:1.0.0
container_name: myapp-docker
restart: unless-stopped
Volumes:
- /Volume*/DockerAppData/myapp-docker/config:/config
- /Volume*/DockerAppData/myapp-docker/data:/data
ports:
- "8080:8080"
environment:
- TZ=Asia/Shanghai
- PUID=1000
- PGID=1000
x-app-meta:
web:
port: 8080
protocol: http
Note:
*in/Volume*/represents the volume number (e.g., Volume1, Volume2) chosen by the user during installation. This application opens its WebUI externally, sopathuses thehttp://${ip}:<port>format.
Multi-container Service Startup Order: For applications with multiple services (e.g., Web + Database):
services:
app-db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
app-web:
image: myapp:1.0.0
depends_on:
app-db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
- Use
depends_onwithcondition: service_healthyto ensure correct startup order - Health checks must be defined for every service
- Platform validation: all services must be healthy before the application is shown as "Running"
Health Check Failure Handling:
- After 3 consecutive health check failures, the container is marked as "unhealthy"
- The Application Center displays the application as "Abnormal"
- Docker's restart policy (
unless-stopped) will attempt to restart unhealthy containers - If the container enters a restart loop, the platform will flag the application as needing developer attention
Data Backup, Migration, and Reset
| Operation | Method | Notes |
|---|---|---|
| Backup | Copy the entire /Volume*/DockerAppData/<appid>/ directory to a backup location | It is recommended to back up the configuration and data directories before upgrading |
| Migration | Copy the data directory to a new volume and update the volume mount paths in docker-compose.yml | Cross-volume migration is supported; ensure the container is stopped before proceeding |
| Reset | Delete the /Volume*/DockerAppData/<appid>/data/ and /Volume*/DockerAppData/<appid>/config/ directories | Resets to initial state; user data in shared folders is not affected |
Note: Configuration and data are stored separately, supporting independent backup and recovery. Major upgrades require backing up both directories.