# Naut-Torrent — multi-stage build. # # The daemon, the webui plugin, and the static UI assets are all compiled from # source inside the image, so the binaries are frozen at `docker build` time: # a rebuild is the only thing that bumps the running version. # # docker build -t naut-torrent . # docker run -d --name naut \ # -p 8080:8080 -p 6881:6881 -p 6881:6881/udp \ # -e NAUT_AUTH_PASSWORD=change-me \ # -v naut-data:/data -v /path/to/downloads:/downloads \ # naut-torrent # # The build context must be the Naut-Torrent repo with its submodules checked # out (external/torrent-peer, external/torrent-tracker, web/torrent-ui): # git submodule update --init --recursive # --------------------------------------------------------------------------- # Stage 1 — build # --------------------------------------------------------------------------- FROM debian:bookworm-slim AS build # Toolchain + library headers. Lua/Jansson/SQLite/OpenSSL/liburing are linked # from the distro (the project's default, non-vendored build path). RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ cmake \ pkg-config \ liburing-dev \ libssl-dev \ libjansson-dev \ liblua5.4-dev \ libsqlite3-dev \ && rm -rf /var/lib/apt/lists/* # CMake asks pkg-config for the module name "lua"; Debian ships it as "lua5.4". # Bridge the two with a .pc symlink rather than patching CMakeLists. RUN set -eux; \ luapc="$(find /usr -name 'lua5.4.pc' | head -n1)"; \ test -n "$luapc"; \ mkdir -p /usr/local/lib/pkgconfig; \ ln -sf "$luapc" /usr/local/lib/pkgconfig/lua.pc ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig WORKDIR /src COPY . . # Configure + build only the artifacts the image ships. -DNAUT_STANDALONE=OFF # (default) uses the system Lua/Jansson installed above. RUN cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ && cmake --build build -j"$(nproc)" --target nautd nautctl naut_webui # --------------------------------------------------------------------------- # Stage 2 — runtime # --------------------------------------------------------------------------- FROM debian:bookworm-slim AS runtime # Shared libraries the daemon + plugin load at runtime, CA certs for HTTPS RSS # feeds / tracker announces, and gosu to drop privileges to PUID/PGID at start. RUN apt-get update && apt-get install -y --no-install-recommends \ liburing2 \ libssl3 \ libjansson4 \ liblua5.4-0 \ libsqlite3-0 \ ca-certificates \ gosu \ && rm -rf /var/lib/apt/lists/* WORKDIR /app # Binaries, the webui plugin, and the static frontend assets. COPY --from=build /src/build/nautd /app/nautd COPY --from=build /src/build/nautctl /usr/local/bin/nautctl COPY --from=build /src/build/naut_webui.so /app/naut_webui.so COPY --from=build /src/web/torrent-ui/public /app/web/torrent-ui/public # nautd links the two submodule engines as shared libraries; ship them and # refresh the loader cache so the SONAMEs resolve at runtime. COPY --from=build /src/build/torrent-peer/libtorrentpeer.so /usr/local/lib/ COPY --from=build /src/build/torrent-tracker/libtorrenttracker.so /usr/local/lib/ RUN ldconfig # Bundled Lua scripts (anime_sort.lua and friends). Loaded by default via # NAUT_SCRIPT below; the daemon runs one script at a time. COPY --from=build /src/examples /app/scripts # Defaults — override any of these at `docker run` time with -e. ENV NAUT_WEBUI_HOST=0.0.0.0 \ NAUT_WEBUI_PORT=8080 \ NAUT_WEBUI_ROOT=/app/web/torrent-ui/public \ NAUT_WEBUI_DB=/data/webui.db \ NAUT_WEBUI_SAVE_PATH=/downloads \ NAUT_STATE_DIR=/data/state \ NAUT_SOCKET=/run/naut/nautd.sock \ PUID=99 \ PGID=100 # PUID / PGID # uid:gid the daemon runs as. Default 99:100 # # = unraid's nobody:users, so it can write to # # /mnt/user shares. Match your storage owner. # NAUT_AUTH_USER=admin # default # NAUT_AUTH_PASSWORD=... # generated + printed to the log if unset # NAUT_SESSION_TTL=604800 # login lifetime in seconds (default 7d) # NAUT_SCRIPT=/app/scripts/anime_sort.lua # set to load a script at startup # Entrypoint: start as root, create the data/socket dirs and hand the daemon's # own state (not the downloads share) to PUID:PGID, then drop privileges with # gosu and exec nautd. Built with printf (single-quoted lines keep the $VARs # literal) so the image stays a single Dockerfile on any builder. RUN printf '%s\n' \ '#!/bin/sh' \ 'set -e' \ ': "${PUID:=99}" "${PGID:=100}"' \ 'mkdir -p "$NAUT_STATE_DIR" "$(dirname "$NAUT_WEBUI_DB")" "$(dirname "$NAUT_SOCKET")"' \ 'mkdir -p "$NAUT_WEBUI_SAVE_PATH" 2>/dev/null || true' \ '# Own the daemon state so it is writable as PUID:PGID. The downloads share' \ '# is left alone — its permissions come from the host / NFS export.' \ 'chown -R "$PUID:$PGID" "$NAUT_STATE_DIR" "$(dirname "$NAUT_WEBUI_DB")" "$(dirname "$NAUT_SOCKET")" 2>/dev/null || true' \ '[ -n "$NAUT_SCRIPT" ] && set -- --script "$NAUT_SCRIPT" "$@"' \ 'exec gosu "$PUID:$PGID" /app/nautd --socket "$NAUT_SOCKET" --plugin /app/naut_webui.so --state-dir "$NAUT_STATE_DIR" "$@"' \ > /usr/local/bin/entrypoint.sh \ && chmod +x /usr/local/bin/entrypoint.sh # Mountpoints (ownership is fixed at runtime by the entrypoint per PUID/PGID). RUN mkdir -p /data /downloads /run/naut VOLUME ["/data", "/downloads"] EXPOSE 8080 6881 6881/udp # Liveness: ask the daemon to pong over its control socket (no extra tooling). HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD nautctl --socket "$NAUT_SOCKET" ping || exit 1 ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]