docker-compose.yml
Rama main · réplica de lectura del repositorio original.
# nzbfast - the whole install, anywhere Docker runs: home server, NAS,
# seedbox, VPS, a laptop.
# 1. put this file in a folder of its own
# 2. docker compose up -d
# 3. open http://<host>:6789 and add your Usenet server in the
# Welcome panel (no file to edit - it applies live)
# Web UI + SABnzbd/NZBGet-compatible API at http://<host>:6789
# Later, updating is: docker compose pull && docker compose up -d
#
# This file is generic: no provider details go in it, and the one line
# worth setting first is the downloads volume, below. NAS owners who would
# rather click than type have per-platform guides: Synology (Container
# Manager, no SSH) is docs/SYNOLOGY.md, and Unraid has a Community
# Applications template - search nzbfast in the Apps tab. Same image, and
# the same program, either way.
services:
nzbfast:
image: nzbfast/nzbfast:latest # Docker Hub (searchable in Synology/Unraid GUIs)
# ghcr equivalent (identical image): ghcr.io/nzbfast/nzbfast:latest
# Or build locally instead of pulling:
# build: .
container_name: nzbfast
restart: unless-stopped
ports:
- "6789:6789"
environment:
# PUID/PGID = the host user that should own downloads.
# On Synology run `id <dsm-user>` (often uid 1026, gid 100/users).
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
# API key: the control API is published on your LAN (below), so on
# first run nzbfast GENERATES a key and prints it in the logs
# (`docker logs nzbfast`) - use that in Sonarr/Radarr.
#
# Better, if you wire up Sonarr/Radarr: set your own key here and
# uncomment. A key in this file lives on the host and is re-applied
# on every start, so it survives the container being recreated,
# re-pulled, or rebuilt from scratch - your *arrs never need
# re-pairing. A key set later in the dashboard still wins over it.
# To run keyless on a trusted network, NZBFAST_OPEN=1.
# - NZBFAST_APIKEY=change-me
# - NZBFAST_OPEN=1
#
# Where finished downloads land. See the volumes note below before
# changing it: this path and the mapping under it have to agree.
- NZBFAST_OUT=/data/usenet
# Hardening. Every line here was measured against this image on a real
# Docker engine, including a download run end to end, because the
# obvious spelling of it does not work: `cap_drop: [ALL]` on its own
# stops the container dead at
# error: failed switching to "1000:1000": operation not permitted
# The entrypoint starts as root so it can adopt the ownership of your
# bind mounts, then drops to an unprivileged uid with `gosu` before the
# daemon ever runs, and dropping every capability takes away the two it
# needs to do that. So the capabilities below are added back by name and
# nothing else is: it is the smallest set that still lets the entrypoint
# hand your folders to your own user, and lets the container stop.
#
# SETUID, SETGID the privilege drop itself
# CHOWN give a freshly created bind mount to PUID/PGID
# FOWNER chmod the config file to 0600 once it is theirs
# DAC_OVERRIDE read and fix up a /config a previous run left
# owned by somebody else
# KILL let tini pass `docker stop`'s SIGTERM on to the
# daemon. tini is PID 1 and stays root; the daemon
# runs as PUID after the drop, and sending a signal
# to another user's process is exactly what
# CAP_KILL grants. Without it the forward is refused,
# the daemon never hears the stop, and every stop or
# restart sits out Docker's whole timeout before it
# is SIGKILLed (GitHub #105, found and fixed by
# CLHatch in #106). The earlier list left KILL out
# because the measured run above only ever STARTED
# the container and finished a download in it.
#
# What that removes, relative to the fourteen Docker grants by default:
# NET_RAW (raw sockets), MKNOD, SETPCAP, SETFCAP, SYS_CHROOT, FSETID,
# AUDIT_WRITE and NET_BIND_SERVICE. The daemon itself runs with no
# capabilities at all either way.
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- FOWNER
- KILL
- SETGID
- SETUID
# Nothing in the container is setuid, so this costs nothing and closes
# the route a setuid binary would give an escape.
security_opt:
- no-new-privileges:true
#
# A read-only root filesystem is available and needs a scratch mount to
# go with it. Measured: the container starts, adopts the folders, picks
# up an .nzb and finishes a download with these three lines uncommented.
# Not measured: an unpack of a large archive set, and a long-running
# index. Uncomment if you want it and watch the first unpack.
# read_only: true
# tmpfs:
# - /tmp
# - /run
volumes:
# ./ paths are anchored to THIS FILE's folder (not where you run the
# command from). The config volume IS your install - settings, API
# key, queue - so keep this file in place, and if you ever move it,
# move the folders with it or switch these to absolute paths.
# Updating never touches the volumes; see the manual's Updates page.
- ./config:/config # settings + index database
- ./watch:/watch # drop an .nzb here to auto-download
#
# DOWNLOADS. Two things about this line are deliberate.
#
# It is the SAME path on both sides. When a job finishes, nzbfast
# tells Sonarr/Radarr where the files are, and that path has to mean
# the same thing inside their container as it does inside this one.
# Map it to /downloads here and they are handed a path that does not
# exist in their namespace: the download sits in the queue and the
# *arr declines to import it, reporting a remote path mapping error
# while the files themselves are perfectly fine.
#
# And it sits under a root you also give your *arrs (/data here, but
# the name does not matter - /shared, /storage, whatever, as long as
# every container uses the one root). Point your library at
# /data/media and an import becomes a rename: instant, and no second
# copy of the release. Downloads on their own mount look like a
# separate filesystem to Docker even when they are not, and then
# every import copies 5-50 GB and deletes the original.
#
# Give nzbfast the usenet subtree only, not the whole root. It has no
# business in your library, and the rename still works: it is your
# *arr that moves the files, and it sees both sides.
- /data/usenet:/data/usenet
#
# No "incomplete" folder is needed, and that is not an omission.
# SABnzbd writes there and moves everything across when a job
# finishes; nzbfast writes at the final path from the first article
# on, so there is nothing to move. It does mean a folder named after
# completed downloads holds in-progress ones while they run, which is
# harmless - your *arrs import on the API's job state, not by
# watching the folder - but it surprises people who expect otherwise.
# Auto-update. Watches for a newer nzbfast image and recreates the
# container when one ships (your config/downloads persist - they live on
# the volumes above). Scoped to the nzbfast container only, so it never
# touches your other containers. Remove this service to pin your version.
#
# Read this before you keep it: recreating containers needs the Docker
# socket, and mounting /var/run/docker.sock gives this container
# root-equivalent control of the host. If you would rather not make that
# trade, delete the service and run `docker compose pull && docker
# compose up -d` from cron (or, on a Synology, from Task Scheduler)
# instead - same effect, no standing socket access.
#
# Either way, keep the :latest tag above. A container created from a
# version tag such as :1.0.3 never moves: both Watchtower and a manual
# re-pull fetch the tag the container was created with.
watchtower:
# The maintained fork. The original containrrr/watchtower was
# archived, and its image has not been rebuilt since 2023.
image: nickfedor/watchtower
container_name: nzbfast-watchtower
restart: unless-stopped
environment:
# Same timezone as nzbfast above, so the schedule below means your
# 04:00 and not 04:00 UTC.
- TZ=Etc/UTC
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --cleanup --schedule "0 0 4 * * *" nzbfast # daily 04:00, nzbfast only