diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..44e7254 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,31 @@ +# Build output (recompiled inside the image) +build/ +**/build/ + +# VCS metadata — source is copied, submodule working trees are already populated +.git/ +**/.git/ +.gitmodules.bak + +# Local data that must never end up in the image +Downloads/ +downloads/ +*.mkv +*.mp4 +*.torrent +*.db +*.db-wal +*.db-shm +state/ +uploads/ + +# Logs / scratch +*.log +claude.* +list.log +dump.log + +# Editor / OS noise +.vscode/ +.idea/ +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f21e44a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,122 @@ +# 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, plus CA certs for +# HTTPS RSS feeds / tracker announces. +RUN apt-get update && apt-get install -y --no-install-recommends \ + liburing2 \ + libssl3 \ + libjansson4 \ + liblua5.4-0 \ + libsqlite3-0 \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* \ + && useradd --system --create-home --home-dir /home/naut --uid 1000 naut + +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 + +# 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 +# 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) + +# Create the data/download/socket dirs (if the volume is fresh) then exec the +# daemon with the webui plugin. 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' \ + 'mkdir -p "$NAUT_STATE_DIR" "$NAUT_WEBUI_SAVE_PATH" "$(dirname "$NAUT_WEBUI_DB")" "$(dirname "$NAUT_SOCKET")"' \ + 'exec /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 + +# Owned by the unprivileged runtime user; bind-mounted volumes must be writable +# by uid 1000. +RUN mkdir -p /data /downloads /run/naut \ + && chown -R naut:naut /app /data /downloads /run/naut + +USER 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"]