Data & persistence
Everything Tidefetch keeps is plain files. This page documents exactly what is stored, where, and what you must put on a volume.
The short version for self-hosting: mount two volumes — /config and
/downloads — and you have persisted everything.
What is stored
| Data | File | Volume | Rebuildable? |
|---|---|---|---|
| Settings, RPC secret, web password hash, theme | config.json |
/config |
No — back this up |
| Download history + metadata | history.json |
/config |
No |
| aria2 queue (unfinished/paused downloads) | session.aria2 |
/config |
No — losing it loses the queue |
| DHT routing tables (BitTorrent) | dht.dat, dht6.dat |
/config |
Yes, rebuilt automatically |
| Completed files | your files | /downloads |
No |
| Resume state for in-progress downloads | <file>.aria2 |
/downloads |
No — losing it restarts the file |
| Saved torrent metadata from magnets | <infohash>.torrent |
/downloads |
Yes |
| Web UI login sessions | in memory only | — | Restart requires re-login |
| Live speed-history charts | in memory only | — | Rebuilds as downloads run |
Container layout
The image sets HOME=/config, so every state file resolves beneath it:
/config/
├── .config/tidefetch/
│ └── config.json # settings, RPC secret, bcrypt password hash, theme
├── .local/share/tidefetch/
│ ├── history.json # completed + failed download history
│ └── session.aria2 # aria2 queue, restored on restart
└── .cache/aria2/
├── dht.dat # IPv4 DHT routing table (BitTorrent only)
└── dht6.dat # IPv6 DHT routing table
/downloads/
├── ubuntu-24.04.iso # completed file
├── debian-13.iso # in-progress file
├── debian-13.iso.aria2 # its resume/control file
└── <infohash>.torrent # metadata saved from magnet links
[!IMPORTANT]
config.jsoncontains the aria2 RPC secret and the bcrypt hash of your web password. Treat the/configvolume as sensitive: restrict permissions and encrypt backups.
Minimum volumes
volumes:
- ./config:/config
- /srv/downloads:/downloads
Named volumes work equally well:
volumes:
- tidefetch-config:/config
- tidefetch-downloads:/downloads
Nothing else needs to persist. Mounting only /downloads will lose your
settings, history and queue on every restart.
Native layout
Outside a container, Tidefetch follows platform conventions.
| Platform | Config | Data |
|---|---|---|
| Linux | ${XDG_CONFIG_HOME:-~/.config}/tidefetch/ |
~/.local/share/tidefetch/ |
| macOS | ~/Library/Application Support/tidefetch/ |
~/.local/share/tidefetch/ |
| Windows | %AppData%\tidefetch\ |
%UserProfile%\.local\share\tidefetch\ |
Confirm the resolved paths on any machine with:
tidefetch doctor
File formats
config.json
Plain JSON, mode 0600, written on every settings change.
{
"rpc_url": "ws://127.0.0.1:6800/jsonrpc",
"secret": "…",
"download_dir": "/downloads",
"theme": "surge",
"web_password_hash": "$2a$10$…"
}
history.json
Every completed or failed download, capped by history_limit (default 2000,
oldest entries dropped first). Each entry records name, URI, size, destination,
status, category and timestamps. It is Tidefetch's own record — independent of
aria2, which forgets downloads once they leave its result list.
session.aria2
Written by aria2, not Tidefetch. It holds unfinished and paused downloads with their URIs and options, and is saved every 20 seconds plus on clean shutdown. On startup it is fed back to aria2 so the queue survives restarts.
[!NOTE] Because it saves every 20 seconds, an unclean kill can lose up to 20 seconds of queue changes. Stop the container with
docker compose stop(SIGTERM) rather thandocker killso aria2 flushes first.
.aria2 control files
aria2 writes <filename>.aria2 next to each in-progress download to track
which pieces are complete. Delete one and that download restarts from zero.
They are removed automatically on completion.
This is why partial downloads must live on the same volume you keep — a
separate /incomplete mount is fine, but it has to persist too.
Backups
/config is small (kilobytes) and the only irreplaceable part. Stop the
service first so aria2 flushes its session:
docker compose stop tidefetch
tar -C /srv/tidefetch -czf tidefetch-config-$(date +%F).tar.gz config
docker compose start tidefetch
For a named volume:
docker run --rm \
-v tidefetch-config:/source:ro \
-v "$PWD:/backup" \
alpine tar -C /source -czf /backup/tidefetch-config.tar.gz .
Restore into a stopped service, then fix ownership:
docker compose down
tar -C /srv/tidefetch/config -xzf tidefetch-config-2026-07-26.tar.gz --strip-components=1
chown -R 1000:1000 /srv/tidefetch/config
docker compose up -d
Back up /downloads according to what the files are worth — most are
re-downloadable, so it is usually excluded from off-site backups.
Permissions
The container runs as UID/GID 1000. Both volumes must be writable by it:
chown -R 1000:1000 /srv/tidefetch/config /srv/downloads
chmod 700 /srv/tidefetch/config
On SELinux hosts add :Z to bind mounts. On NFS, confirm root squashing still
lets UID 1000 create, rename and delete — aria2 renames files on completion.
Migrating to another host
- Stop Tidefetch on the old host.
- Copy the whole
/configvolume, and/downloadsif you want the files. - Start on the new host with the same volume paths.
Everything — settings, password, history and the in-flight queue — comes back.
If you copy /config without /downloads, unfinished downloads restart from
the beginning because their .aria2 control files are gone.
Using an external aria2
When Tidefetch attaches to an aria2 you run yourself (-no-spawn), that daemon
owns session.aria2 and the control files at whatever paths you configured.
Tidefetch still keeps config.json and history.json in its own directory, so
/config remains worth persisting.