Skip to content

Upgrading from 3x

Kheopsian edited this page Oct 13, 2026 · 3 revisions

🇬🇧 English · 🇫🇷 Français

Upgrading from 3.x

Applies to Hydranos 4.4.

This page is for you if you run Hydranos 3.x (then called Hydra) and want to move to 4.4 without losing torrents, seeding time or tracker standing. At the end you will know what disappeared, what replaces it, what to back up, what the first 4.4 start does to your files, and why there is no way back except your backup.

It is the only page of this wiki that explains 3.x. The words "agent", "front", "gRPC" and "Typhon process" name things that do not exist in 4.4; other pages mention them only to say they are gone.

What changed

The short version: 3.x was two programs (a Go daemon and a Rust engine talking over a local socket), optionally spread across machines with gRPC "agents". 4.4 is one Rust process, hydranos, that holds the web UI, the APIs and every engine. Several machines are now several complete instances that talk to each other over their normal HTTP API.

flowchart LR
  subgraph v3["3.x (gone)"]
    direction TB
    GO["hydra (Go daemon, the front)"]
    SOCK(["local unix socket, JSON-RPC"])
    ENG["Typhon engine process"]
    AG["remote agent host"]
    GO --- SOCK --- ENG
    GO -- "gRPC + agent token" --- AG
  end
  subgraph v4["4.4"]
    direction TB
    subgraph P["one hydranos process"]
      UI["web UI, REST API, qBittorrent shim, MCP"]
      R["engine race"]
      H["engine hoard"]
      X["extra engines, optional"]
    end
    N["other Hydranos instance (node)"]
    P -- "HTTP + the node's API key" --> N
  end
Loading
3.x 4.4
Go daemon (the "front") + Rust engine process over a unix socket One Rust process hydranos; engines run inside it. See Architecture.
gRPC agents, --agent-only, --front-only, --agent-addr, --agent-token, agent TLS Nodes: whole Hydranos instances added by URL + API key, or enrolled with a one-time token. See Nodes and Multiple Machines.
Separate Typhon engine process per engine In-process engines ([race], [hoard], plus extra engines).
Client spoofing ([announce_clients], per-tracker peer id / user agent) Removed. Hydranos always announces as itself. A one-time migration stops the affected torrents (below).
Managed WireGuard Reimplemented in 4.4, Linux only: network mode WireGuard, managed by Hydranos, one tunnel per engine from your provider's .conf. See Managed WireGuard.
hydra set-listen-port subcommand POST /api/race/listen-port, POST /api/hoard/listen-port or POST /api/engines/:id/listen-port (live rebind, saved to the config).
hydra hash-password / hydra reset-password hydranos hash-password <password> and hydranos reset-password <password> [path/to/default.toml] (since 4.4). See Security and Access.
hoard_pinned.json Already replaced in 3.x by the pinned column of the store; the file is not read.
.torrent files in <data_dir>/uploads/ .torrent bytes live in the store (hydra.db). At every start, uploads/ is checked for any torrent whose metainfo is still missing from the store; once everything is in the store, nothing more is read from it.
Before 3.94.0 only: per-torrent resume JSON in <engine>/resume/ One SQLite state.db per engine (3.94.0 and later already use it); the JSON is imported once and no longer written (unless TYPHON_RESUME_JSON=1 keeps it mirrored, or TYPHON_STATE_DB=0 keeps the engine on JSON only).
UDP trackers: announced since 3.56.0; broken from 4.0 to 4.2 (handed to the HTTP client, failing on every pass) Restored in 4.3.0, on by default (enable_udp_trackers = true per [race]/[hoard]).
Category placement, agents, strategy, min_free_bytes Kept in the stored category so it round-trips, read by nothing, and named in a warning at every start. A category routes on its Mode only. See Categories and Routing.
Name hydra: binary, image ghcr.io/kheopsian/hydra, /opt/hydra, hydra unit, HYDRA_* env vars Renamed in 4.1.0: hydranos, ghcr.io/kheopsian/hydranos, /opt/hydranos, hydranos unit, HYDRANOS_*. The old HYDRA_* names are not read. TYPHON_* env vars kept their names.
Two binaries in the Docker image (hydra + hydra-engine) One daemon binary, hydranos, in the image and in the archives (the archives add the updater hydranos-update); no hydranos-engine in 4.4.

