Skip to content

Installation

Haul ships as one container image: tristanteu/haul for linux/amd64 and linux/arm64. It contains the server, the web UI, the built-in hoster plugins and the extractors (7z, unrar).

Docker Compose

mkdir haul && cd haul
curl -O https://raw.githubusercontent.com/firsttris/haul/main/docker/docker-compose.yml
# set APP_SECRET and your download folders, then
docker compose up -d

The file in docker/docker-compose.yml:

services:
  haul:
    image: tristanteu/haul:latest
    container_name: haul
    restart: unless-stopped
    ports:
      - "8080:8080"
      - "127.0.0.1:9666:9666"   # Click'n'Load, only on the host's loopback
    volumes:
      - ./config:/config
      - ./downloads/tmp:/downloads/tmp
      - ./downloads/done:/downloads/done
    environment:
      - APP_SECRET=change-me    # openssl rand -hex 32

Point the two download volumes wherever your disks are, for example /mnt/cache/downloads:/downloads/tmp and /mnt/disk1/downloads:/downloads/done.

Podman Quadlet

For Podman with systemd, docker/ has a Quadlet unit and network:

mkdir -p ~/.config/containers/systemd ~/haul/config ~/haul/downloads/{tmp,done}
cp docker/haul.container docker/haul.network ~/.config/containers/systemd/
# set APP_SECRET, adjust the Volume= lines
systemctl --user daemon-reload
systemctl --user start haul

For a start at boot without a login, install the files into /etc/containers/systemd/ and use systemctl without --user (or run loginctl enable-linger $USER for the user unit).

The unit sets AutoUpdate=registry, so podman auto-update pulls new releases. Logs: journalctl --user -u haul or podman logs haul.

docker run

docker run -d --name haul --restart unless-stopped \
  -p 8080:8080 -p 127.0.0.1:9666:9666 \
  -v ./config:/config \
  -v ./downloads/tmp:/downloads/tmp \
  -v ./downloads/done:/downloads/done \
  -e APP_SECRET="$(openssl rand -hex 32)" \
  tristanteu/haul:latest

Keep the APP_SECRET you used: without it, stored account passwords cannot be read.

First start

Open http://<server>:8080. On the first visit Haul asks you to create the login. To create it without the UI, set HAUL_USER and HAUL_PASSWORD for the first start.

Then:

  1. Accounts & Plugins: add your hoster accounts, see Hosters.
  2. Settings → Captchas: install the userscript if you use hosters with reCaptcha, hCaptcha or Turnstile, see Captchas.
  3. Settings → Click'n'Load from the desktop: create an API token if you want to send Click'n'Load links from your desktop.

Volumes

Path Content
/config SQLite database haul.db and your own plugins in plugins/
/downloads/tmp Downloads in progress (<id>.part). Fast disk or cache drive recommended.
/downloads/done Finished files, one folder per package. Archives are extracted here.

tmp and done may be on different disks; Haul moves finished files across.

Environment variables

Variable Default Purpose
APP_SECRET – (required) Key that encrypts stored account passwords. Do not change it later.
HAUL_USER, HAUL_PASSWORD – Create the web login on the first start
HAUL_CONFIG_DIR /config Database and own plugins
HAUL_TMP_DIR /downloads/tmp Downloads in progress
HAUL_DONE_DIR /downloads/done Finished downloads
HAUL_LISTEN 0.0.0.0:8080 Web UI and API
HAUL_CNL_LISTEN 0.0.0.0:9666 in the image, else 127.0.0.1:9666 Click'n'Load; off turns it off. Publish it only on 127.0.0.1.
HAUL_BUILTIN_PLUGINS /app/plugins in the image, else unset Plugins that come with Haul; unset means only your own plugins load
HAUL_USER_AGENT a desktop browser User-Agent sent to hosters
HAUL_7Z, HAUL_UNRAR found on PATH Extractors: 7zz, 7z or 7za, and unrar
RUST_LOG info,sqlx=warn Log level. haul=debug also saves the hoster pages of failed downloads, see Debugging a hoster.

Settings in the UI

Everything else is under Settings in the web UI and stored in the database.

Setting Default Range
Parallel downloads 3 1–20
Connections per file 4 1–16, hosters may allow fewer
Bandwidth limit (KiB/s) 0, no limit over all downloads
Retries 5 0–50
Extract finished packages automatically on
Delete archives after successful extraction off
Remove the downloads from the list after successful extraction off
Ask for the archive password when none fits on
Verify the checksum after the download on

The same page holds the archive password list, the captcha userscript, the API token for Click'n'Load, the folders and extractors Haul found, and:

  • Language: German or English for this browser, including messages from the server and the hosters. It is also switchable at the bottom of the sidebar.
  • Login: change your password, or log out.

Health check

GET /api/health answers {"status":"ok"} without a login. The image uses it as its Docker HEALTHCHECK, and you can point an uptime monitor at it.

Updating

docker compose pull && docker compose up -d

With Podman: podman auto-update, or systemctl --user restart haul after podman pull. Downloads in progress resume after the restart.

Tags: latest is the latest release, 1.2.3 and 1.2 pin a version.

Behind a reverse proxy

Haul is a single HTTP service on port 8080. The live progress uses Server-Sent Events on /api/events, so the proxy must not buffer that path. With nginx:

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_buffering off;          # live progress (SSE)
    proxy_read_timeout 1h;
}

Caddy and Traefik need no extra settings for SSE.