-
Notifications
You must be signed in to change notification settings - Fork 1
Folder Structure
Note
This tree is created by the filetree core role. It is the authoritative layout for the whole
stack: every path below is what the roles actually configure. Source: roles/filetree/ in the
SEEDbox repo.
Based on:
- Overview
- The tree
- Categories
- Ownership and permissions
- How the data flows
- Per-service paths
- The rTorrent exception
data_folder (default /mnt/storage, set in settings.yml) is the root of the data tree. It is
bind-mounted as a single volume on /data in every container.
That single mount is the whole point. Because the download tree and the media library live on the
same filesystem inside the container, the PVRs can hardlink completed downloads into the library
instead of copying them, and moves are atomic. Splitting /downloads and /media into two mounts
is the classic mistake that turns every import into a full copy and doubles disk usage.
data
├── torrents
│ ├── incomplete
│ │ ├── qbittorrent
│ │ └── rutorrent
│ └── complete
│ ├── books
│ ├── comics
│ ├── documentaries
│ ├── games
│ ├── mangas
│ ├── misc
│ ├── movies
│ ├── music
│ ├── software
│ └── tv
├── usenet
│ ├── incomplete
│ │ └── sabnzbd
│ └── complete
│ ├── books
│ ├── comics
│ ├── documentaries
│ ├── games
│ ├── mangas
│ ├── misc
│ ├── movies
│ ├── music
│ ├── software
│ └── tv
└── media
├── books
├── comics
├── documentaries
├── games
├── mangas
├── misc
├── movies
├── music
├── software
└── tv
The incomplete/<client> subfolders are not created by filetree. Each download client role
creates its own on deploy.
The same ten categories are created under torrents/complete, usenet/complete and media:
| Category | Consumed by |
|---|---|
books |
Readarr, Kavita |
comics |
Kavita |
documentaries |
manual |
games |
manual |
mangas |
Kavita |
misc |
catch-all, default SABnzbd category |
movies |
Radarr, Jellyfin |
music |
Lidarr, Navidrome |
software |
manual |
tv |
Sonarr, Jellyfin |
Important
These names are hardcoded in roles/filetree/tasks/main.yml and kept in sync with the categories
configured in the download clients. If you add a category, add it in both places or downloads will
land in a folder the PVRs do not watch.
Every directory is created as {{ user }}:{{ group }} (defaults debian:docker) with symbolic mode
u=rwX,g=rwX,o=rX, which resolves to 0775 on directories. The capital X sets the execute bit on
directories only, so files created later are not made executable.
Containers run as the uid and gid from settings.yml (defaults 1000 and 998), which must
match that owner and group for hardlinking to work across services.
- A PVR (Sonarr, Radarr, Lidarr, Readarr) sends a release to a download client with a category.
- The client downloads into
<protocol>/incomplete/<client>/. - On completion the client moves the files to
<protocol>/complete/<category>/. - The PVR imports, hardlinking into
media/<category>/. - The media servers (Jellyfin, Navidrome, Kavita) read from
media/only.
Because step 4 is a hardlink, the file exists in both complete and media while occupying disk
space once. Deleting the torrent later does not remove the imported media.
| Service | Container mount | Incomplete | Complete |
|---|---|---|---|
| qBittorrent | /data |
/data/torrents/incomplete/qbittorrent |
/data/torrents/complete/<category> |
| ruTorrent |
/data (state) plus /downloads
|
/downloads/incomplete/rutorrent |
/downloads/complete/<category> |
| SABnzbd | /data |
/data/usenet/incomplete/sabnzbd |
/data/usenet/complete/<category> |
| NZBGet | /data |
/data/usenet/nzbget/intermediate |
/data/usenet/<category> |
| Sonarr | /data |
root folder /data/media/tv
|
|
| Radarr | /data |
root folder /data/media/movies
|
|
| Lidarr | /data |
root folder /data/media/music
|
|
| Readarr | /data |
root folder /data/media/books
|
|
| Kavita | /data |
/data/media/books, /comics, /mangas
|
ruTorrent is the one service that cannot take the single /data mount. The
crazymax/rtorrent-rutorrent image hardcodes /data for its own state and /downloads for the
download tree (cfg.basedir and cfg.download in .rtlocal.rc, both const).
The role therefore mounts:
| Host path | Container path |
|---|---|
{{ rutorrent.folder }} |
/data |
{{ data_folder }}/torrents |
/downloads |
Both still resolve to the same host filesystem, so hardlinks keep working. But the paths the client
reports to the PVRs (/downloads/complete/tv) are not the paths the PVRs see
(/data/torrents/complete/tv).
Important
If you use ruTorrent with the PVRs, you must add a remote path mapping in each PVR (Settings, Download Clients, Remote Path Mappings):
| Host | Remote Path | Local Path |
|---|---|---|
rutorrent |
/downloads/ |
/data/torrents/ |
Install
Configuration
Reference
Help