Some file names did not change: the config is still default.toml, the store is still <data_dir>/hydra.db, and the statistics file is still <data_dir>/bench.db.

Before you upgrade

4.4 reads your existing default.toml, your existing hydra.db and your existing engine folders. Nothing needs converting by hand. But the first start rewrites some of them, and that rewrite cannot be undone.

There is no automatic rollback. Once 4.3.0 or later has opened the store, it rebuilds the torrents table on a new key (one row per torrent per engine). A 3.x binary assumes one row per info hash and must not be pointed at that file again. Restoring your backup is the only way back to 3.x.

Stop 3.x cleanly first (so its resume data is flushed), then copy:

What Where it lives Why
default.toml your config dir (Docker: /config) 4.4 removes the [announce_clients] tables from it and may write an api_key into it.
hydra.db (and hydra.db-wal, hydra.db-shm if present) [daemon] data_dir Re-keyed and switched to WAL on first start.
bench.db [daemon] data_dir Switched to WAL, re-indexed, old per-tracker samples folded.
one folder per engine: race/, hoard/, and one per extra engine beside default.toml (the config dir, not data_dir) Resume state: imported into a new state.db; the JSON stops being updated (same TYPHON_* exceptions as above).
uploads/ [daemon] data_dir Read once to migrate any .torrent missing from the store.

In the Docker image the config dir and data_dir are both /config, so copying the whole /config volume with the container stopped covers everything. Your payload data is not touched by the upgrade.

Example (Docker, container stopped):

docker stop -t 300 hydra
tar -C /srv/hydra -czf hydra-3x-backup-$(date +%F).tar.gz config

Also check, before starting 4.4:

  • data_dir points at your existing store. If it does not, 4.4 creates a new, empty hydra.db there and you see an empty instance.
  • The engine folders sit beside default.toml. 4.4 looks for <config dir>/<engine id>/ (the same layout 3.x writes). If they are elsewhere, torrents come back without resume state and must be re-checked.

Upgrade steps

flowchart TD
  A["Stop 3.x cleanly"] --> B["Back up default.toml, hydra.db, bench.db,<br/>engine folders, uploads/"]
  B --> C["Swap image or binary, rename HYDRA_ env vars,<br/>remove 3.x-only flags"]
  C --> D["First 4.4 start: migrations run"]
  D --> E{"Expected log lines?<br/>Torrents listed?"}
  E -- "yes" --> F["Checklist, then done"]
  E -- "no" --> G["Stop 4.4"]
  G --> H["Restore the backup"]
  H --> I["Start 3.x again"]
Loading

You can go straight to 4.4: on its first start it runs every store migration it knows (they are cumulative), so no intermediate 4.x version is required. Do not target 4.1.0 to 4.1.4 (see Versions to avoid).

Docker

  1. Change the image to ghcr.io/kheopsian/hydranos:v4.4.1 (pin the tag). The old ghcr.io/kheopsian/hydra path is deprecated: do not use it for 4.x, not even its latest tag. It holds only images published before the 4.1.0 rename, and retention pruning may have removed many of them: pin a 3.x tag there (for a rollback) only after checking it still exists; 4.1.0 and later are only under ghcr.io/kheopsian/hydranos.
  2. Rename every HYDRA_* variable to HYDRANOS_*. For example HYDRA_STOP_TIMEOUT becomes HYDRANOS_STOP_TIMEOUT.
  3. Remove any command: that carried 3.x flags (--agent-only, --front-only, --agent-addr…). 4.4 does not honour them: each --agent-… or --front-… flag is named on stderr (hydranos: ignoring --agent-only: the agent/front split was removed in 4.x and Hydranos now runs as one process. Starting a normal instance. …, with the node enrolment command), the values of --agent-addr, --agent-token, --agent-tls-cert, --agent-tls-key and --front-addr are skipped, and the process starts as a complete instance with its own race and hoard engines. Any other unknown argument gets hydranos: ignoring unknown argument "…"; starting anyway (see hydranos --help).
  4. Remove HYDRANOS_ENGINE_ID and HYDRANOS_ENGINES from the environment. The entrypoint refuses them: it prints hydranos: ignoring HYDRANOS_ENGINE_ID: the 3.x agent mode was removed in 4.x and Hydranos now runs as one process. Starting a normal instance on /config/default.toml. … (the directory is HYDRANOS_CONFIG_DIR), tells you to enrol the machine as a node instead, and starts on that config as usual. Removing the variables silences the message.
  5. Give the stop enough time. HYDRANOS_STOP_TIMEOUT bounds the resume flush (default 120; also 90s, 2m, 1m30s, see Operating Hydranos); the canonical compose uses stop_grace_period: 150s. Keep the grace period above the timeout plus about 10 s.
  6. Keep the same volumes. Container and service names are yours to choose; keeping hydra works.

