Running Noct in Docker
services: noct: image: drumandgeorge/noct:latest ports: - "7356:7356" volumes: - ./noct-data:/data - /path/to/media:/media:ro environment: PUID: 1000 PGID: 1000 devices: - /dev/dri:/dev/dri # optional: hardware encoding restart: unless-stoppedAdd the folders under /media in the web app.
The user
Section titled “The user”The container starts as root only to become PUID:PGID (1000:1000 unless you
say otherwise), and Noct runs as that. Set them to your user’s on the host, which
id shows, so that what is written to /data is yours: the database, backups,
artwork. It’s the only thing Noct writes to: media folders can be mounted read
only (:ro), and nothing is lost by it.
If you’d rather not start as root at all, run the container with user: "1000:1000" and make /data writable by it yourself; the PUID and PGID
settings are then not used.
UMASK sets who else can read what Noct writes: 002 makes it group-writable,
for a backup tool running as another user in the same group, and 077 keeps it
private to Noct’s user, which is worth having since backups hold your TMDB key.
It’s three or four octal digits. Unset, files get Docker’s default (022), and it
applies when you start the container with user: too.
Keeping the cache apart
Section titled “Keeping the cache apart”Next to its database, Noct keeps what it can make again: the video it converts
as it’s watched, resized pictures, subtitles, the pictures on the seek bar. It’s
all under /data/cache, so backing up /data backs up gigabytes of it, and the
constant writing of converted video wears out whatever disk the database is on.
NOCT_CACHE_DIR puts it somewhere else, such as a fast disk or memory:
environment: NOCT_CACHE_DIR: /cache tmpfs: - /cacheThe container makes the folder and gives it to PUID:PGID as it does /data.
Nothing is lost when it’s emptied, and what’s converted for a device is made
again. Without it, nothing changes. The dashboard’s free space is still that of
the disk /data is on.
Being found by the apps
Section titled “Being found by the apps”Noct announces itself on the local network (_noct._tcp, over mDNS, which
Apple calls Bonjour) so that its apps list it without anyone typing an address.
Multicast doesn’t cross a container’s own network, so for that to work give the
container the host’s: network_mode: host in place of ports. Without it
everything else works, and an app is given the address (http://<host>:7356).
NOCT_MDNS=off turns the announcement off where it isn’t wanted.
Is it well
Section titled “Is it well”The image has a health check, so docker ps says healthy once the server is
answering, and unhealthy if it stops. It runs noct-server healthcheck, which
asks the server’s own /api/health.
For Prometheus and Grafana, set NOCT_METRICS_TOKEN and scrape /api/metrics
with it: see metrics.
Hardware encoding
Section titled “Hardware encoding”Without it, anything that has to be converted for a device that can’t play it as it is (see Transcoding) is encoded by the CPU, which a NAS can be slow at. With an Intel or AMD graphics card, Noct can use VA-API instead:
- Pass the card in:
devices: ["/dev/dri:/dev/dri"](or--device /dev/dri). - That’s all. The entrypoint finds the group that owns the card’s devices on
your host and adds Noct to it, so there’s no
group_addorrendergroup id to look up.
The image has the VA-API drivers for Intel (on amd64) and for AMD, and ffmpeg.
Noct looks for /dev/dri/renderD128, which is the first card. Nothing is done
about NVIDIA’s NVENC yet.
If hardware encoding doesn’t start, Noct falls back to the CPU on its own, and
says so in the log (encoder failed, trying the next), so a card that doesn’t
work shows up as slow, not as video that doesn’t play.
What’s in the image
Section titled “What’s in the image”ffmpeg from Debian, which is what looks inside your files (ffprobe) and
converts them. Without it Noct would only know their names and sizes. That makes
the image bigger than it would otherwise be.
Publishing the image by hand
Section titled “Publishing the image by hand”.github/workflows/docker.yml publishes :edge on every push to main and the
version tags on a release. When it can’t run (out of Actions minutes, say),
docker/publish.sh builds the same Dockerfile on your own machine and pushes
it to Docker Hub:
docker logindocker/publish.sh --tag edge --platforms linux/amd64 # what the workflow would push, for an x86 serverdocker/publish.sh # :<this branch's name>, for trying a branch outdocker/publish.sh --no-push # build onlyRun it from a clean checkout of main for :edge, since it builds what is in the
folder. It makes a buildx builder of its own (noct-builder) the first time, and
keeps a build cache in ~/.cache/noct-docker-build. The web build needs a few GB:
on Colima or Docker Desktop’s default 2 GB virtual machine it is killed with
cannot allocate memory, so give the VM 8 GB (colima start --memory 8 --cpu 4).
It never tags :edge or
:latest unless you ask with --tag.