Configuration Engines - Kheopsian/Hydranos GitHub Wiki
Applies to Hydranos 4.4.
This page lists every key of [race], [hoard], the engine blocks (TOML array of tables) and [race_drain] in default.toml. For each key you get its type, the value in the shipped template, the value Hydranos uses when the key is missing, what it really does in 4.4, and when a change takes effect. It is a reference page. To learn what engines are and why you would add one, read Engines: Race and Hoard first.
How the file is found, edited and reloaded is covered in Configuration Reference. Settings that are not engine settings are covered in Configuration: Daemon, Auth and Global Sections.
-
raceandhoardalways run. They take their settings from[race]and[hoard]. If a section is missing, its engine still starts, with every key at its "missing" value (see the tables below). - Each
engineblock adds one more engine. Its settings are the[race]or[hoard]section of its role, plus the keys in its own[engine.session]table laid over them. - Engine settings are read once, when the engines start, except the keys marked live in the tables. A live key changed from the web UI or the API (
POST /api/settings, the per-engine routes) applies to the running engines without a restart: the speed caps,peer_timeout, the choker, the queue, the slow-torrent rule and the share limits. The listen port and the dial limits have their own live routes. A hand edit of the file is read at the next start, or as soon as any UI or API change rewrites the file (that reloads the whole file). - If a key under
[race]or[hoard]has the wrong type (for examplelisten_port = "16171"), the file does not parse and Hydranos stops at boot. The web editor refuses an edit that is not valid TOML, but not a wrong type (max_connections = 4000.5): such an edit is saved, and Hydranos then refuses to start. The same mistake inside an[engine.session]table only discards that override (see below). - A key Hydranos does not know is accepted and ignored, and a misspelt key just does nothing. The keys that are known to be dead (3.x leftovers, see Keys that do nothing in 4.4) are named at startup, one warning per key:
config: race.listen_interfaces is ignored: <why>. Instead: <what to use>.
How the list of engines is built from the file at startup:
flowchart TD
T["default.toml"] --> R["[race] section"]
T --> H["[hoard] section"]
T --> B["Each legacy agent block,<br/>then each engine block"]
R --> ER["Engine race, role race, always"]
H --> EH["Engine hoard, role hoard, always"]
B --> A{"addr set, or role empty?"}
A -- yes --> SK["Skipped: not a local engine"]
A -- no --> RO{"role is race or hoard?"}
RO -- no --> W["Warning unknown role,<br/>no engine"]
RO -- yes --> ID{"engine_id, else name,<br/>not empty?"}
ID -- no --> W2["Warning, skipped"]
ID -- yes --> M["That role's section,<br/>the session table laid over it"]
M --> V{"Merged settings valid?"}
V -- no --> P["Warning override refused,<br/>role's section used as is"]
V -- yes --> SAME{"Id already in the list?"}
P --> SAME
SAME -- yes --> REP["Replaces that engine,<br/>race and hoard included"]
SAME -- no --> ADD["One more engine"]
ER --> L["Engine list"]
EH --> L
REP --> L
ADD --> L
L --> WG["WireGuard mode: each tunnelled engine<br/>pinned to its tunnel device"]
WG --> PC{"For each engine in order:<br/>listen_port 0?"}
PC -- yes --> DEF["16171 for race role,<br/>16172 for hoard role, warning"]
PC -- no --> WR["Port as written"]
DEF --> TK{"Taken by an earlier engine?"}
WR --> TK
TK -- no --> KEEP["Port kept"]
TK -- yes --> FREE["+1 until a free port, warning"]
The port picked in the last step is not written to the file. The warning reads listen_port missing or taken: using a free one.
In 4.4 every key in the tables below is read. They fall in five groups: peers and network, queue/share/speed, announces and start, the keys the Network tab writes (proxy, relay, gluetun), and the managed WireGuard keys. Only two keys you may still meet in these sections are read by nothing and named nowhere: inactivity_timeout and announce_rate_limit. The 3.x leftovers are read by nothing either, but Hydranos names each of them in a startup warning. Both lists are in Keys that do nothing in 4.4 below.
Template = value in the shipped configs/default.toml (race / hoard). Missing = what Hydranos uses when the key is absent. Live? = whether a change applies without restart (see How engine settings are read).
| Key | Type | Template (race / hoard) | Missing | Effect | Live? |
|---|---|---|---|---|---|
listen_port |
integer 1–65535 |
16171 / 16172
|
16171 (race role) / 16172 (hoard role); the next free port if an earlier engine has it |
TCP peer listener and uTP socket (same number), the port announced to trackers, and the port that automatic port forwarding maps | live with POST /api/engines/:id/listen-port (saved to the file, see Networking); else restart |
bind_interface |
string |
"" / ""
|
"" (default route) |
Linux only. Pins every socket of the engine to that interface (SO_BINDTODEVICE): listener, uTP, peer dials, HTTP and UDP announces, DHT, LSD, webseeds. It never falls back to the default route: if the interface is missing at start, the engine has no listener and no uTP until a restart finds it. On Windows and macOS a non-empty value keeps the engine off the network (no listener, dial or announce), and the Network tab and POST /api/engines refuse it (400). Details: VPN and Egress
|
restart |
enable_ipv6 |
boolean |
false / false
|
false |
Adds an IPv6 listener on the same port and accepts IPv6 peers. false: every announce of the engine goes over IPv4 only |
restart |
enable_dht |
boolean |
true / true
|
true |
DHT (BEP 5) for this engine, through its interface. Private torrents are never put in the DHT. Off behind a SOCKS5 proxy whatever this says | restart |
enable_pex |
boolean |
true / true
|
true |
Peer exchange (BEP 11) for this engine | restart |
enable_lsd |
boolean |
true / false
|
on for the race role, off for any other | Local Service Discovery (BEP 14): multicast on the LAN, or on the engine's interface. Never for a private torrent; off behind a SOCKS5 proxy. See Networking | restart |
enable_webseed |
boolean | not in template | true |
Webseed (BEP 19, url-list) downloads, through the engine's interface or proxy like its announces. false: the URLs are parsed and never fetched |
restart |
enable_udp_trackers |
boolean | not in template | true |
false: this engine skips udp:// trackers and announces over HTTP only. UDP trackers are skipped anyway while a proxy is in use |
restart |
max_connections |
integer |
4000 / 12000
|
0 (no cap) |
Ceiling on this engine's live peer connections. At the ceiling it stops dialing; incoming peers are still accepted (and count). Each engine has its own ceiling. A negative value counts as 0 | live with POST /api/engines/:id/dial-limits (saved); else restart |
max_dials_per_sec |
number | not in template |
0 (no limit) |
New outbound peer dials per second for this engine. Written by the dial-limits route, and read from the file since 4.4 | live with the dial-limits route (saved); else restart |
aio_threads |
integer ≥ 0 | not in template | 256 |
Size of the engine's pool of open files (minimum 100). Despite the name, not a thread count | restart |
peer_timeout |
integer (seconds) |
300 / 300
|
0 = 300 |
Seconds a peer may send nothing useful before it is dropped. Under 120 is raised to 120 | live |
How these work, with examples and the per-torrent overrides: Queue, Share and Speed Limits. Every key here is live: the queue runs every 30 seconds and the share-limit worker every 2 minutes, and each pass reads the current values.
| Key | Type | Template (race / hoard) | Missing | Effect |
|---|---|---|---|---|
active_downloads |
integer | not set / 10
|
0 (no ceiling) |
Downloads running at once. 0 or negative = no ceiling. Applies with or without queueing
|
queueing |
boolean |
false / false
|
false |
Turns on active_seeds and active_limit
|
active_seeds |
integer |
-1 / -1
|
no ceiling | Seeds running at once, only with queueing = true. 0 or negative = no ceiling |
active_limit |
integer |
-1 / -1
|
no ceiling | Downloads + seeds running at once, only with queueing = true. 0 or negative = no ceiling |
dont_count_slow_torrents |
boolean | not in template | false |
A running torrent under its threshold for slow_torrent_inactive_timer keeps running but frees its slot in the three limits above |
slow_torrent_dl_rate_threshold |
integer (KiB/s) | not in template | 2 |
Under this, a download is slow |
slow_torrent_ul_rate_threshold |
integer (KiB/s) | not in template | 2 |
Under this, a seed is slow |
slow_torrent_inactive_timer |
integer (seconds) | not in template | 60 |
How long a torrent must stay under its threshold |
max_ratio |
number |
-1.0 / -1.0
|
off | A seed reaching this ratio gets share_limit_action. Negative = off |
max_seeding_time |
integer (minutes) |
-1 / -1
|
off | The same, after this much seeding time |
max_inactive_seeding_time |
integer (minutes) |
-1 / -1
|
off | The same, after this long seeding with nothing uploaded |
share_limit_action |
string |
"stop" / "stop"
|
"stop" |
stop, remove or remove_with_files. Any other value in the file acts as stop. Never applied while the torrent's tracker still has a Minimum seed to serve, or declares none |
upload_rate_limit |
integer (bytes/s) |
0 / 0
|
0 |
Engine-wide upload cap. 0 or negative = unlimited |
download_rate_limit |
integer (bytes/s) |
0 / 0
|
0 |
Engine-wide download cap. 0 or negative = unlimited |
choking |
boolean |
false / false
|
false |
Runs the choker: each seeding torrent serves only max_uploads_per_torrent peers at a time. Best left off |
max_uploads_per_torrent |
integer |
100 / -1
|
0 = 4 slots |
Unchoke slots per seeding torrent, read only with choking = true. Negative = unlimited |
| Key | Type | Template (race / hoard) | Missing | Effect | Live? |
|---|---|---|---|---|---|
registration_retry_minutes |
integer (minutes) |
6 / not in template |
6 |
Race-role engine only: while a tracker answers with a failure reason and no tracker has accepted the torrent yet, re-announce every 5 s for this long, then follow the tracker's interval. 0 = the default. At most 255 refusals are counted, so about 21 minutes is the effective ceiling. See Trackers and Announces
|
restart |
start_paused |
boolean | not in template | false |
The engine starts with its dials and announces held until you release it (Start now on the banner, or POST /api/startup-pause/release). See Queue, Share and Speed Limits
|
restart |
announce_ip |
string (an IP) | commented out |
"" (not sent) |
The address trackers are asked to list: BEP 7 ip= over HTTP, the ip field over UDP (IPv4 only). Empty: the tracker uses the address the announce came from |
restart |
announce_proxy |
string (proxy URL) | commented out | "" |
Proxy for this engine's announces, webseeds and magnet downloads, instead of the SOCKS5 peer proxy (socks5h://user:pass@host:port). Empty: the SOCKS5 peer proxy if set, else the environment variable TYPHON_ANNOUNCE_PROXY if set, else direct. UDP trackers are not announced while a proxy is in use |
restart |
Config › Advanced settings (default.toml) › Network › Save this mode writes [network] mode, the keys of the chosen mode into [race], [hoard] and the extra engines' blocks, and removes the keys of the other modes. The modes and their fields: Networking. All these keys are read when the engine starts (restart).
| Key | Type | Template | Missing | Effect |
|---|---|---|---|---|
socks5_outbound_host, socks5_outbound_port, socks5_outbound_user, socks5_outbound_pass
|
string / integer / string / string | commented out |
"" / 1080 / "" / ""
|
Every outbound peer dial of the engine goes through this SOCKS5 proxy, IPv4 and IPv6. A dial the proxy refuses is dropped, never retried directly. Outbound uTP, DHT and LSD are off, and UDP trackers are not announced. Announces, webseeds and magnets also go through it (socks5h://) unless announce_proxy is set. A port of 0 means 1080 |
listen_port_proxy_v2 |
integer | commented out |
0 (no listener) |
A second listener for peers your relay forwards with a PROXY-v2 header carrying their real address |
listen_addr_proxy_v2 |
string | commented out |
"" (every address) |
Bind address of that listener |
proxy_v2_trusted_sources |
array of strings | commented out | [] |
Relay addresses allowed to send the header. Loopback and private addresses are always trusted; a public relay must be listed |
gluetun_port_forward |
boolean | not in template | false |
This engine takes gluetun's forwarded port, listens on it and follows it live. Its announces wait until it holds that port |
gluetun_url, gluetun_api_key
|
string | not in template |
"" (http://127.0.0.1:8000) / ""
|
gluetun's control server and the key sent as X-API-Key
|
allow_direct |
boolean | commented out | false |
This engine leaves by the host's default route on purpose. With the kill switch armed (every mode but Direct), an engine with no tunnel, no interface and no proxy is kept off the network unless this is true
|
The kill switch itself ([daemon] kill_switch) and the daemon's own route ([daemon] egress, [proxy]) are not engine keys: see Configuration: Daemon, Auth and Global Sections and VPN and Egress.
The Session Race and Session Hoard sub-tabs hide the keys the Network tab owns (listen_port, bind_interface, enable_ipv6, the SOCKS5, PROXY-v2 and announce keys, allow_direct): change those on the Network tab. The gluetun_* and wireguard_* keys still show there when the file has them.
In [network] mode = "wireguard", the Network tab writes per engine wireguard_enabled, wireguard_config (a file name in <data_dir>/wireguard, never the key itself), wireguard_provider, wireguard_port and wireguard_port_forward, or allow_direct = true for an engine left on the default route. None of them is in the template. What each means and what is written: Managed WireGuard.
[network] mode is direct, wireguard, gluetun, socks5 or proxy_v2. Missing (a file from before 4.4) or unknown, the mode is deduced from the keys above, and never as wireguard.
| Key | Template (race / hoard) | What happens | Use instead |
|---|---|---|---|
inactivity_timeout |
20 / 20
|
Nothing, and no startup warning. The Advanced settings editor describes it as "Seconds before an idle peer is considered inactive." | peer_timeout |
announce_rate_limit |
not in template | Nothing, and no startup warning. The editor still has a description for it ("Cap on outbound tracker announces…") when a file holds it |
max_dials_per_sec (dial pacing, not announce pacing) |
listen_interfaces |
not in template | Nothing. Named at startup | bind_interface |
file_pool_size |
not in template | Nothing. Named at startup | aio_threads |
[race.custom_choking], [hoard.custom_choking]
|
not in template | Nothing. Named at startup (see below) |
choking, max_uploads_per_torrent
|
[hoard.disk_slots] |
not in template | Nothing. Named at startup (see below) | — |
Accepted but ignored in 4.4:
inactivity_timeoutandannounce_rate_limitlook like peer and announce settings and are read by nothing — no startup warning names them — usepeer_timeoutfor idle peers; announces cannot be rate limited.
The four keys named at startup are hidden from the Advanced settings editor. inactivity_timeout is shown, with the hint default: 20 for race and default: 90 for hoard.
Since 4.4 most Missing values match the template: DHT, PEX and webseeds are on, LSD follows the role, and every engine gets a real listen port. Two differences remain. A [race] or [hoard] section you write yourself, a section you trimmed, or the config written by the node enrolment script (install.sh, which writes only listen_port 16371/16372 and enable_ipv6 = true) has:
-
no cap on peer connections (
max_connectionsmissing = 0), where the template has 4000 / 12000; - for hoard, no download ceiling (
active_downloadsmissing = 0), where the template has 10.
An engine without listen_port gets its role's default (16171 race, 16172 hoard); if that port, or the one it wrote, is already taken by an earlier engine, it gets the next free port above it. Either way, with a warning. That port is not saved, so it can change when engines are added: write listen_port for every engine.
The Advanced settings (default.toml) editor changes keys that already exist in the file. The exceptions are the live keys of the queue, share-limit, speed and choker tables and enable_lsd: the editor lists them for [race] and [hoard] at their default even when the file lacks them, and saving one creates it — except active_downloads, max_uploads_per_torrent and peer_timeout, which the editor lists only when the file has them (Known bug in 4.4: the server would create them; race's template has no active_downloads: add it by hand). Every other key missing from the template (enable_webseed, enable_udp_trackers, aio_threads, start_paused) must be added with a text editor; max_dials_per_sec also through POST /api/engines/:id/dial-limits. A section with the keys written out:
[race]
listen_port = 16171
bind_interface = ""
enable_ipv6 = false
enable_dht = true
enable_pex = true
enable_lsd = true
enable_webseed = true
enable_udp_trackers = true
max_connections = 4000
aio_threads = 256
peer_timeout = 300
registration_retry_minutes = 6
# active_downloads not set: no download ceiling for race
[hoard]
listen_port = 16172
bind_interface = ""
enable_ipv6 = false
enable_dht = true
enable_pex = true
enable_lsd = false
enable_webseed = true
enable_udp_trackers = true
max_connections = 12000
aio_threads = 256
peer_timeout = 300
active_downloads = 10The queue, share-limit, speed and choker keys are in the shipped template as shown in the tables above.
An extra engine is declared with an engine block (TOML array of tables) and an optional [engine.session] sub-table. Nodes › This node › + Add an engine writes exactly this block for you. Afterwards, the Network tab and the per-engine routes change some keys (see Changing an extra engine later); any other key is edited by hand.
| Key | Type | Missing | Effect | Status |
|---|---|---|---|---|
engine_id |
string | "" |
The engine id: used in /api/engines/:id, ?engine=, and as the folder name <config dir>/<id>/ that holds its resume state. Letters, digits, - and _ (the UI enforces this; keep to it by hand too, since the id becomes a folder name) |
Works |
name |
string | "" |
Used as the id when engine_id is empty. Neither set: the block is skipped with a warning |
Works |
role |
"race" or "hoard"
|
"" |
Which section the engine inherits ([race] or [hoard]) and how it behaves (announce mode; a race-role engine also gets the race drain and the race add-block). Missing: block skipped. Any other value: block skipped with a warning |
Works |
addr |
string | "" |
Must stay empty. A non-empty addr means a 3.x remote agent: the block is skipped entirely, starts nothing here, and is named in a startup warning. Other machines join as nodes on the Nodes tab (Nodes and Multiple Machines) |
Works (as a skip) |
token, tls_ca
|
string | "" |
Nothing. Named in a startup warning | Ignored (3.x leftovers) |
[engine.session] |
table | empty | Sparse override: any key of the [race]/[hoard] tables above, laid over the role's section. Every key of the tables above works there, the Network-tab and WireGuard keys included |
Works |
Rules worth knowing:
-
Additive.
raceandhoardalways exist; each valid block adds one engine. Adding a block never disables[race]or[hoard]. -
Same id replaces. A block whose id is already taken replaces that engine. That includes
raceandhoard: a block withengine_id = "race"redefines the race engine (role and settings included). Give extra engines their own ids. -
The override is all or nothing. If one key of
[engine.session]has the wrong type (for examplelisten_port = "16473"), the whole override is dropped with the warningagent session override refused, using the role profile, and the engine runs with its role's section unchanged: its role's settings and interface, and the next free port after its role's (warninglisten_port missing or taken: using a free one). -
Unknown keys in the override are dropped without a word (a misspelt key, for example). The dead keys of Keys that do nothing in 4.4 are named at startup there too, with the block's name and
session.<key>. -
What an extra engine inherits. Everything in its role's section, including the SOCKS5 proxy and
announce_proxy, except four keys that it gets only by writing them in its own session:listen_port_proxy_v2(one relay port per host),gluetun_port_forward(one forwarded port),wireguard_enabled(a tunnel per engine) andallow_direct(an engine added later is unassigned, and the armed kill switch blocks it until you choose). -
Always set
listen_portin the override, unique across engines. At boot, an engine whose port is missing or already taken by an earlier engine is moved to the next free port (with a warning, not saved), so it listens, but not on a port you published or forwarded. + Add an engine refuses a port that a running engine already uses (409); the Network tab does not compare extra engines' ports with race and hoard. -
Where the block goes in the file. A TOML block owns every line below it until the next
[header]. Append engine blocks at the end of the file (the UI does this), or you will move the keys that follow into the block. The sub-table must use the block's name:[engine.session]under anengineblock. Mixing spellings can make the file unparsable, and Hydranos then refuses to start. -
Legacy
agentblocks (the 3.x spelling, same fields) are still read, beforeengineblocks. When both declare the same id, theengineblock wins. New blocks are always written asengine. History: Upgrading from 3.x. - An
enginesub-array inside a block (the 3.x per-agent engine override, with anidkey) matches no field and does nothing; Hydranos names it at startup. Put the overridden keys in the block'ssessionsub-table.
# At the END of default.toml
[[engine]]
name = "vpn1"
role = "hoard"
engine_id = "vpn1"
[engine.session]
listen_port = 16473
bind_interface = "wg1"This is what + Add an engine writes for Id vpn1, Role hoard, Listen port 16473, Interface wg1. The engine inherits everything else from [hoard] (DHT, PEX, max_connections, active_downloads = 10, …). Then:
- Restart Hydranos (adding or removing an engine always needs a restart; the UI shows Restart now).
- With Docker, publish the port yourself:
16473:16473/tcpand16473:16473/udp. The shipped compose publishes only 16171 and 16172. - Check Nodes › This node: the row should say listening. not listening usually means
wg1was not up when the engine started. + Add an engine refuses an interface that is not up (400no interface named wg1 is up), and refuses any interface outside Linux (400).
bind_interface pins every socket of this engine to wg1: listener, uTP, its own outgoing peer connections, announces, DHT, LSD and webseeds. If wg1 is missing it falls back to nothing (no listener, no uTP), never to the default route. An extra engine with no interface, no tunnel and no proxy inherited from its role is kept off the network while the kill switch is armed (every mode but Direct), until you give it a way out or allow_direct = true. Read VPN and Egress for what stays outside the pin.
Any key can be overridden per engine. Here a second hoard engine stays off DHT and PEX, skips UDP trackers, caps its upload and stops its seeds at ratio 2, while [hoard] keeps its own values:
[[engine]]
name = "quiet"
role = "hoard"
engine_id = "quiet"
[engine.session]
listen_port = 16474
enable_dht = false
enable_pex = false
enable_udp_trackers = false
active_downloads = 2
upload_rate_limit = 1048576 # bytes/s = 1 MiB/s
max_ratio = 2.0-
Listen port and interface: the Network tab shows {id} listen port and {id} engine interface ({role}) for each extra engine. Save this mode writes them into the block's
[engine.session](creating it if needed). Restart. -
Share limits, speed caps, dial limits, listen port: the per-engine routes write into the block's
[engine.session]:POST /api/engines/:id/share-limits,/rate-limits,/dial-limits,/listen-port(live, no restart). - Any other key: edit the block by hand. The Advanced settings (default.toml) editor cannot change engine blocks: they are not shown there at all.
-
Removing: Remove on the engine's row deletes the block (not offered for
raceandhoard). An engine that still holds torrents is refused (409<id> still holds <n> torrent(s): move them to another engine or remove them first). An empty engine keeps its listener until you restart. Its<config dir>/<id>/folder stays on disk (see Engines: Race and Hoard).
API equivalents: POST /api/engines with {"id","role","listen_port","bind_interface"} and DELETE /api/engines/:id. Both answer restart_required: true (REST API).
Settings for the automatic freeing of race volumes. One drain runs per race-role engine, one pass per volume. What it deletes, what it graduates and how seed obligations protect torrents is explained in Race Drain and Graduation.
| Key | Type | Template | Missing | Effect | Live? | Status |
|---|---|---|---|---|---|---|
enabled |
boolean | true |
false |
Default drain policy for every volume. A volume's own policy (Race tab volume card, saved in the store hydra.db) overrides it |
next pass | Works |
high_watermark_pct |
integer | 95 |
0 |
A pass starts when the volume's allocation (space promised to torrents, not space used) reaches this % | next pass | Works |
low_watermark_pct |
integer | 85 |
0 |
A pass frees until allocation falls to this % | next pass | Works |
check_interval_seconds |
integer | 60 |
0 = 300 s |
Time between passes. The first pass runs 10 s after start plus one interval | restart | Works |
add_block_enabled |
boolean | not in template | false |
Refuses a new race torrent when the volume's projected free space (free − still to download on that volume − reserve) is smaller than the torrent | next add | Works |
reserve_free_gb |
integer | not in template | 0 |
Space the add-block keeps free, in GB (10⁹ bytes) | next add | Works |
Live? "next pass" / "next add" means: a change made from the web UI or the API applies without a restart, because those write paths update the running configuration. The Settings UI still says Daemon/auth settings changed, a full restart is required. for this section; for these keys you can ignore it. A change you make by hand in the file is read at the next start.
The per-volume Quota and TRIM after drain are not keys of this section: set them on the Race tab volume card or with POST /api/drain/policy (quota_gb, trim_after_drain); they are stored in hydra.db.
min_age_minutes is no longer in the template. It never did anything (a torrent is protected by its tracker's minimum seed time, not by its age); a value left in an older file is ignored, hidden from the editor and named at startup: config: race_drain.min_age_minutes is ignored: …. See Race Drain and Graduation.
Trap: without high_watermark_pct and low_watermark_pct, an enabled drain starts a pass at every interval and tries to free everything it is allowed to (only seed obligations hold it back). If you write [race_drain] yourself, set all four of the template's keys:
[race_drain]
enabled = true
check_interval_seconds = 60
high_watermark_pct = 95
low_watermark_pct = 85
# optional: refuse races that would not fit
add_block_enabled = true
reserve_free_gb = 50With [race_drain] missing entirely, the global drain default and the add-block are off; a volume with its own enabled policy (Race tab) is still drained.
The 3.x table (enabled, tick_interval_seconds, strategy, max_unchoked, rarity_weight, speed_weight) is no longer in the template. In a file that still has it, nothing reads it; it is hidden from the editor, and Hydranos logs at startup config: race.custom_choking is ignored: a 3.x choking strategy; the engine has one built-in choker and no strategy to pick. Instead: choking = true and max_uploads_per_torrent = <slots> (off by default; read their help first). Delete it. The built-in choker is described in Queue, Share and Speed Limits.
Older templates ended with a commented-out [hoard.disk_slots] example (a per-disk limit on active uploads for spinning drives, with disk sub-entries holding key, type, max_active, wake_below). It is no longer in the template, and Hydranos 4.4 has no such feature: a file that has the table is accepted, the table is hidden from the editor and named at startup (config: hoard.disk_slots is ignored: …).
Accepted but ignored in 4.4:
[hoard.disk_slots]describes per-disk seeding slots to keep hard drives quiet — no code reads it and every seeding torrent stays active — there is no equivalent; stop torrents yourself if a disk must rest.
- Configuration Reference: how the file works, restart tiers, and the full table of keys that do nothing.
- Engines: Race and Hoard: what the role changes, extra engines, peer protocols.
- Queue, Share and Speed Limits: the queue, slow torrents, share limits, speed caps, the choker and the startup pause.
- Networking: Ports, Port Forwarding and the Network Tab: ports, live port change, the Network tab modes, LSD.
-
Managed WireGuard: the
wireguard_*keys. -
VPN and Egress: what
bind_interfacepins, the kill switch,allow_direct. - Race Drain, Graduation and Seed Obligations: the drain's behaviour and the Race tab volume cards.
- Known Limitations in 4.4: every gap in one list.