In a 3.x compose file, only these lines change:

    image: ghcr.io/kheopsian/hydranos:v4.4.1   # was ghcr.io/kheopsian/hydra:<3.x tag>
    stop_grace_period: 150s
    # environment: every HYDRA_* renamed HYDRANOS_*; HYDRANOS_ENGINE_ID / HYDRANOS_ENGINES removed
    # command: no 3.x flags (--agent-only, --front-only, --agent-addr...)

Ports and volumes stay as they were. The complete compose file, with every option explained, is on Install with Docker.

Linux bare metal

The 3.x bare-metal installer (from 3.8.0) used /opt/hydra, /etc/hydra, /var/lib/hydra, a hydra user and a hydra unit. 4.4's install.sh uses /opt/hydranos, /etc/hydranos, /var/lib/hydranos, user hydranos and a hydranos unit. It seeds a new config only when /etc/hydranos/default.toml does not exist, so put your old files in place first:

sudo systemctl stop hydra
sudo systemctl disable hydra
# Back up first (see above), then move config + engine folders and the data dir
sudo mkdir -p /etc/hydranos /var/lib/hydranos
sudo cp -a /etc/hydra/. /etc/hydranos/
sudo cp -a /var/lib/hydra/. /var/lib/hydranos/
# Point data_dir at the new location
sudo sed -i 's#^data_dir = .*#data_dir = "/var/lib/hydranos"#' /etc/hydranos/default.toml
# Create the new account now, so the files belong to it before the service starts
sudo useradd --system --home-dir /var/lib/hydranos --shell /usr/sbin/nologin hydranos
sudo chown -R hydranos:hydranos /etc/hydranos /var/lib/hydranos
# Unpack the 4.4.0 tarball, then from inside it:
sudo ./install.sh

install.sh reuses the existing hydranos account and config, installs hydranos and hydranos-update in /opt/hydranos, installs the unit (or, if /etc/systemd/system/hydranos.service already exists and differs, keeps yours and puts the shipped one beside it as hydranos.service.new), then enables and starts the service. Rename any HYDRA_* variable in drop-in units to HYDRANOS_*. Details of the unit are on Install on Linux.

Windows

  1. Stop the 3.x daemon.
  2. Back up its default.toml, data dir and engine folders.
  3. Unzip hydranos-v4.4.0-windows-amd64.zip and start hydranos.exe with an explicit config path, so it uses your existing files rather than seeding new ones:
    hydranos.exe --config C:\Hydranos\default.toml
    
  4. Stop it with the tray menu Quit Hydranos, which flushes resume data; wait until hydranos.exe is gone from Task Manager.

Without --config, 4.4 on Windows uses default.toml beside hydranos.exe, or, if there is none there, the \config\default.toml a 4.3 install left. The notice it prints (hydranos: using … (the 4.3 location); move it beside hydranos.exe or pass --config) is printed before any console is attached, so it does not show in a console window. See Install on Windows.

What happens on the first 4.4 start

