Linux · headless daemon

One command. Then it just runs.

Goel° on Linux is a download daemon: HTTP, FTP, SFTP, BitTorrent and HLS in one queue, driven from a browser or from the goel command. The installer puts it in as a hardened systemd service, generates a portal password, and starts it.

install
$ curl -fsSL https://goel.vinitk.dev/install.sh | sudo sh
~250 MB on disk ~2 min including deps x86_64 and aarch64 sudo goel uninstall reverses it

No DockerNo HomebrewNo PythonNo Node Checksum-verifiedFree for personal use

01 — Before you pipe anything into a root shell

Read it first. That's the right instinct.

Piping a script to sudo sh is asking a stranger to run code as root on your machine. The script is plain POSIX sh, about 700 lines, and it is the same file this page links to — nothing is minified or fetched at runtime. Download it, read it, then run it:

$ curl -fsSL https://goel.vinitk.dev/install.sh -o install.sh
$ less install.sh
$ sudo sh install.sh

Two things the script does on your behalf, worth knowing before it runs. It refuses to install a release whose published .sha256 it cannot fetch or cannot match — because it is running as root and an unverifiable tarball is not worth the risk. And every line of it lives inside one main() that is only called on the last line, so a connection that drops halfway defines a function and does nothing, instead of half-uninstalling your previous copy.

02 — What the one command actually does

Seven steps, then a URL and a password.

  1. 01Installs runtime libraries via apt — libssh2, libcurl, libssl and ffmpeg, picking whichever package name exists on your release. Skip it with GOEL_SKIP_DEPS=1.
  2. 02Resolves the latest release from the GitHub API, or the one you pinned with GOEL_VERSION.
  3. 03Downloads and verifies the tarball against its published SHA-256, and refuses to continue if it cannot.
  4. 04Creates a goel system user — no login shell, no home directory. The daemon never runs as root.
  5. 05Unpacks into /opt/goel — the daemon, the CLI and the whole Swift runtime, self-contained. Symlinks the CLI to /usr/local/bin/goel.
  6. 06Writes /etc/goel/config at mode 0600 with a generated portal password, and installs the systemd unit plus its writable-paths drop-in.
  7. 07Starts the service and prints the portal URL, the username and the password — once. Re-running the installer upgrades in place and touches none of it.
root@home-server
 Installing runtime libraries
 Checking shared libraries
    ok all resolved
 Finding the latest release
 Downloading goel-daemon-1.0.2-linux-x86_64.tar.gz
 Verifying checksum
    ok 9f2c1d…8ab4
 Creating the goel system user
 Unpacking into /opt/goel
 Writing /etc/goel/config
 Installing the systemd service
 Configuring writable paths
 Starting the service

  Portal    http://127.0.0.1:8080/

  Username  admin
  Password  ••••••••••••••••

  Generated for this machine, and stored in /etc/goel/config.

  Next      sudo goel status        what it is doing
            sudo goel add <url>    queue a download
            sudo goel doctor       check the install
            sudo goel help         everything else

Illustrative — the step names are the real ones; the version and checksum are samples.

03 — What you get

A download manager, not a wrapper around wget.

The same engine as the macOS app, with the window taken off. Everything below is in the daemon itself — there is no plugin system to assemble and nothing else to install.

Five protocols, one queue

HTTP/HTTPS, FTP, SFTP, BitTorrent (torrents and magnets) and HLS streams sit in the same list, with the same pause, resume, retry and priority.

Segmented transfers

Up to 16 connections per file, spread across mirrors, with Metalink failover and back-off retry. Interrupted transfers resume from where the bytes stopped.

Browser portal, phone included

The full UI at http://127.0.0.1:8080/. Set GOEL_LAN=true and drive it from your laptop or phone on the same network, behind a password and a token.

Multi-NIC aggregation

Two uplinks? Pin a download to one interface, or split its segments across several. Per-download or as the server-wide default.

goel add <url> --net aggregate

Survives reboots

The queue is a database, not a process list. The service comes back at boot and picks up every unfinished task where it left off.

Hardened unit

Runs as an unprivileged user with ProtectSystem, a private /tmp, no new privileges and an explicit writable-path list maintained from your config.

Self-contained

The Swift runtime and libtorrent ship inside the tarball. Four common system libraries come from apt. Nothing is compiled on your machine.

A CLI that answers questions

goel doctor checks the install and tells you how to fix what is wrong, rather than printing a stack trace and stopping.

Uninstalls cleanly

