Operating Hydranos - Kheopsian/Hydranos GitHub Wiki
Applies to Hydranos 4.4.
For whoever keeps an instance running: how to stop it without losing resume state, what the restart buttons do, what the start looks like, what to back up and how to restore it, what to do when the store will not open or the password is lost, and how to update on Docker, Linux and Windows.
Short version: every stop and every restart (Docker, systemd, the tray, the web UI's restart buttons) goes through the same clean stop; keep the supervisor's stop limit above HYDRANOS_STOP_TIMEOUT + 10 s. To back up: stop Hydranos, copy its folder(s), start it again.
| Platform | Start | Clean stop |
|---|---|---|
| Docker | docker compose up -d |
docker compose stop / docker stop hydranos (SIGTERM, then SIGKILL after the grace period) |
| Linux (systemd) | sudo systemctl start hydranos |
sudo systemctl stop hydranos (SIGTERM, then SIGKILL after TimeoutStopSec) |
| Linux (in a shell) | hydranos --config /path/to/default.toml |
Ctrl+C (SIGINT) or kill <pid> (SIGTERM) |
| Windows |
hydranos.exe (double-click, shortcut or Startup folder; --config optional) |
tray › Quit Hydranos; in a console (--console), Ctrl+C, Ctrl+Break or closing the window |
Hydranos stops the same way on every trigger (signal, tray, console event, the Windows updater's stop request, a restart asked from the UI or the API):
- The UI's event stream (
/api/events) and the Logs live tail end themselves; the HTTP server stops accepting connections and lets in-flight requests finish, for 5 s at most. -
Departures: every torrent that announced
startedsendsstoppedto its trackers, race engines first, 5 s at most for all of them. - The resume state of every engine is written (each engine on its own thread, in parallel), bounded by
HYDRANOS_STOP_TIMEOUT. - Managed WireGuard tunnels are taken down.
- Exit with code 0, or 75 when the stop is a restart (see Restart from the UI).
Nothing is written to the store at that point: store changes are committed as they happen.
sequenceDiagram
participant S as Supervisor - Docker, systemd or you
participant M as hydranos
participant H as HTTP server
participant T as trackers
participant R as race engine thread
participant D as hoard engine thread
S->>M: SIGTERM, SIGINT, Ctrl+C, a Windows console event, tray Quit Hydranos or a restart request
M->>H: event stream and log tail end, stop accepting connections
H-->>M: in-flight requests finished, or 5 s passed
M->>T: stopped for every started torrent, race first, 5 s at most
par one thread per engine
M->>R: write every resume row to race/state.db
R-->>M: resume data saved, took_ms
and
M->>D: write every resume row to hoard/state.db
D-->>M: resume data saved, took_ms
end
alt every engine done within HYDRANOS_STOP_TIMEOUT
M->>M: log shutdown flush complete, took_s
else budget reached
M->>M: log WARN shutdown flush hit HYDRANOS_STOP_TIMEOUT, leave with what is saved
end
M->>M: take managed WireGuard tunnels down
M-->>S: exit code 0, or 75 for a restart
Note over S,M: If the supervisor's grace period ends first, it sends SIGKILL.<br/>Rows not yet written fall back to the last 300 s save.
Extra engines get their own thread in the same way. What you see in the log (Linux):
WARN SIGTERM received, draining the API and flushing resume data
INFO stopped sent to the trackers departed=… of=…
INFO resume data saved engine=race took_ms=…
INFO resume data saved engine=hoard took_ms=…
INFO shutdown flush complete took_s=…
The stopped sent to the trackers line is absent only when no torrent had announced started. The first line names the trigger (SIGINT, restart request…); on Windows it reads <trigger>: draining the API and flushing resume data, e.g. tray quit:, console closed:, system shutdown:. A tab still holding a connection after 5 s adds WARN connections still open 5 s into the drain (event stream, log tail); flushing without them. With managed WireGuard, INFO wireguard: tunnels taken down tunnels=… follows the flush.
A stop asked while the catalogue is still loading is heard: the load finishes, nothing more starts, and Hydranos logs stop requested during startup; flushing and leaving, sends the departures, flushes and exits.
HYDRANOS_STOP_TIMEOUT (default 120) bounds the flush: past it, Hydranos stops waiting, logs shutdown flush hit HYDRANOS_STOP_TIMEOUT; leaving with what is saved (budget_s=…) and exits with what is written; each engine's state.db commits per transaction, so what was written stays written. Accepted forms: 120, 60s, 2m, 1m30s, 1h (units largest first, each once). Anything else (30s1m, 1.5m, -5, empty) is refused at startup with WARN HYDRANOS_STOP_TIMEOUT="…" is not a duration (use 120, 60s, 2m or 1m30s); using 120 s. 0 means leave without waiting for the flush. The value is read once, at startup.
A stop takes at most about 5 s (drain) + 5 s (departures) + HYDRANOS_STOP_TIMEOUT, i.e. 130 s by default. The supervisor's limit must be above that, or it kills the flush:
| Supervisor | Setting | Shipped value | Set it to |
|---|---|---|---|
| Docker Compose | stop_grace_period |
150s in the repository's compose file |
HYDRANOS_STOP_TIMEOUT + 10 s or more |
docker run / Unraid |
--stop-timeout |
Docker default 10 s (install.sh node install: 150) |
same; Docker uses 150
|
| systemd | TimeoutStopSec |
150 in packaging/hydranos.service
|
same |
| Windows |
HYDRANOS_STOP_TIMEOUT itself (default 120 s) |
— | quit from the tray before shutting Windows down (on sign-out or shutdown Windows allows only a few seconds); never End task |
If you raise HYDRANOS_STOP_TIMEOUT for a large catalogue, raise the supervisor's limit with it. Measure your own flush time after a stop:
docker logs hydranos 2>&1 | grep "shutdown flush" # Docker
journalctl -u hydranos | grep "shutdown flush" # systemdOn Windows, the log is hydranos.log in the config dir: findstr /C:"shutdown flush" C:\Hydranos\hydranos.log.
If you see SIGTERM received… but neither shutdown flush complete nor shutdown flush hit HYDRANOS_STOP_TIMEOUT before the process dies, the supervisor killed it first: its limit is below HYDRANOS_STOP_TIMEOUT + 10 s.
-
Array stop. Stopping the array (or the Docker service) stops every container; whether Unraid honours the container's
--stop-timeoutthere is not tested by the maintainer. Stop the hydranos container yourself on the Docker tab first, wait until it shows stopped, then stop the array. Noshutdown flushline indocker logs hydranosmeans the flush was cut. -
Behind gluetun (
network_mode: "service:gluetun"): stop hydranos before gluetun. If gluetun is restarted or updated, hydranos keeps a dead network namespace (no network, no web UI) until you restart it too (Docker behaviour, not tested by the maintainer). Recipe: VPN and Egress.
Several controls restart Hydranos: Restart now (banner on the Nodes tab after an engine change), Apply & restart or Apply and restart (after saving a setting that needs it, e.g. on the Network tab), Save and restart (Duplicate data card, and the leave-page dialog), and Reset and restart (see Resetting settings below). The same happens with POST /api/restart and POST /api/settings/restart.
The daemon answers the request first ({"ok":true,"restarting":true} or {"status":"restarting"}), then, 500 ms (/api/restart) or 300 ms (/api/settings/restart) later, logs restart requested via API: stopping cleanly, then exiting for the supervisor (or restart requested from settings: …) and goes through the clean stop above: drain, departures, flush, tunnels down. It then logs restart: exiting with code 75 for the supervisor and exits with code 75 (EX_TEMPFAIL), not 0, so that a supervisor that restarts on failure brings it back.
flowchart TD
A["Restart control in the UI,<br/>or POST /api/restart or /api/settings/restart"] --> B["clean stop: drain, departures,<br/>resume flush, tunnels down"]
B --> C{"What started hydranos?"}
C -->|"Windows, any launch"| W["starts its successor with the same arguments,<br/>then exits with code 75"]
W --> UP["Hydranos runs again"]
C -->|"Linux or Docker"| E["exit code 75"]
E --> D{"Supervisor policy"}
D -->|"Docker restart: unless-stopped, always or on-failure"| UP
D -->|"systemd Restart=on-failure - the shipped unit - or always"| UP
D -->|"Docker without a restart policy, or started by hand in a shell"| DOWN["stays stopped"]
-
Windows: nothing supervises the process, so before exiting it starts its successor itself (
restart: successor started; on failureERROR restart: cannot start the successor: …, and nothing comes back: start it yourself). - Windows under a service wrapper (NSSM): the successor starts outside the wrapper, and the wrapper sees code 75 and may start another one: two instances, one of which fails to bind the port, the other unsupervised. Deduced from the code, not tested. Under a service, restart through the service, not with the UI's buttons.
- After Apply & restart the page reloads 7 s later (Restart now says to reconnect in about 40 s); during a long flush it may show a connection error until Hydranos is back: reload it then. Once the port is open again you get the startup screen below.
docker restart and systemctl restart send SIGTERM, so they go through the same clean stop (exit code 0, then the supervisor starts it).
Since 4.4 the port opens in the first second (INFO hydra API listening (starting) addr=…), before the catalogue loads: a port already taken fails at once. Until the engines are loaded and the store is open, only a startup surface answers:
-
/shows the startup screen: the logo, HYDRANOS, a phase line (Initializing…, then Restoring state…, Connecting to the network…, Opening the database…, Starting…), a bar and<restored> / <total> torrents. It polls/api/startupevery 500 ms and fades out when the daemon is ready. The total only counts engines that have started reading, so the bar can step back once per engine. -
/healthanswers 200 with"status": "starting",/metricsa reduced set,/api/startupthe progress. - Everything else (the API, login, the qBittorrent-compatible
/api/v2/*,/mcp) answers 503 withRetry-After: 5andHydranos is starting (<phase>): <restored> of <total> torrents restored.
The end of the start is INFO hydra API ready. If the store does not open, the phase becomes rescue and the page reloads into Rescue mode below. Details: Monitoring and Logs.
A crash, a power cut, kill -9, End task or a SIGKILL from a supervisor skips the flush. Each engine then starts from its last saved resume state:
| Lost | Not lost |
|---|---|
| Up to 300 s of piece progress, uploaded/downloaded counters and seed time per engine (the periodic resume save runs every 300 s) | Torrents added, completed or moved before the crash: their resume row is written at that moment |
| Pieces finished since the last save: the next start has to check them again | Store contents (categories, tags, stop intent, metainfo): committed as they happen |
With a power cut only: the last few seconds of commits of each SQLite file (synchronous=NORMAL) |
Jobs: those that were running are queued again at the next start |
| Bulk tasks from the context menu (they live in memory) | Magnets waiting for metadata: they resume |
Rechecks after a crash are normal and limited to the affected torrents. Details: Architecture.
Hydranos has no backup feature in 4.4 (no button, endpoint or scheduled copy; backups are the operator's job, as in other BitTorrent clients). You copy the files below yourself. The payload (the files in your save paths) is yours to back up separately; Hydranos does not copy it.
| File | Holds | Criticality | Can it be rebuilt? |
|---|---|---|---|
default.toml (the config file) |
engines, ports, tracker overrides, network mode, kill switch, api_key, admin password_hash, data_dir
|
high | by hand only |
<data dir>/hydra.db (+ hydra.db-wal, hydra.db-shm) |
the store: every .torrent, categories, tags, stop intent, workflows, RSS feeds and rules, nodes, jobs, lifetime counters of removed torrents |
critical |
no: it is the only copy of the metainfo, and Hydranos cannot rebuild it from the payload on disk (an install upgraded from 3.x may also keep .torrent copies in <data dir>/uploads/, re-imported at boot: back it up too) |
<config dir>/<engine id>/state.db (+ -wal, -shm), one per engine |
the engine's resume state: which torrents the engine holds, save paths, verified pieces, counters, edited tracker lists, seed time | critical | no: an engine loads its torrent list from it; without it the engine starts empty |
<config dir>/<engine id>/resume/ |
old per-torrent resume files, imported once into an empty state.db
|
low | not needed once state.db exists |
<data dir>/wireguard/ |
provider .conf files of Managed WireGuard (they hold the tunnel's private key) |
high if you use it | from your VPN provider |
<data dir>/bench.db |
Benchmark tab history | low | recreated empty |
hydranos.log (+ .1 to .4) |
the log, rotated at 128 MiB | none | — |
<config dir> is the folder holding default.toml; <data dir> is [daemon] data_dir. They are the same folder only in Docker.
| Platform | Config dir (config, engine folders, log) | Data dir (hydra.db, bench.db) |
|---|---|---|
| Docker |
/config (your host folder mounted there) |
/config |
Linux, packaging/install.sh or the steps on Linux (bare metal)
|
/etc/hydranos (so /etc/hydranos/race/state.db, /etc/hydranos/hoard/state.db) |
/var/lib/hydranos |
Linux, binary started with a --config file that did not exist yet |
the folder of that file | <that folder>/data |
Windows, started with --config C:\Hydranos\default.toml that did not exist yet |
C:\Hydranos |
C:\Hydranos\data |
Windows, default.toml placed there by you from the shipped template |
C:\Hydranos |
\config on the current drive (the template says data_dir = "/config") |
Windows, started without --config
|
the folder of hydranos.exe (a 4.3 install that only has \config\default.toml on the current drive keeps using it; its notice is printed before any console is attached, so it does not show in a console window) |
<that folder>\data |
Hydranos writes a starting config, with data_dir set to data beside it, only when the config file does not exist. When in doubt, read data_dir in your default.toml: it is authoritative.
The recommended recipe, on every platform. hydra.db and every state.db must be copied at the same moment and complete (with their -wal files): a stopped Hydranos guarantees both, and its clean stop has just written the latest resume state.
# Docker (compose project in /srv/hydranos, /config mounted from ./config)
cd /srv/hydranos
docker compose stop hydranos
tar czf /backup/hydranos-$(date +%F).tar.gz config
docker compose start hydranos# Linux, packaged layout
sudo systemctl stop hydranos
sudo tar czf /backup/hydranos-$(date +%F).tar.gz /etc/hydranos /var/lib/hydranos
sudo systemctl start hydranos-
Unraid or a NAS: stop the container in the Docker tab (or the NAS's container manager), copy the whole folder mounted as
/configwith any file tool or backup app, start the container. -
Windows: tray › Quit Hydranos, wait for the tray icon to disappear, then copy the config dir (and the data dir if it is elsewhere) with Explorer, or in
cmd:robocopy C:\Hydranos D:\Backup\Hydranos /E. Start Hydranos again. Notarorsqlite3needed.
On a network share (Unraid /mnt/user, NFS, SMB) the store keeps SQLite's rollback journal and has no -wal file; the recipe is the same.
Possible when you cannot stop Hydranos, with the sqlite3 tool on the host (it is not in the Docker image) and the files on a local disk (WAL mode). Each copy is consistent for its own file.
# Docker layout: hydra.db and the engine folders in ./config; run as the owner of the files
cd /srv/hydranos/config
mkdir -p /backup/hydranos-$(date +%F)
cp default.toml /backup/hydranos-$(date +%F)/
sqlite3 hydra.db ".backup '/backup/hydranos-$(date +%F)/hydra.db'"
for e in race hoard; do # every engine id
mkdir -p /backup/hydranos-$(date +%F)/$e
sqlite3 $e/state.db ".backup '/backup/hydranos-$(date +%F)/$e/state.db'"
doneWhat it does not give you, compared with a stopped copy:
- The store and the
state.dbfiles are taken at different moments. A torrent added or removed between two copies may be missing after a restore (see Restoring: skipped at load, or its store row dropped by the reconcile). Copy them back to back, at a quiet time. -
state.dbholds the resume state of the last periodic save (every 300 s): after a restore, recent pieces are checked again. - On a busy store,
.backupstarts over each time Hydranos writes during the copy;sqlite3 hydra.db "VACUUM INTO '/backup/…/hydra.db'"reads one snapshot instead. - On a network share (rollback journal) or on Windows, use the stopped copy.
-
<config file>.bak-reset-<unix time>: the previous config, written by Reset to defaults (see below). -
hydra.db.bak-preconvert-<unix time>: the store before a rescue-mode conversion (see Rescue mode).
They are not deleted automatically.
The store and the engines' resume state must come from the same backup. At start, each engine loads the torrents listed in its state.db and takes their .torrent from the store; then, right after store open and every 5 minutes, a store reconcile compares, engine by engine, the store's rows with the torrents the engine loaded:
-
older store, newer
state.db: a torrent the store has no row for is skipped at load (WARN[resume] skip …: no metainfo in the store) unless<data dir>/uploads/<hash>.torrentexists (installs carried over from 3.x): it is then imported into the store first. Add skipped ones again. -
newer store, older
state.db: the store has rows for torrents the engine did not load. The reconcile treats them as leftovers of a removal and deletes them,.torrentincluded, when their number is at mostmax(rows of that engine in the store ÷ 100, 50); one line at INFO:store reconcile: rows without a torrent removed engine=… dropped=N. Above that ceiling it deletes nothing and logs at WARNstore reconcile: refusing to drop that many rows at once(would_drop,of), and refuses again every 5 minutes. An engine that loaded no torrent at all (missingstate.db) is skipped, so its rows are kept.
At 1 million rows that ceiling is 10,000 torrents, and those .torrents exist nowhere else. The reconcile deletes only that engine's row: a copy of the same torrent held by another engine keeps its own. Rows of records the loader refused (their .torrent on disk is a different torrent) are kept too (store reconcile: rows kept for records the loader refused).
Procedure:
-
Stop Hydranos and keep it stopped.
-
Put
default.tomlback at the path you start Hydranos with. If the new machine uses other paths, fixdata_dirin it. -
Put
hydra.dbback in the data dir. Delete anyhydra.db-walandhydra.db-shmalready there unless they come from the same backup: a stale-walnext to another copy of the file corrupts it. -
Put each engine folder back as
<config dir>/<engine id>/with itsstate.db(same rule forstate.db-wal/-shm), from the same backup ashydra.db. The folder name must equal the engine id in the config (race,hoard, or the id of an extra engine): an engine whose folder is missing or renamed starts empty. -
Make the save paths exist at the same paths as before (same mounts in Docker).
-
Fix ownership: Docker
PUID/PGIDuser, orhydranos:hydranoson the packaged Linux layout. -
Keep a copy of the restored
hydra.dbaside, outside the data dir. If the reconcile deletes rows anyway, their.torrentis still in that copy. -
Optional, if you have the
sqlite3CLI on the host: count, per engine, store rows that have nostate.dbrow (a lower bound of what the reconcile may delete). Any result other than 0 means the files do not match; 0 does not rule out rows dropped because their.torrentfails to parse.cd /srv/hydranos/config # the folder holding hydra.db and the engine folders for e in race hoard; do sqlite3 hydra.db "ATTACH '$e/state.db' AS s; SELECT '$e', count(*) FROM torrents WHERE session = '$e' AND info_hash NOT IN (SELECT lower(info_hash) FROM s.torrent_state);" done
-
Start, and check the log: one
engine state loadedline per engine withtorrents=…(compare with the counts you had before), no[resume] skiplines,engines up,store open,hydra API ready, and nostore reconcile: rows without a torrent removedline.
bench.db can be restored or left out (the Benchmark tab then starts empty).
If hydra.db cannot be opened, or its torrents table lacks columns, Hydranos logs the store could not be opened: <why> -- starting in rescue mode at ERROR and serves a minimal surface on the listener already open, so on your api_host and api_port (default 0.0.0.0:8199). The web UI is not served: http://<host>:8199/ answers the text hydra: the store could not be opened (a startup screen still open in a browser reloads into it). The engines were started before the store was opened and keep running (Architecture).
Rescue mode asks for no API key: anyone who reaches the port can run the conversion and the restart. Keep the port reachable only from trusted hosts, as for the normal UI.
| Route (no API key needed) | Does |
|---|---|
GET /health |
answers ok
|
GET /api/store/repair (same as GET /api/setup) |
diagnosis: needed, targets (path), on_network, in_wal, hot_wal
|
POST /api/store/repair |
the conversion below, only when needed is true |
POST /api/settings/restart |
exit with code 75 after 300 ms (Windows: starts its successor first); no resume flush |
The web UI contains a Hydranos cannot open its database screen with a Back up and convert button, but in 4.4 it never appears: rescue mode does not serve the UI, and the normal API always reports no repair needed. Use the routes directly:
curl http://127.0.0.1:8199/api/store/repair
curl -X POST http://127.0.0.1:8199/api/store/repairThe only repair is for a store in WAL mode on a network filesystem (needed = on_network and in_wal). On Linux "network" means NFS, SMB/CIFS or FUSE (mergerfs, Unraid /mnt/user); on Windows a UNC path or a mapped network drive. It typically happens when a store created on a local disk is moved to a share.
flowchart TD
A["POST /api/store/repair<br/>(rescue mode only)"] --> B{"on a network filesystem and in WAL?"}
B -->|no| S["returns the diagnosis, changes nothing"]
B -->|yes| C["copy hydra.db to hydra.db.bak-preconvert-unix time"]
C -->|"copy failed"| E5["500, nothing changed"]
C -->|"copy done"| D["PRAGMA journal_mode=DELETE"]
D -->|ok| OK["200, method pragma"]
D -->|"failed, WAL file empty"| H["rewrite header bytes 18-19,<br/>delete -wal and -shm"]
H -->|ok| OK2["200, method header"]
H -->|"write failed"| E6["500, backup kept"]
D -->|"failed, WAL file holds data"| E4["409, store left untouched"]
After a successful conversion, restart: curl -X POST http://127.0.0.1:8199/api/settings/restart exits with code 75, which brings Hydranos back under Docker with a restart policy, under the shipped systemd unit (Restart=on-failure), and on Windows (successor); or restart through your supervisor (docker restart hydranos, sudo systemctl restart hydranos). On a 409, the -wal still holds commits: move the files back to a local disk, start Hydranos there once and stop it cleanly, then move them again; or better, keep data_dir on a local disk.
For any other cause (permissions, disk full, damaged file), POST /api/store/repair does nothing: fix the reason given in the log, or restore from a backup (Restoring).
In rescue mode a SIGTERM (or Ctrl+C) still stops the HTTP server gracefully and the process exits with code 0, but without departures or resume flush: the engines' state is the last periodic save. Deduced from the code, not tested.
Read the release notes first in the changelog. The Changelog tab (and /changelog.md) shows the changelog compiled into the version you are running, so it does not list the new release. Take a backup (stopped copy) before every update: it is also your way back.
Pin a version tag and change it to update:
cd /srv/hydranos
# edit your compose file: image: ghcr.io/kheopsian/hydranos:v4.4.0 → the new tag
docker compose pull
docker compose up -dup -d stops the old container with your stop_grace_period (clean stop), then starts the new image on the same /config. Nothing in the container updates itself. Unraid: change the tag in the Repository field and Apply. Details: Docker.
hydranos-update downloads the release archive for your architecture from github.com/Kheopsian/Hydranos releases, checks its SHA-256 against the .sha256 published beside it, and replaces the binaries.
sudo /opt/hydranos/hydranos-update --dir /opt/hydranos --config /etc/hydranos/default.toml --check
sudo /opt/hydranos/hydranos-update --dir /opt/hydranos --config /etc/hydranos/default.toml # download, verify, ask, replace
sudo systemctl restart hydranos| Option | Effect |
|---|---|
--check |
prints installed: and available: and exits |
--dir <path> |
folder holding hydranos (default: the current folder) |
--config <file> |
the daemon's config (default: default.toml in --dir); the updater's downloads then leave the way the daemon's do ([daemon] egress, kill switch). A file that does not parse is a refusal; no file means the default route |
--tag vX.Y.Z |
a given release instead of the latest; older releases allowed (downgrade) |
--yes, -y
|
no confirmation (replace the binaries with <tag>? [y/N]) |
- Nothing is replaced when the download fails, the
.sha256is missing (refusing to install unverified bytes) or the checksum differs (checksum mismatch -- nothing replaced). - It replaces only
hydranosandhydranos-updatealready in--dir(the archive has nohydranos-engine; an old one left in the folder is not touched); config, store, engine folders and log are never touched. - On Linux it does not restart anything (
note: restart the service for the new binaries to take effect). -
packaging/install.shinstallshydranos-updatebesidehydranosin/opt/hydranos(Linux (bare metal)).
Without the updater: download and verify the new tarball, unpack it, run sudo ./install.sh again (it keeps the config), then restart.
Tray › Check for updates opens a cmd window running hydranos-update.exe --dir <folder of hydranos.exe>; same options and checks as above. After you answer y, the updater asks the running Hydranos to stop through a named event (Local\HydranosStop), the same clean stop as Quit Hydranos, waits up to 60 s for hydranos.exe to exit, replaces the files and prints updated to <tag>. Start hydranos again. If the stop takes longer than 60 s (a flush close to HYDRANOS_STOP_TIMEOUT), it prints hydranos is still running after 60s -- stop it yourself, nothing was replaced: wait for the tray icon to disappear and run it again. A daemon older than 4.4 has no such event: quit it from the tray first. The step-by-step is on Windows.
When a newer version exists, an update vX.Y.Z link appears next to the version in the header. The server reads the first 100 tags of github.com/Kheopsian/Hydranos (not the releases) and keeps a successful answer for 6 hours. A failure (no network, rate limit, 5 s timeout) means "no update" and is not kept, so the server asks GitHub again on the next request. Turn it off with update_check_disabled = true in [daemon].
The badge only informs: nothing is downloaded or applied by the daemon. Coming from 3.x, read Upgrading from 3.x first.
Config tab › Advanced settings (default.toml) › toolbar button Reset to defaults › Reset and restart:
- The current config is copied to
<config file>.bak-reset-<unix time>next to it (e.g./config/default.toml.bak-reset-1759600000). -
default.tomlis replaced by the shipped template, keeping only your admin login (username,password_hash),api_keyanddata_dir(non-empty strings only). - Hydranos restarts through the clean stop of Restart from the UI (exit code 75).
Everything else goes back to defaults: ports (16171 race, 16172 hoard), tracker overrides, engine tuning, queue, share and speed limits, the network mode, kill switch, proxy and managed WireGuard settings (the provider files in <data dir>/wireguard/ stay), and extra engines (their folders stay on disk, but they are no longer started). The store (categories, workflows, RSS feeds and rules) and the resume state are not touched. To undo: stop Hydranos, copy the .bak-reset-… file over default.toml, start.
The Personalisation card on the same tab has a button with the same label, Reset to defaults: it only resets the theme and the hidden tabs in this browser and touches nothing on the server.
Signed in, change it under Config › Account › Change password (8 characters minimum; applies at once). Locked out, set a new one on the host with hydranos reset-password <password> [path/to/default.toml], then restart:
# Docker (config at /config/default.toml inside the container; pass the path if you changed HYDRANOS_CONFIG_DIR)
docker exec hydranos hydranos reset-password 'new-password-here'
docker restart hydranos
# Linux, packaged layout
sudo /opt/hydranos/hydranos reset-password 'new-password-here' /etc/hydranos/default.toml
sudo systemctl restart hydranosOn Windows: hydranos.exe reset-password "new-password-here" in cmd in the folder of hydranos.exe (the default config is the one beside it), then Quit Hydranos and start it (not tested on Windows).
- It writes a bcrypt
[auth] password_hashinto the file, checks that the file still parses, printshydranos: password set in <path>. Restart Hydranos for it to apply.and exits. The running daemon keeps the old hash until the restart;usernameandapi_keydo not change. - Without a path it uses
/config/default.toml(Windows:default.tomlbesidehydranos.exe, or the\config\default.tomla 4.3 install left when there is none there). Refusals: fewer than 8 characters (hydranos: the password must be at least 8 characters, exit 2), a file it cannot read or write, or an edit that would not parse (… would not parse after the edit; nothing written). - The password is a command-line argument: it stays in your shell history and shows in
pswhile the command runs.
hydranos hash-password <password> only prints a bcrypt hash, for editing password_hash by hand. More on accounts and keys: Security and Access.
-
Monitoring and Logs:
/health,/metrics, the log file and the Logs tab. - Troubleshooting: symptoms and fixes.
- Docker, Linux (bare metal), Windows: platform specifics.
- Architecture: startup order, files on disk, crash safety.
- Upgrading from 3.x.