In order, the first start does the following. The log lines quoted are the ones to look for (in hydranos.log beside the config, and in docker logs or journalctl in every case).

  1. API key. If [daemon] api_key is empty, a new key (48 hex characters) is generated and written to the config, with the log line no API key was configured; a new one has been generated and written to the config. If it is still the published placeholder change-me-in-production, it is replaced the same way and the line reads the configured API key was the published placeholder and has been replaced by a generated one -- clients configured with the old value must be updated …. Any client that used the old value must be given the new key.

  2. 3.x keys named. Every key Hydranos knows to be dead gets one warning, config: <where> is ignored: <why>. Instead: <what to do>., at this start and every later one: [daemon] agent_token; in agent/engine blocks addr (when not empty), token, tls_ca and the engine sub-table; listen_interfaces, file_pool_size, custom_choking and disk_slots in [race], [hoard] or a block's session; the sections [bench], [metrics], [peer_intel], [arr_cleanup], [notify]; and [race_drain] min_age_minutes. For example, for an agent block named box2 (the line names the block as written in the TOML, kind and name):

    config: [[agent]] "box2" addr is ignored: a 3.x remote agent: 4.x has no agent channel, so this block starts nothing here and reaches nothing there. Instead: enrol that machine as a node: …
    

    Once the store is open, the 3.x category fields get one line per field, naming the categories: config: category field `strategy` (in films, series) is ignored: …. These are warnings, never errors; the full list is under Leftovers below. A typo in a key name is still accepted without a word.

  3. Re-key, new tables, WAL. When the first engine opens the store, the torrents table is rebuilt on (info_hash, session) in one transaction: re-keying the torrents table on (info_hash, session); this rewrites it and ends the 3.x rollback. New tables (nodes, workflows, magnets, IP bans…) are added, and the store switches to WAL journaling, except when its folder is on a network filesystem.

  4. Metainfo. For each engine, any torrent known to its state.db whose .torrent is missing from the store is imported from <data_dir>/uploads/<info_hash>.torrent (only files named by their hash, and only if the hash matches): metainfo migrated out of uploads/ and into the store. On an install whose resume state was still JSON (before 3.94.0), state.db is empty at this point, so this import happens on the second start.

  5. Resume state (before 3.94.0 only). Per engine, the legacy JSON in resume/ is imported once into an empty state.db: [statedb] first start on SQLite state: N records carried over.

  6. bench.db. Opened after the engines, and switched to WAL with the same network-filesystem exception.

  7. Stopped torrents. Torrents you had stopped in 3.x stay stopped.

  8. Client-spoofing removal. Only torrents whose first tracker matched an [announce_clients] override are stopped, once; a warning lists the hosts and the count (client spoofing has been removed from Hydranos. These torrents were announcing as another client …). The tables are then removed from default.toml. When you start those torrents again they announce under Hydranos's own peer id: check that each tracker allows Hydranos first. Nothing else is stopped.

  9. Background work. A content index is built in a background thread, and bench.db gets an index and folds per-tracker samples older than 48 h into 5-minute rows. The UI is usable meanwhile.

If the store cannot be opened, or lacks a column 4.4 needs, the daemon does not guess: it logs the store could not be opened: <why> -- starting in rescue mode and starts in rescue mode on its usual address (api_host, api_port). The web UI is not served: / answers the one-line text hydra: the store could not be opened (see Rescue mode on Operating Hydranos). Stop it, restore your backup, and report the message on the issue tracker.

Your admin password keeps working: the [auth] hash format is unchanged. If [auth] password_hash is empty, the UI shows the first-run screen Welcome to Hydranos with Create account. That screen only answers a caller on loopback or a private network; from elsewhere, set the password on the host with hydranos reset-password (see Security and Access).