sudo goel uninstall removes the service, the binaries, the unit and the user. Add --purge to take the data too. Nothing is left behind to find later.

04 — The goel command

Everything the portal does, from a shell.

Most commands need root, because the config file and the API token are readable only by root. goel help prints this list on the machine itself.

CommandWhat it does
Service
goel statusService state, portal URL, queue summary
goel start | stop | restartControl the service
goel enable | disableStart at boot, or not
goel logs [-f] [-n N]The journal for the service
Configuration
goel configList every setting and its current value
goel config set <key> <val>Change one value, then restart if running
goel config unset <key>Revert to the daemon's default
goel urlPortal URL including the API token
goel token [show|rotate]The API token
Queue
goel add <url>…Queue downloads. --folder, --priority, --paused, --net auto|single:<iface>|aggregate|aggregate:<a>,<b>
goel adaptersNetwork interfaces and the aggregation policy
goel list [--all]The queue; --all includes finished
goel pause | resume <id|all>One download, or everything
goel retry <id>Retry a failed download
goel rm <id> [--data]Remove; --data deletes the files too
Maintenance
goel doctorCheck the install and say how to fix what is wrong
goel uninstall [--purge]Remove the service; --purge also deletes data
# queue an ISO, split across every usable interface
$ sudo goel add https://releases.ubuntu.com/24.04/ubuntu-24.04-desktop-amd64.iso --net aggregate

# a magnet link, paused, into a specific folder
$ sudo goel add 'magnet:?xt=urn:btih:…' --folder /srv/media --paused

# what is going on right now
$ sudo goel list
05 — Installer options

Change the defaults on the way in.

Every one of these is optional, and they go before sh so that sudo passes them through:

$ curl -fsSL https://goel.vinitk.dev/install.sh | sudo GOEL_PORT=9090 GOEL_LAN=true sh
VariableDefaultEffect
GOEL_VERSIONlatest releaseInstall a specific version
GOEL_PORT8080Portal port
GOEL_LANfalseServe to the network rather than loopback only
GOEL_SAVE_DIR/var/lib/goel/downloadsDownload folder
GOEL_NO_STARTInstall without enabling or starting the service
GOEL_SKIP_DEPSDon't touch apt; you are supplying the libraries
GOEL_TARBALLInstall from a local tarball instead of downloading
GOEL_INSECUREInstall even if the release publishes no checksum

Requirements

RequirementWhat it has to be
OSAny Linux with systemd and glibc. Tested on Ubuntu 22.04+ and Debian 12+ and their derivatives; the dependency step uses apt, and on Fedora, Arch or Alpine the installer says so and continues.
Architecturex86_64 or aarch64
RootYes, for the install. The daemon itself runs as an unprivileged goel user.
Disk~250 MB for the release, plus whatever you download

What it touches

PathWhat
/opt/goelThe release: the daemon, the CLI and the bundled Swift runtime
/usr/local/bin/goelSymlink to the CLI
/etc/goel/configConfiguration, mode 0600, root-only — it holds the portal password
/var/lib/goelQueue database, generated API token, and downloads by default
/etc/systemd/system/goel.serviceThe unit, plus a drop-in listing the writable paths
a goel system userNo login shell, no home directory of its own

Upgrading and removing

# upgrade in place — keeps your config, queue, downloads and password
$ curl -fsSL https://goel.vinitk.dev/install.sh | sudo sh

# pin a version instead of the latest
$ curl -fsSL https://goel.vinitk.dev/install.sh | sudo GOEL_VERSION=1.0.2 sh

# remove the service, binaries, unit and user — data kept
$ sudo goel uninstall

# …and the data too
$ sudo goel uninstall --purge
06 — Releases

Every build, with its checksum, on GitHub.

The installer downloads from the same place you would: the GitHub releases page. Each Linux release publishes goel-daemon-<version>-linux-<arch>.tar.gz alongside a .sha256, and the installer refuses any tarball whose checksum it cannot fetch or cannot match.

Prefer to do it by hand?

Download the tarball, verify it yourself, and point the installer at the local file with GOEL_TARBALL=/path/to.tar.gz — the rest of the install is identical.

Not on Linux? The macOS build is a native app, not a daemon — same engine, with a window. It's on the homepage and in the same releases. Building for another architecture or running without systemd is covered in docs/linux.md.

Licence. Goel° is source-available under PolyForm Noncommercial 1.0.0 — free for personal, hobby and student use, and free for charities, schools and public bodies. Running it in the course of a business needs a paid licence; see commercial licensing.