Skip to main content

Install with Docker

The image ghcr.io/njmule/njmule (its page on GitHub) runs njMule's headless engine with its web interface, for a server, a NAS or any machine with Docker. This guide describes ghcr.io/njmule/njmule:0.3.1. You use it from a browser, through the web interface.

What the image holds​

The image holds only njMule's native executable: no Java, no shell, no package manager.

PlatformExecutableBase
linux/amd64the static one, linked with muslempty (scratch)
linux/arm64the glibc onedistroless

It runs as user and group 1000, keeps all its data in the volume /njmule, and exposes three ports: 4662/TCP (eD2K), 4672/UDP (eD2K and Kad) and 4711/TCP (web interface). By default it starts as:

njmule --config-dir /njmule --webui-password-file /run/secrets/njmule_webui_password --webui-lan

that is: the web interface password is read from a secret at every start, and the interface answers on every address of the container.

Image tags​

Each version is tagged with its number, such as ghcr.io/njmule/njmule:0.3.1. A release is also tagged with its minor version (0.1 for 0.1.x) and latest; a test version (alpha, beta or release candidate) gets its own number only, and does not move latest. The commands below use latest; name a version instead to choose when you move to the next one.

docker pull ghcr.io/njmule/njmule:latest

Run it with docker run​

  1. Make a folder for the completed downloads, and a file whose first line is the web interface password (8 characters at least):

    mkdir -p ~/njmule/incoming
    printf '%s\n' 'a password of 8 characters or more' > ~/njmule/webui_password
    sudo chown -R 1000:1000 ~/njmule/incoming
  2. Start the container:

    docker run -d --name njmule --restart unless-stopped --stop-timeout 30 \
    -p 4662:4662/tcp -p 4672:4672/udp -p 4711:4711/tcp \
    -v njmule:/njmule -v ~/njmule/incoming:/njmule/incoming \
    -v ~/njmule/webui_password:/run/secrets/njmule_webui_password:ro \
    ghcr.io/njmule/njmule
  3. Open the web interface at the address of the host, for example http://192.0.2.10:4711/, and log in with the password. The first time, a short set-up opens: see First start.

-v njmule:/njmule keeps the settings, lists, identity and unfinished downloads in a Docker volume named njmule; the completed downloads go to ~/njmule/incoming on the host.

Run it with Docker Compose​

The repository holds a Compose file, packaging/docker/compose.yaml. Put it in a folder with the password in webui_password.txt beside it:

services:
njmule:
image: ghcr.io/njmule/njmule:latest
restart: unless-stopped
# Time to save the downloads and settings once asked to stop.
stop_grace_period: 30s
ports:
- "4662:4662/tcp" # eD2K
- "4672:4672/udp" # eD2K and Kad
- "4711:4711/tcp" # web interface
volumes:
- njmule:/njmule
- ./incoming:/njmule/incoming
- ./temp:/njmule/temp
secrets:
- njmule_webui_password
command: ["--webui-password-file", "/run/secrets/njmule_webui_password", "--webui-lan"]

volumes:
njmule:

secrets:
njmule_webui_password:
file: ./webui_password.txt

Then, in that folder:

printf '%s\n' 'a password of 8 characters or more' > webui_password.txt
mkdir -p incoming temp
sudo chown 1000:1000 incoming temp
docker compose up -d

Data and permissions​

The volume /njmule holds everything: config, data, temp (unfinished downloads), incoming (completed downloads), cache, logs and gui. You can mount the unfinished and the completed downloads on their own, as the Compose file does; keep them on the same disk if you can, so that a finished file moves without being copied.

njMule runs as UID 1000 in the container, so the host folders you mount must belong to UID 1000:

sudo chown -R 1000:1000 ~/njmule/incoming

To run as another user, add --user <uid>:<gid> (or user: in Compose) and mount a folder of that user on /njmule itself, instead of the named volume.

Ports and High ID​

The image publishes 4662/TCP, 4672/UDP and 4711/TCP. For a High ID, so that other clients can reach you, your router must forward 4662/TCP and 4672/UDP to the host. UPnP does not cross Docker's bridge network: to let njMule ask the router itself, run the container with --network host (then the -p options are not needed). If you change the ports in the options, publish the new ones unchanged, such as -p 5000:5000/tcp. See Ports and firewalls.

Web interface options​

Options after the image name replace the default ones, so repeat those you keep:

docker run … ghcr.io/njmule/njmule \
--webui-password-file /run/secrets/njmule_webui_password --webui-lan --webui-host nas.local

In Compose, change command: the same way.

  • Password. It comes from the first line of the secret at every start; change the file and the new password applies from the next start. njMule never prints or logs it, and keeps only a hash.

  • Host names. Against DNS rebinding, the interface answers to localhost and to IP addresses only. To reach it by a name, such as nas.local or the public name of a reverse proxy, add --webui-host <name> for each name.

  • Reverse proxy. Add --webui-proxy <address> for a proxy you trust to name its clients; see Behind a reverse proxy.

  • Guest. For a guest, who may only look, put its password in a second secret and add --webui-guest-password-file /run/secrets/njmule_webui_guest_password; like yours, it is read again at every start. The repository's Compose file has these lines, commented out. --webui-no-guest takes the guest away.

  • Remote-control API. Add --webui-api; then the command line in the container drives njMule:

    docker exec njmule njmule --config-dir /njmule --remote status

    See Remote control.

note

The password file sets only the password at every start: the other settings of the web interface stay as they were saved. An option on the command line wins over what was saved: --webui-lan and --webui-api turn their setting on, and the --webui-host or --webui-proxy names given replace the saved ones. The web interface's own settings change only in the desktop app on njMule's computer, never in a browser, so a container takes them from its command line.

The interface is served over plain HTTP: keep it on a trusted network, or put a reverse proxy with HTTPS in front of it. See Web interface security.

Stop and logs​

docker stop asks njMule to save its state and exit (SIGTERM); --stop-timeout 30 and stop_grace_period: 30s give it the time to. The container then ends with code 143, a requested stop. docker logs njmule shows what it printed; the full log is in the volume, under /njmule/logs.

Update​

njMule in Docker tells you when a new version is out, in a notice of the web interface (its Details open the Updates window, which tells how to install it) and in its log, but never replaces itself: pull the new image and recreate the container.

docker compose pull && docker compose up -d

With docker run, pull the image, remove the container (docker stop njmule, docker rm njmule) and run it again with the same options: the volume keeps your data. See Updates.

Uninstall​

Remove the container, then the volume if you want to delete njMule's data too:

docker stop njmule && docker rm njmule
docker volume rm njmule # deletes the settings, identity and unfinished downloads

With Compose, docker compose down removes the container and docker compose down --volumes the volume too.

The completed downloads in the folder you mounted stay. See Uninstall.

Build the image yourself​

From a checkout of the repository:

docker build -f packaging/docker/Dockerfile -t njmule .

It compiles njMule from the sources inside the build, for the platform of the machine that builds it: on amd64 the static executable, with the musl toolchain it downloads and checks, on arm64 the glibc one. See Building.