After the upgrade: checklist

  • hydranos --version prints the release you installed (hydranos 4.x.y).
  • The log shows the lines above, and the web UI opens normally (rescue mode serves no UI).
  • Every config: … is ignored line read, and each named key removed from default.toml (your backup keeps the 3.x file; the category fields stay in the store and keep being named).
  • The Race and Hoard tabs list your torrents; the count matches 3.x.
  • Torrents stopped by the spoofing migration reviewed, then started with Start where the tracker allows it.
  • Sonarr, Radarr, autobrr and scripts use the current API key ([daemon] api_key).
  • Former 3.x agent hosts re-added as nodes: Nodes tab, + Declare an existing one (URL + that instance's API key) or + Enrol a machine. See Nodes and Multiple Machines.
  • Trackers listed with udp:// URLs now get announced; while an engine's announces go through a SOCKS5 proxy (announce_proxy, the SOCKS5 mode or TYPHON_ANNOUNCE_PROXY), its UDP trackers are not announced (see VPN and Egress).
  • Categories that relied on a routing strategy or per-agent paths: re-check their Mode and save path.
  • The stop timeout of your supervisor (stop_grace_period, TimeoutStopSec) is long enough.
  • Keep the 3.x backup until you are sure; it is your only way back.

Moving a 3.x multi-machine setup

4.4 does not convert a 3.x agent into a node. Each machine becomes its own instance with its own store, and the instance where you declare it (the controller) sees its torrents in the merged list. There is no automatic transfer of the torrents a 3.x agent was running to a 4.4 instance on that machine: plan to add them there again, pointing at the existing data (see Adding Torrents and Existing Data). Which deployment fits which need is on Deployment Topologies.

Several VPN tunnels on one machine no longer need agents: declare an extra engine per tunnel (+ Add an engine on the Nodes tab), and on Linux let Hydranos bring each tunnel up (Managed WireGuard) or pin each engine to an interface you manage. Read what an interface pins on VPN and Egress.

Leftovers that do nothing in 4.4

These survive in old config files, scripts and compose files. 4.4 names most of them instead of ignoring them in silence. Do not rely on any of them.

Accepted but ignored in 4.4: 3.x remote-agent settings — agent blocks (TOML array of tables) with an addr (and their token, tls_ca), and [daemon] agent_token — are parsed and never used, and each is named in a startup warning; no connection is made — declare the remote machine as a node instead.

An agent or engine block without addr and with a role still starts a local extra engine: agent is a legacy name for the same block (see Configuration: Engines). With an addr, as in this 3.x example, it is skipped:

# 3.x remote agent: skipped in 4.4, starts nothing, named at startup
[[agent]]
name = "box2"
addr = "192.0.2.10:7070"

The 3.x remote-agent API is gone: every method under /api/agents and /api/jobs/move-remote answers 410 Gone (behind the API key, so 401 without it), with the routes to use instead:

{"error":"the 3.x agent API was removed in 4.4: engines on this machine are /api/engines, other machines are /api/nodes","see":["/api/engines","/api/nodes"]}
{"error":"move-remote was removed in 4.4: use POST /api/selection/handoff with a node from /api/nodes and one of its engines","see":["/api/selection/handoff","/api/nodes","/api/engines"]}
Leftover What happens in 4.4
agent block with addr, token, tls_ca, or an engine sub-table Skipped, starts nothing; one startup warning per key, with the node enrolment command.
[daemon] agent_token Not a setting any more; named at startup; dropped by Reset to defaults.
listen_interfaces, file_pool_size, [race.custom_choking], [hoard.disk_slots] Not read; named at startup with the key to use instead (bind_interface, aio_threads, choking + max_uploads_per_torrent, nothing).
[bench], [metrics], [peer_intel], [arr_cleanup], [notify], [race_drain] min_age_minutes Not read; named at startup; hidden from Advanced settings.
Every method under /api/agents (GET, POST, PUT, DELETE, …/test, …/action, …/restore) 410, naming /api/engines and /api/nodes.
/api/jobs/move-remote 410, naming POST /api/selection/handoff.
Category placement, agents, strategy, min_free_bytes Stored (so a 3.x rollback finds them), never read; one startup warning per field, naming the categories.
HYDRANOS_ENGINE_ID, HYDRANOS_ENGINES Refused by the Docker entrypoint with a message; the container starts on its own config (see Docker step 4).
HYDRA_* env vars Not read.
--agent-only, --front-only, --agent-addr, --agent-token, any --agent-…/--front-… flag Named on stderr; the process starts as a complete instance.
hydranos set-listen-port Does not exist: ignoring unknown argument …; starting anyway, and the daemon starts. Use the listen-port routes.
hydranos-engine, hydranos-engine.exe, HYDRANOS_ENGINE_BIN No longer in the archives, the image or the shipped unit. An old hydranos-engine left in /opt/hydranos is not used; delete it.
Image ghcr.io/kheopsian/hydra Deprecated; use ghcr.io/kheopsian/hydranos.

hydranos reset-password and hydranos hash-password exist again in 4.4 (see Security and Access).

The 3.x design documents (docs/architecture-agent-front.md, docs/agentification-status.md, docs/hoard_announce_scheduler.md) are no longer in the repository, and packaging/README-windows.md and the shipped unit describe 4.x. Two comments of configs/default.toml are stale: "every agent it drives" (the announce tables), and generate with: hydra hash-password (the command is hydranos hash-password). The 4.4 keys that do nothing are listed on Configuration Reference; every known gap is on Known Limitations.

Versions to avoid

  • 4.1.0 to 4.1.4 were withdrawn: their image exits at once (the binary inside was misnamed) and 4.1.0 to 4.1.3 published no archives. They are gone from the registry and the releases. The first working 4.1 is 4.1.5.
  • 4.0.0 and 4.0.1 published no binary archives.

Version numbers read major.release.patch and are not semantic versioning: the major goes up only when upgrading needs more than replacing the binary. See the CHANGELOG.

Upgrading within 4.x

From any working 4.x, upgrading to 4.4 is a binary or image swap on the same config and store. Coming from 4.0.x, the 4.1.0 rename applies (image path, HYDRANOS_* env vars, /opt/hydranos, unit name). Coming from 4.2 or older, the first start switches the store and bench.db to WAL, builds a tracker-history index on bench.db and adds new tables (4.3.0 did this; 4.4 runs every migration it knows). Bare-metal and Windows installs can use hydranos-update; the routine (and its limits) is on Operating Hydranos.

Upgrading from 4.3 to 4.4

Swap the image tag (ghcr.io/kheopsian/hydranos:v4.4.1) or the binaries, then start. The store only gains tables (rss_*, share_limits) and two magnets columns; your config is not rewritten. A Windows 4.3 must be quit from the tray before hydranos-update replaces it (it does not answer 4.4's stop event). What changes for a file written by 4.3:

  • Hourly line test. A default.toml seeded by 4.3.0 contains [vpn_speedtest] enabled = true, iperf3_server = "ping.online.net" and interval_secs = 3600. 4.3 ignored them; 4.4 reads them, so it runs an iperf3 test (upload then download, 10 s each) against that public server every hour. To keep only the manual Run now, set interval_secs = 0 in the file by hand (Advanced settings hides that key in 4.4), or enabled = false to turn the test off entirely. Any value under 300 counts as 300.
  • Dead keys named. Keys that do nothing (listen_interfaces, [race.custom_choking], [bench], [metrics], [race_drain] min_age_minutes, 3.x agent blocks…) now get a config: … is ignored: …. Instead: …. warning at every start (list under Leftovers above). Nothing breaks; delete them to quiet the log.
  • Defaults of absent keys. A [race]/[hoard] without enable_dht, enable_pex or enable_webseed now has them on (4.3: off); the 4.3 template has no enable_webseed, so webseeds start being used. A missing listen_port is 16171 (race) or 16172 (hoard), or the next one no other engine uses, instead of a random port. The template's peer_timeout = 30 (race) and 20 (hoard) are now read and raised to the 120 s minimum.
  • bind_interface outside Linux is refused. On Windows and macOS, an engine whose file still has bind_interface stays off the network (no listener, no dial, no announce), with a startup warning bind_interface is Linux-only: … -- this engine will not announce, accept or dial any peer until the key is removed. Remove the key and run the VPN client system-wide.
  • Force Start under a queue. torrents/setForceStart (Sonarr/Radarr "Force Start") was a 404 in 4.3; in 4.4.0 it was a plain start, or a 409 when the torrent's engine has a ceiling (with the template, every hoard torrent). Since 4.4.1 it forces the torrent: started, and run past the queue (Queue, Share and Speed Limits).
  • Share limits wait for the tracker's Minimum seed. Ratio and seeding-time limits (yours, or those Sonarr/Radarr send) now act, but never on a torrent whose tracker has no Minimum seed declared on the Trackers tab: it is held and logged once. Declare the hours, 0 included (Queue, Share and Speed Limits). active_seeds and active_limit act only with queueing = true.
  • Restart buttons exit with code 75. Apply & restart and the other restart controls now do the full clean stop, then exit with code 75 (4.3: code 0, without the resume flush). The shipped systemd unit (Restart=on-failure) and Docker restart policies bring Hydranos back; a monitor that alerts on a non-zero exit will see it (Operating Hydranos).

The full list is in the CHANGELOG.

Hydranos 4.4 · 🇬🇧

Start

Install

Use

Integrate

Network & machines

Operate

Reference


Hydranos 4.4 · 🇫🇷

Démarrer

Installer

Utiliser

Intégrer

Réseau & machines

Exploiter

Référence


Clone this wiki locally