HandBrake

HandBrake

Docker app from junkerderprovinz's Repository

Overview

The full HandBrake video transcoder GUI in your browser – built on Selkies for a smooth, hardware-accelerated web desktop. Dark by default, using HandBrake's own native GTK dark mode (not a repaint). GPU-accelerated transcoding on NVIDIA, Intel and AMD – the most complete HandBrake container available for Unraid. What's included: • HandBrake's complete GTK4 interface (ghb) plus HandBrakeCLI • GPU hardware encoding on NVIDIA (NVENC), Intel (Quick Sync) and AMD (VCE) via GPU_VENDOR – NVIDIA and Intel verified end to end on real hardware • Automated watch-folder conversion – drop a video into /watch, get a transcode in /output, no GUI needed • Up to 5 watch folders, directory exclusion, a daily active-hours window, configurable preset/format/extensions, keep-or-delete source • Web file manager (on by default), web terminal and desktop notifications – all reachable from the same browser tab • 5 conversion hooks for custom scripting, including one that fires for conversions started manually in the GUI, not just the watch folder • A configurable staging directory, so in-progress transcodes never touch the array until they are finished • Safe multi-instance operation – two containers can share one watch folder to convert twice as many files at once, without ever converting the same file twice • Atomic output: conversions are staged and moved onto the output disk only after HandBrake reports success, so a media scanner never picks up a half-written file Notes: • WebUI opens via HTTPS on port 3001 (self-signed cert — accept it once). The Selkies web client requires a secure connection, so open the WebUI directly ONLY over HTTPS (3001). Port 3000 (HTTP) is for a reverse proxy that terminates TLS in front of the container. • GPU acceleration needs the matching passthrough: the NVIDIA Container Runtime for GPU_VENDOR=nvidia, or --device /dev/dri under Extra Parameters for intel/amd. Full per-vendor recipes are in the README's Hardware Encoding section. Leave GPU_VENDOR=none for software encoding. • PUID/PGID default to 99/100 (nobody/users on Unraid). • Auth: leave "WebUI Username" and "Password" EMPTY to run without login. Set both to enable HTTP-basic auth on the WebUI. Recommended whenever the container is reachable from anything beyond your LAN. Source on GitHub: https://github.com/junkerderprovinz/handbrake

HandBrake for Unraid

Build  Lint  Docker Pulls  Image Size  Arch  Selkies  Unraid  License: AGPL-3.0


A modern, plug-and-play Docker image for HandBrake on Unraid. The full transcoder GUI in your browser via Selkies, dark by default using HandBrake's own native GTK dark mode, plus a watch-folder converter that transcodes anything you drop into /watch without opening the UI at all. Everything is configurable from the Unraid template, no SSH or config-file editing required.


Maintained solo, in whatever spare time there is. Bugs, ideas and feature requests via GitHub issues. If it's useful to you, a coffee is always welcome.

Buy me a coffee


Table of Contents

  1. Overview
  2. Screenshots
  3. Quick Start
  4. Volumes and Ports
  5. Configuration
  6. Automated Watch-Folder Conversion
  7. Dark Mode
  8. Hardware Encoding
  9. Conversion Hooks
  10. Web Desktop Features
  11. Running More Than One Instance
  12. Optical Drives
  13. Migrating from jlesage/handbrake
  14. Building Locally
  15. Troubleshooting
  16. License
  17. Support this project

1. Overview

This image packages HandBrake — the open-source video transcoder — into a self-contained Docker container that runs in any modern web browser. It is built on linuxserver/baseimage-selkies, so it inherits LSIO's actively maintained Selkies desktop-streaming stack (a hybrid VNC/H.264 pipeline) and weekly security updates, while everything HandBrake-specific is layered on top here.

What you get beyond bare HandBrake:

  • Selkies instead of noVNC — a hybrid VNC/H.264 pipeline for a smooth web desktop, real bidirectional browser clipboard, native file upload and download, high-DPI ready
  • Dark by default — HandBrake's own native GTK dark mode, not a repaint; switch to light with one variable
  • Watch-folder automation — drop a file into /watch, get a transcode in /output, no GUI interaction
  • Atomic output — conversions are written to a hidden .partial file and renamed on success, so a media scanner never indexes a half-written video
  • Multi-arch — amd64 and arm64, both gated by a CI smoke test that really transcodes a clip before anything is published

Another HandBrake container is also in Community Applications: linuxserver/handbrake, the official LinuxServer.io image. It builds on the very same Docker Baseimage Selkies project this image does, just the Arch Linux flavour of it instead of the Ubuntu one, and opts into that base's newer Wayland/PixelFlux screen-streaming pipeline (PIXELFLUX_WAYLAND=true) rather than the classic X11 one this image still uses by default. A strong, actively developed GUI, but no automated conversion of any kind, so it does not compete on the feature this image is built around.

This image jlesage/handbrake linuxserver/handbrake
Web stack Selkies (X11) noVNC Selkies (Wayland)
Base Ubuntu (glibc) Alpine (musl) Arch Linux
NVIDIA NVENC encoding (#49) n/a
Intel Quick Sync (QSV) encoding ⚠️ (#459) n/a
AMD VCE encoding ⚠️ unverified (#441) n/a
Dark mode default opt-in (DARK_MODE=1)
Watch-folder conversion
Browser clipboard ⚠️
File upload via WebUI
Web file manager opt-in (WEB_FILE_MANAGER=1)
Conversion hooks
Staging on a separate disk n/a
Shared-watch-folder locking n/a
CJK fonts opt-in (ENABLE_CJK_FONT=1)
Multi-arch ❌ amd64 only
Direct VNC client

✅ works · ❌ doesn't · ⚠️ present but limited · ❓ undocumented · n/a no automated conversion to accelerate/configure


2. Screenshots

HandBrake running in the browser in dark mode


3. Quick Start

Unraid: install from Community Applications and adjust the paths in the template. Everything else has a working default.

Plain Docker:

docker run -d \
  --name=handbrake \
  -p 3000:3000 \
  -p 3001:3001 \
  -e PUID=99 \
  -e PGID=100 \
  -e TZ=Europe/Vienna \
  -v /mnt/user/appdata/handbrake:/config \
  -v /mnt/user/media:/storage:ro \
  -v /mnt/user/media/watch:/watch \
  -v /mnt/user/media/converted:/output \
  --restart unless-stopped \
  ghcr.io/junkerderprovinz/handbrake:latest

Then open https://<host>:3001/. Wait for HANDBRAKE IS READY in the container log on the very first start.


4. Volumes and Ports

Container path Mode Purpose
/config rw HandBrake presets, queue, logs and container state
/storage ro Media you want to browse from inside the GUI
/watch rw Watch folder — anything dropped here is converted automatically
/watch2/watch5 rw Additional watch folders (optional)
/output rw Where converted files are written
Port Purpose
3000 WebUI over HTTP
3001 WebUI over HTTPS (self-signed by default)

5. Configuration

Variable Default Description
PUID / PGID 911 User and group the container runs as (Unraid: 99 / 100)
UMASK 022 File-mode mask for everything the container creates
TZ Etc/UTC Container timezone
LANG en_US.UTF-8 Locale, also drives HandBrake's UI language
HANDBRAKE_THEME dark dark or light — see Dark Mode
APP_NICENESS 0 nice level (0-19) for the GUI and every transcode
KEYBOARD_LAYOUT us X keyboard layout loaded at session start
GPU_VENDOR none none, nvidia, intel or amd — see Hardware Encoding
CUSTOM_USER / PASSWORD empty Set both to require a login on the WebUI; empty means no login
CUSTOM_PORT / CUSTOM_HTTPS_PORT 3000 / 3001 Internal WebUI ports

6. Automated Watch-Folder Conversion

Every file dropped into /watch (and /watch2/watch5 when mounted) is transcoded with the configured preset and written to /output. The variable names match jlesage/handbrake so existing template values keep working.

Variable Default Description
AUTOMATED_CONVERSION 1 Set to 0 to disable the daemon entirely
AUTOMATED_CONVERSION_PRESET General/Very Fast 1080p30 HandBrake preset, category/name
AUTOMATED_CONVERSION_FORMAT mp4 Output container: mp4, mkv or webm
AUTOMATED_CONVERSION_KEEP_SOURCE 1 0 deletes the source after a successful conversion
AUTOMATED_CONVERSION_VIDEO_FILE_EXTENSIONS (built-in list) Space-separated extensions to pick up
AUTOMATED_CONVERSION_WATCH_DIR AUTO AUTO scans /watch/watchN; any other value is used as the single watch folder
AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS 5 How many /watchN folders AUTO looks for
AUTOMATED_CONVERSION_OUTPUT_DIR /output Destination folder
AUTOMATED_CONVERSION_OUTPUT_SUBDIR empty A fixed subfolder, or SAME_AS_SRC to mirror the source tree
AUTOMATED_CONVERSION_OVERWRITE_OUTPUT 0 1 overwrites an existing output file
AUTOMATED_CONVERSION_SOURCE_STABLE_TIME 5 Seconds a file must stop changing before it is picked up
AUTOMATED_CONVERSION_CHECK_INTERVAL 5 Seconds between watch-folder scans
AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS empty Extra HandBrakeCLI arguments appended to every job
AUTOMATED_CONVERSION_STAGING_DIR empty Where in-progress conversions are written. Empty means <output>/.handbrake-staging
AUTOMATED_CONVERSION_IGNORE_DIRECTORIES empty Space-separated directory basenames pruned from every watch-folder scan, matched anywhere in the tree
AUTOMATED_CONVERSION_ACTIVE_HOURS empty Restrict conversion to a daily window, HH-HH (24h clock, e.g. 22-06 for overnight only). Empty means always active. Uses the container's TZ (default Etc/UTC), so set TZ first if the window should follow your local time

How it behaves:

  • A file is only converted once it has been stable for AUTOMATED_CONVERSION_SOURCE_STABLE_TIME seconds, so a file still being copied in is never touched.
  • Output is written into the staging directory and only moved to its final place after HandBrakeCLI succeeds, so a media scanner watching /output never sees a half-written file. By default the staging directory is a hidden folder under the output root (<output>/.handbrake-staging). Map /staging to a cache pool and set AUTOMATED_CONVERSION_STAGING_DIR=/staging to keep the array out of the write path while a transcode runs. When staging and output are on different filesystems the finished file is copied to a hidden sibling inside the output folder first and then renamed, so the last step stays atomic.
  • If the staging directory cannot be written, the daemon says so loudly and refuses to convert anything instead of failing every file one by one. The GUI keeps working.
  • Processed sources are remembered in /config/handbrake/watch-state/done.list by path, size and mtime — an unchanged source is never converted twice, an edited or re-copied one is.
  • A failed job is recorded in failed.list and is not retried until the source changes. The full HandBrakeCLI output for every job is in /config/handbrake-watch.log.

7. Dark Mode

HANDBRAKE_THEME=dark (the default) applies HandBrake's own native GTK dark mode — the stock Adwaita dark theme that ships inside GTK 4, exactly what HandBrake uses on any Linux desktop set to dark. Nothing is repainted or restyled. HANDBRAKE_THEME=light switches to the light variant.

One consequence worth knowing: the container sets GTK_THEME, which GTK reads before it looks at any in-app preference. HandBrake's own light/dark toggle in the UI therefore has no visible effect here — HANDBRAKE_THEME is the single source of truth. Change it in the template and restart the container.


8. Hardware Encoding

Set GPU_VENDOR and pass the device through; the watch-folder converter then adds --encoder <hardware encoder> to every job. The GUI is unaffected and keeps its own encoder dropdown. This is the feature the Alpine-based community image has never been able to ship at all: NVIDIA's userspace libraries are glibc binaries that musl cannot load, so its NVENC request has been open since 2019. This image is Ubuntu-based, so the standard container runtimes just work.

GPU_VENDOR What you need on the host Works out of the box Verified by the maintainer
none (default) nothing ✅ software x264/x265
nvidia --runtime=nvidia, the Nvidia-Driver plugin ✅ real hardware, RTX 4070 Ti SUPER
intel /dev/dri passthrough, i915 or xe kernel driver known Ubuntu-packaging bug ✅ real hardware, bug found and fixed (handbrake:gpu-full)
amd /dev/dri passthrough, amdgpu kernel driver, a custom image, AMD's AMF runtime ❌ see below ❌ no AMD GPU here

The container never pretends. If the encoder you asked for is not usable it falls back to software and writes the reason into the container log, plus a full report to /config/handbrake-gpu.log.

NVIDIA NVENC

GPU_VENDOR=nvidia encodes every watch-folder job on an NVIDIA GPU using HandBrake's NVENC encoder instead of the CPU.

Status: developer-verified on real hardware (NVIDIA GeForce RTX 4070 Ti SUPER, Unraid).

What the host needs

Requirement Value
Unraid plugin Nvidia-Driver (ich777), from Community Applications
Extra Parameters --runtime=nvidia
NVIDIA_VISIBLE_DEVICES a GPU UUID from nvidia-smi -L on the host, or all
NVIDIA_DRIVER_CAPABILITIES compute,video,utility (or all)
GPU_VENDOR nvidia

NVIDIA_DRIVER_CAPABILITIES matters more than it looks: with the variable unset the NVIDIA runtime defaults to utility,compute, which does not include video — and video is the capability that injects libnvidia-encode.so.1, the library NVENC actually calls.

Plain Docker:

docker run -d \
  --name=handbrake \
  --runtime=nvidia \
  -e NVIDIA_VISIBLE_DEVICES=all \
  -e NVIDIA_DRIVER_CAPABILITIES=compute,video,utility \
  -e GPU_VENDOR=nvidia \
  -p 3000:3000 -p 3001:3001 \
  -e PUID=99 -e PGID=100 -e TZ=Europe/Vienna \
  -v /mnt/user/appdata/handbrake:/config \
  -v /mnt/user/media/watch:/watch \
  -v /mnt/user/media/converted:/output \
  --restart unless-stopped \
  ghcr.io/junkerderprovinz/handbrake:latest

What it changes

  • Watch-folder jobs only. GPU_VENDOR adds --encoder nvenc_h264 to every automated conversion. In the GUI you pick the encoder yourself — the NVENC entries appear in HandBrake's own encoder list as soon as the GPU is passed in.
  • H.264 by default, on purpose. The default preset is an x264 preset, so nvenc_h264 keeps the delivered codec identical and only swaps the encoder. For HEVC, set AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS=--encoder nvenc_h265 — custom args are appended last, so they win. nvenc_av1 and nvenc_av1_10bit are compiled in too (confirmed in docs/hardware-encoding-nvidia.md); the watch-folder seam does not pick AV1 automatically since not every player supports it yet, but --encoder nvenc_av1 works the same way.
  • A HandBrake hardware preset is left alone. If AUTOMATED_CONVERSION_PRESET already names an NVENC preset, the container does not override its encoder.
  • Speed presets. NVENC does not understand x264 speed names such as veryfast; HandBrake substitutes its own default. To control the tradeoff yourself, add --encoder-preset <name> to the custom args — the valid names are listed by docker exec handbrake HandBrakeCLI --encoder-preset-list nvenc_h264.
  • Hardware decoding (NVDEC) stays off. HandBrake disables hardware decoding as soon as any filter runs, and every stock preset crops or scales, so it would buy nothing by default. Force it with AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS=--enable-hw-decoding nvdec if your preset has no filters.

The measured details for this build, including the NVENC encoders it offers on a working GPU and the hardware evidence behind the "developer-verified" claim, are in docs/hardware-encoding-nvidia.md.

Intel Quick Sync (QSV)

Requirements on the host:

  • The iGPU or Arc card passed into the container. Unraid: add --device=/dev/dri to Extra Parameters. Plain Docker: --device /dev/dri.
  • The open-source i915 (or xe) kernel driver, which every current Linux kernel ships. No proprietary driver, no vendor container toolkit, nothing to install on the host.
docker run -d \
  --name=handbrake \
  --device /dev/dri \
  -e GPU_VENDOR=intel \
  ... \
  ghcr.io/junkerderprovinz/handbrake:latest

On the next start the log says which encoder was chosen:

[handbrake-gpu] Intel QSV enabled: --encoder qsv_h264 (render node /dev/dri/renderD128)

Important: the default image's QSV detection is correct, but the encode itself currently fails. This was measured on real Intel hardware (Intel UHD 770), not assumed: every conversion with the stock, apt-installed HandBrakeCLI fails at the muxing step with "Application provided invalid, non monotonically increasing dts to muxer". This is a confirmed bug in Ubuntu's specific packaged build of HandBrake, independently reproduced by another user on the identical environment (HandBrake/HandBrake#7962), not a bug in this container or in HandBrake itself.

The fix ships as an optional variant image. Build handbrake:gpu-full (Dockerfile.gpu, just build-gpu-full, 30-60 minutes on 8 cores, amd64 only, not published) — it rebuilds HandBrakeCLI from source with --enable-qsv, which fixes the bug completely. Verified end to end: a 180 s 1080p30 clip encodes in 12 s with qsv_h264 on this hardware (27 s in software on the same CPU), with no mux errors, and the output decodes cleanly. Full measured evidence is in docs/hardware-encoding-intel.md.

docker build -f Dockerfile.gpu -t handbrake:gpu-full .
docker run -d \
  --name=handbrake \
  --device /dev/dri \
  -e GPU_VENDOR=intel \
  ... \
  handbrake:gpu-full

Notes worth knowing:

  • The chosen encoder is qsv_h264, so the output codec matches what the default preset produces and stays as compatible as before. For HEVC, set AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS=--encoder qsv_h265; custom arguments are appended after the automatic ones and always win.
  • Hardware decoding is not enabled automatically. Add --enable-hw-decoding qsv to AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS if you want it.
  • Quality is preset-driven and the RF scale is not identical between x264 and QSV, so expect a different file size at the same nominal quality.
  • Quick Sync is x86-64 only. On arm64 the variable is accepted and ignored, with a log line saying so.
  • Which encoders your specific GPU generation actually supports (H.264/H.265 are broadly supported; AV1 needs a newer generation) is logged by HandBrake itself at the start of every job — see docs/hardware-encoding-intel.md section 2.

AMD VCE

Honest summary: the stock image cannot do AMD hardware encoding, and this is not something we can fix from inside the container. Setting GPU_VENDOR=amd is still worth doing, because it prints the exact reason and keeps converting in software:

[handbrake-gpu] WARNING: GPU_VENDOR=amd and /dev/dri/renderD128 exists, but HandBrakeCLI offers neither vce_h264 nor vaapi_h264 here.

Why:

  • HandBrake's AMD path on Linux is VCE through AMD's AMF framework. Ubuntu does not build HandBrake with --enable-vce, and upstream enables it by default only for Windows builds, so the packaged HandBrakeCLI contains no AMD encoder at all.
  • Even a rebuilt binary needs AMD's proprietary AMF runtime (libamfrt64.so.1, from the amf-amdgpu-pro package on repo.radeon.com). That library is not redistributable here, and AMD no longer ships AMF as part of the Linux driver stack. The last release covers RDNA1 and RDNA2 only (RX 5000 and RX 6000 series).
  • HandBrake 1.11 has no VA-API fallback for AMD. VA-API encoders exist in upstream's development branch, so this is expected to change; when a base image update brings them, this container picks them up automatically, because it asks HandBrake which encoders exist instead of hardcoding names.

If you have an RX 5000/6000 series card and want to try anyway:

  1. Install amf-amdgpu-pro on the host per AMD's instructions, and find the library: dpkg -L amf-amdgpu-pro | grep amfrt.
  2. Build the variant image (amd64 only, expect 30 to 60 minutes; also fixes Intel QSV, see above):
    docker build -f Dockerfile.gpu -t handbrake:gpu-full .
    
  3. Run it with the runtime mounted in and the device passed through:
    docker run -d \
      --name=handbrake \
      --device /dev/dri \
      -v /opt/amdgpu-pro/lib/x86_64-linux-gnu/libamfrt64.so.1:/usr/lib/x86_64-linux-gnu/libamfrt64.so.1:ro \
      -e GPU_VENDOR=amd \
      ... \
      handbrake:gpu-full
    
  4. Check the log for AMD hardware encoding enabled: --encoder vce_h264. If it is not there, /config/handbrake-gpu.log says which piece is missing.

One more caveat, because it has caught people out: on cards newer than RDNA2 the AMF runtime can report encoder capabilities and still encode on the CPU. If the transcode runs at software speed, that is what is happening; there is no fix available today other than waiting for HandBrake's VA-API encoders.

AMD VCE is unverified. There is no AMD GPU here to test the actual encode on — see the Community Verification section below.

What the container tells you

Every non-none GPU_VENDOR writes /config/handbrake-gpu.log on each start: the render nodes and their permissions, the groups the container user is in, the kernel driver behind each node, the encoders HandBrake really offers on your machine, and vainfo / vpl-inspect output.

docker exec handbrake cat /config/handbrake-gpu.log

That file is the first thing to read when hardware encoding does not engage, and the one thing to attach to a report.

The container never guesses an encoder name: at start-up it asks the bundled HandBrakeCLI which encoders it can actually use on your GPU and picks from that list, so a driver or GPU that cannot do the requested vendor is detected instead of assumed.

docker logs handbrake 2>&1 | grep '\[handbrake-gpu\]'
docker exec handbrake cat /run/handbrake/gpu-args    # empty means software encoding

Help us verify this (please)

AMD VCE in this image is implemented against AMD's and HandBrake's own documentation. It has not been verified on real hardware by the maintainer, because there is no AMD GPU here to test on. NVIDIA and Intel both have a card behind them now — see the table above. Every part that could be tested without AMD hardware has been: the runtime libraries are asserted in CI, the encoder selection logic is exercised in CI on GPU-less runners, and the fallback path is checked on both architectures.

What is missing is somebody with actual AMD hardware saying whether a file comes out the other end faster — and, since Intel Quick Sync varies a lot by GPU generation, a confirmation on hardware other than a Gen12/Xe iGPU (older Gen9-11, or a discrete Arc card) is useful too.

If you have an AMD Radeon, or Intel hardware other than a Gen12+ iGPU:

  1. Set GPU_VENDOR=amd (or intel with handbrake:gpu-full) and pass --device /dev/dri.
  2. Convert one file.
  3. Open a report with the hardware report form: Report your GPU result

Attach /config/handbrake-gpu.log and say whether it worked. A report that says "it does not work" is just as useful as one that says it does, and the log file usually contains the reason.


9. Conversion Hooks

Drop a shell script into /config/hooks/ and the watch-folder daemon runs it at the matching point. The folder is created on first start and always contains an up-to-date .example for each hook; copy one and remove the .example suffix to enable it. Hooks are executed with /bin/sh and their shebang is ignored, which is the same contract jlesage/handbrake uses, so scripts written for that image work here unchanged.

Hook When Arguments
pre_conversion.sh Before HandBrakeCLI starts on a file $1 output file, $2 source file, $3 preset
post_conversion.sh After every attempt, once the file has reached its final path $1 status (0 = success), $2 output file, $3 source file, $4 preset
post_watch_folder_processing.sh End of a scan pass that converted at least one file $1 watch folder
hb_custom_args.sh Just before HandBrakeCLI, to add per-file arguments $1 source file, $2 preset. Print the arguments on stdout

The same values are also in the environment, which is usually easier to read: HB_INPUT, HB_OUTPUT, HB_STATUS, HB_PRESET, HB_FORMAT, HB_WATCH_DIR.

Two behaviours worth knowing:

  • A non-zero exit from pre_conversion.sh refuses the file. The conversion is skipped and the source is recorded in failed.list, so it is not retried until the file itself changes. Every other hook's exit code is logged and otherwise ignored.
  • hb_custom_args.sh output is appended after AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS, so where both set the same flag the hook wins. This is also how to pick a quality setting per file, e.g. inspecting the source's resolution with ffprobe and printing --quality 22 for 1080p versus --quality 20 for 4K.

Everything a hook prints goes to /config/handbrake-watch.log.

A fifth hook, post_manual_conversion.sh, covers conversions you start yourself in the GUI, not just the watch-folder daemon. It rides on HandBrake's own "Send file to" preference (Preferences → When Done), which this image wires up automatically, so there is nothing to configure beyond copying the .example file. The contract is narrower, because it is genuinely all HandBrake's GUI hands over: $1 is the finished output file only, no source path, no preset, and it only fires on a successful encode. This wiring activates from the second container start onward — on a brand-new /config, HandBrake has not created its own preferences file yet on the first boot, and this image only ever patches an existing one rather than overwriting HandBrake's real defaults.


10. Web Desktop Features

Most of what other HandBrake images expose through their own variables comes straight from the Selkies desktop and needs no configuration at all.

Variable Default Description
WEB_FILE_MANAGER 1 Serves the data folders at https://<host>:3001/files/ for browsing, download and upload. 0 removes the endpoint and the sidebar panel
WEB_FILE_MANAGER_ALLOWED_PATHS AUTO AUTO publishes the watch folders, the output folder and /storage, whichever exist. Otherwise a comma-separated list of absolute paths
WEB_FILE_MANAGER_DENIED_PATHS empty Comma-separated paths inside the allowed ones that answer 403
WEB_TERMINAL 0 1 enables a terminal on the web desktop with Ctrl+Alt+T. 0 disables every terminal program in the container
WEB_TERMINAL_SHELL_PATH /bin/bash The shell that terminal opens
WEB_NOTIFICATION 0 1 shows a popup on the web desktop when a conversion finishes or fails

File manager. Upload a video in the browser and it lands in /watch, where the watch-folder daemon picks it up; browse /output and download the result without touching a share. /config is refused as an allowed path even if you ask for it explicitly, because it holds the WebUI's TLS private key. If you expose this container beyond your LAN, set CUSTOM_USER and PASSWORD.

Terminal. A keyboard shortcut rather than a separate web page: HandBrake's window is maximised, so the desktop's right-click menu cannot be reached. The terminal is a real window on the same desktop, streamed like everything else.

Notifications are shown by the desktop itself, in the corner of the HandBrake tab. They are not browser or operating-system notifications, so you see them while the tab is open rather than in the background. Their colours follow HANDBRAKE_THEME.

Clipboard works in both directions out of the box, no variable required. It needs the HTTPS port (3001): browsers only allow clipboard access on a secure origin. Firefox additionally blocks the silent clipboard read the web client uses on focus, which can lower-case pasted capitals; set dom.events.testing.asyncClipboard to true in about:config if you hit that.

Audio works out of the box as well, so there is no variable for it. The microphone path is switched off, since a transcoder has no use for one.

CJK fonts (Japanese, Korean, Chinese) are always installed. Nothing to enable, and filenames or subtitle tracks in those scripts render correctly everywhere in the UI.

HTTPS is always available on port 3001 with a self-signed certificate that is generated on first start and kept in /config/ssl.

Login is off by default and switched on by setting CUSTOM_USER and PASSWORD, which is the same pattern every container in this fleet uses.


11. Running More Than One Instance

Two independent containers, each with its own /config, watch folder and output folder, need nothing special: no path outside /config, /watch*, /output and /staging is shared, and everything else the container writes lives in its own /run.

Two containers sharing one watch folder to convert twice as many files at once also works. Each file is claimed with a lock directory in the watch folder, so exactly one container converts it. Some ground rules:

  • The watch folder must be writable by both containers. If it is read-only, locking is off, the log says so, and you must not point a second instance at it.
  • Give each container its own /config. The conversion bookkeeping is per container; the lock is what keeps them from colliding.
  • Give each container a distinct --hostname. A container only ever clears locks tagged with its own hostname on startup, so two containers sharing one hostname (e.g. copy-pasted into a second docker-compose service without changing it) could clear each other's in-progress lock. Docker's own default hostname (the container ID) is already unique; this only matters if you set hostname:/--hostname explicitly.
  • If both containers share one output folder, leave AUTOMATED_CONVERSION_OVERWRITE_OUTPUT=0 (the default). A file the other container already converted is then simply skipped.
  • Sharing one staging directory is fine. Every in-progress file carries the container's own tag, and on restart a container only cleans up its own leftovers.
  • If a container is killed hard, its lock is cleared automatically the next time it starts. To clear one by hand: rm -rf /path/to/watch/.handbrake-lock-* while no conversion is running.

12. Optical Drives

Unverified. The device plumbing is wired and the container is proven to run correctly when no drive is present, but no optical drive was available to test ripping end to end. Treat this section as best effort until somebody reports back. Reports very welcome.

Pass the drive in and HandBrake can use it as a source:

docker run -d \
  --name=handbrake \
  --device /dev/sr0 \
  -p 3000:3000 \
  -p 3001:3001 \
  -e PUID=99 \
  -e PGID=100 \
  -v /mnt/user/appdata/handbrake:/config \
  -v /mnt/user/media/converted:/output \
  --restart unless-stopped \
  ghcr.io/junkerderprovinz/handbrake:latest

In Unraid, add --device /dev/sr0 under Extra Parameters. The container adds itself to the group that owns the device automatically, so no permission changes on the host should be needed. Open the drive from the GUI with Open Source and browse to /dev/sr0.

ISO images, DVD folders containing VIDEO_TS and Blu-ray folders containing BDMV also work as ordinary sources, and .iso files dropped into a watch folder are picked up by the automatic converter like any other video.

Commercially encrypted DVDs are not supported: the container ships no decryption library, and adding one is out of scope for this image.


13. Migrating from jlesage/handbrake

  • Ports change: 5800/5900 become 3000 (HTTP) and 3001 (HTTPS). There is no direct VNC port — Selkies is the only access path, by design.
  • All AUTOMATED_CONVERSION* variables keep their names and defaults, so you can copy those values over unchanged.
  • /config/hooks/ keeps its name and its argument order, so existing hook scripts work without edits.
  • /config, /storage, /watch and /output keep their meaning, but the /config contents are not compatible: start with a fresh appdata folder and re-import your custom presets from the GUI.

Variables that changed, and why:

jlesage Here Note
USER_ID / GROUP_ID PUID / PGID The LinuxServer convention this image is built on
DARK_MODE=1 HANDBRAKE_THEME=dark Already the default
WEB_AUTHENTICATION, _USERNAME, _PASSWORD CUSTOM_USER, PASSWORD HTTP basic auth on the WebUI. WEB_AUTHENTICATION_TOKEN_VALIDITY_TIME has no counterpart: basic auth has no token to expire
SECURE_CONNECTION=1 (none) HTTPS on port 3001 is always available
WEB_HOST_CLIPBOARD_SYNC (none) Clipboard sync is always on
WEB_AUDIO (none) Browser audio is always on. The microphone is off, which a transcoder has no use for
ENABLE_CJK_FONT (none) CJK fonts are always installed
KEEP_APP_RUNNING (none) The GUI is always restarted if it exits
WEB_FILE_MANAGER*, WEB_TERMINAL*, WEB_NOTIFICATION same names See Web Desktop Features. WEB_FILE_MANAGER defaults to 1 here, and WEB_NOTIFICATION shows its popups on the web desktop rather than as browser notifications
VNC_PASSWORD, VNC_LISTENING_PORT, SECURE_CONNECTION_VNC_METHOD (none) There is no VNC port
AUTOMATED_CONVERSION_USE_TRASH, _TRASH_DIR (none) Not implemented. AUTOMATED_CONVERSION_KEEP_SOURCE=1 (the default) never deletes a source
AUTOMATED_CONVERSION_NON_VIDEO_FILE_ACTION, _NON_VIDEO_FILE_EXTENSIONS (none) Not implemented. Non-video files in a watch folder are ignored
AUTOMATED_CONVERSION_SOURCE_MIN_DURATION, _SOURCE_MAIN_TITLE_DETECTION (none) Not implemented. Disc sources convert their first title
AUTOMATED_CONVERSION_NO_GUI_PROGRESS (none) The watch daemon never draws in the GUI, so there is nothing to hide
INSTALL_PACKAGES, PACKAGES_MIRROR (none) Build a derived image instead

14. Building Locally

git clone https://github.com/junkerderprovinz/handbrake.git
cd handbrake
docker build -t handbrake:dev .
docker run -d --name hb -p 3000:3000 -p 3001:3001 handbrake:dev

just check runs the same lint chain as CI. just smoke builds and boots the image; just convert-test drops a generated clip into its watch folder.


15. Troubleshooting

The WebUI is black on the first start. The desktop is up before HandBrake has drawn its window. Wait for HANDBRAKE IS READY in docker logs handbrake.

Nothing in /watch gets converted. Check docker logs handbrake for [handbrake-watch] lines. The most common cause is a watch or output folder the container user cannot write — the init log says so explicitly: WARNING: watch folder /watch is NOT writable by the container user. Fix the share owner on the host (chown nobody:users /mnt/user/<share>).

A conversion failed. The full HandBrakeCLI output is in /config/handbrake-watch.log. The source is recorded in /config/handbrake/watch-state/failed.list and is not retried until the file changes; delete the line to retry it.

The UI is light although HANDBRAKE_THEME=dark. Confirm the variable reached the process:

docker exec handbrake sh -c 'cat /proc/$(pgrep -x ghb)/environ | tr "\0" "\n" | grep GTK_THEME'

It must print GTK_THEME=Adwaita:dark.

GPU_VENDOR=nvidia but the log says "no /dev/nvidia device node".* The container was not started through the NVIDIA runtime. Add --runtime=nvidia to Extra Parameters and set NVIDIA_VISIBLE_DEVICES to a UUID from nvidia-smi -L (Unraid needs the Nvidia-Driver plugin installed first). Conversions keep running in software until then.

The log says libnvidia-encode.so.1 is missing. The GPU is passed in but the driver capabilities are too narrow. Set NVIDIA_DRIVER_CAPABILITIES=compute,video,utility; the default of the NVIDIA runtime leaves video out, and video is what injects the encoder library.

The log says HandBrakeCLI "offers none of" the NVENC encoders. The GPU and the driver library are both there, but HandBrake itself will not use NVENC on this machine. HandBrake only lists a hardware encoder it can currently use, so the usual cause is an NVIDIA driver older than HandBrake's minimum — update the Nvidia-Driver plugin. The log line Encoders HandBrakeCLI offers here: shows exactly what it did find.

NVENC is on but the files are still slow. Check which encoder ran:

grep -i nvenc /mnt/user/appdata/handbrake/handbrake-watch.log | tail -n 5

If the job log names a software encoder, your preset is a hardware preset the container deliberately did not override, or your custom args set --encoder themselves — custom args are applied last and win.

/files/ is empty or returns 404. Check the startup log: docker logs handbrake 2>&1 | grep handbrake-web. Every published folder is listed there as /files/<name>/ -> <path>. A folder that is not mounted is not published. If a path was refused, the log says why.

A conversion never starts and the log mentions the staging directory. The staging directory is not writable. Fix the owner of the mapped host folder (chown nobody:users /mnt/user/<share>) or point AUTOMATED_CONVERSION_STAGING_DIR somewhere writable.

Ctrl+Alt+T does nothing. Confirm WEB_TERMINAL=1 and look for terminal keybind installed in docker logs handbrake. Some browser extensions capture the shortcut before the page sees it; try another browser or a private window.

A file in a shared watch folder is never converted. A lock left behind by a container that no longer exists blocks it. With no conversion running:

rm -rf /mnt/user/<watch-share>/.handbrake-lock-*

A hook does not run. It must be at /config/hooks/<name>.sh without the .example suffix, and readable by the container user. Its output and any error are in /config/handbrake-watch.log.

Which image am I actually running?

docker exec handbrake cat /etc/handbrake-build

16. License

This wrapper is AGPL-3.0-only (see LICENSE). HandBrake itself is GPL-2.0 and its artwork is CC BY-SA 4.0 — every bundled component and its licence is listed in NOTICE.


17. Support this project

Questions, bugs, ideas or feature requests? Please open a GitHub issue.

This is a one-person project. I put a lot of time and effort into building and maintaining it, in whatever free time I have. If it's helped you, I'd genuinely appreciate the support: you're welcome to buy me a coffee.

Buy me a coffee

Install HandBrake on Unraid in a few clicks.

Find HandBrake in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for HandBrake Review the template variables and paths Click Install

Download Statistics

2,720
Total Downloads

Related apps

Details

Repository
junkerderprovinz/handbrake:latest
Last Updated2026-08-16
First Seen2026-08-16

Runtime arguments

Web UI
https://[IP]:[PORT:3001]/
Network
bridge
Shell
bash
Privileged
false
Extra Params
--restart=unless-stopped --shm-size=1gb

Template configuration

WebUI Port (HTTPS / Selkies)Porttcp

HTTPS port of the Selkies WebUI (self-signed cert). This is the default WebUI — HTTPS is required for clipboard support in the browser. Accept the self-signed certificate once.

Target
3001
Default
3001
Value
3001
WebUI Port (HTTP / Selkies)Porttcp

HTTP port of the Selkies WebUI. For a reverse proxy that terminates TLS in front of the container — NOT for direct browser access. The Selkies web client requires a secure context, so opening http://IP:3000 directly shows a 'requires a secure connection (HTTPS)' error. For direct access use the HTTPS port 3001.

Target
3000
Default
3000
Value
3000
AppData (/config)Pathrw

Persistent HandBrake presets, queue, logs, container state, watch-folder bookkeeping and conversion hooks (/config/hooks).

Target
/config
Default
/mnt/user/appdata/handbrake
Value
/mnt/user/appdata/handbrake
Storage (/storage)Pathro

Media you want to browse from inside the GUI (read-only).

Target
/storage
Default
/mnt/user
Value
/mnt/user
Watch Folder (/watch)Pathrw

Anything dropped here is converted automatically.

Target
/watch
Default
/mnt/user/media/watch
Value
/mnt/user/media/watch
Output Folder (/output)Pathrw

Where converted files are written.

Target
/output
Default
/mnt/user/media/converted
Value
/mnt/user/media/converted
Watch Folder 2 (/watch2)Pathrw

Optional additional watch folder.

Target
/watch2
Watch Folder 3 (/watch3)Pathrw

Optional additional watch folder.

Target
/watch3
Watch Folder 4 (/watch4)Pathrw

Optional additional watch folder.

Target
/watch4
Watch Folder 5 (/watch5)Pathrw

Optional additional watch folder.

Target
/watch5
Staging Folder (/staging)Pathrw

Optional. Map this to a fast disk (e.g. a cache pool) and set 'Staging Directory' below to /staging to keep in-progress conversions off the array while they run.

Target
/staging
Theme (HANDBRAKE_THEME)Variable

HandBrake's own native GTK dark mode. 'dark' (default) or 'light'.

Target
HANDBRAKE_THEME
Default
dark|light
Value
dark
Keyboard Layout (KEYBOARD_LAYOUT)Variable

X keyboard layout loaded at session start (setxkbmap). Binds Shift so pasted UPPERCASE text keeps its case in the web desktop, and gives the correct symbols for your layout. Default 'us' suits most users.

Target
KEYBOARD_LAYOUT
Default
us|de|gb|fr|es|it|pt|nl|se|no|dk|fi|pl|cz|hu|ru|jp
Value
us
GPU Vendor (GPU_VENDOR)Variable

Hardware encoding vendor for every automated watch-folder conversion. 'nvidia' needs the NVIDIA Container Runtime (Extra Parameters: --runtime=nvidia) plus NVIDIA_DRIVER_CAPABILITIES=compute,video,utility. 'intel' and 'amd' need the GPU device passed through (Extra Parameters: --device /dev/dri). NVIDIA and Intel are verified on real hardware; AMD is wired but unverified (no AMD GPU to test on). A vendor that cannot be honoured logs exactly why and falls back to software encoding — check with: docker exec handbrake cat /config/handbrake-gpu.log

Target
GPU_VENDOR
Default
none|nvidia|intel|amd
Value
none
App Niceness (APP_NICENESS)Variable

nice level (0-19) applied to the GUI and every transcode. Higher = lower priority, leaves more CPU for other containers.

Target
APP_NICENESS
Default
0
Value
0
Automated Conversion (AUTOMATED_CONVERSION)Variable

1 = watch-folder conversion enabled (default), 0 = disable the daemon entirely.

Target
AUTOMATED_CONVERSION
Default
1|0
Value
1
Conversion Preset (AUTOMATED_CONVERSION_PRESET)Variable

HandBrake preset used for every automated conversion, as 'category/name'.

Target
AUTOMATED_CONVERSION_PRESET
Default
General/Very Fast 1080p30
Value
General/Very Fast 1080p30
Output Format (AUTOMATED_CONVERSION_FORMAT)Variable

Output container for automated conversions.

Target
AUTOMATED_CONVERSION_FORMAT
Default
mp4|mkv|webm
Value
mp4
Output Subdirectory (AUTOMATED_CONVERSION_OUTPUT_SUBDIR)Variable

Optional. A fixed subfolder under the output folder, or SAME_AS_SRC to mirror the source's own subfolder structure.

Target
AUTOMATED_CONVERSION_OUTPUT_SUBDIR
Keep Source (AUTOMATED_CONVERSION_KEEP_SOURCE)Variable

1 = keep the original file after conversion (default), 0 = delete it after a successful conversion.

Target
AUTOMATED_CONVERSION_KEEP_SOURCE
Default
1|0
Value
1
Overwrite Output (AUTOMATED_CONVERSION_OVERWRITE_OUTPUT)Variable

0 = skip a file if the output already exists (default), 1 = overwrite it.

Target
AUTOMATED_CONVERSION_OVERWRITE_OUTPUT
Default
0|1
Value
0
Video Extensions (AUTOMATED_CONVERSION_VIDEO_FILE_EXTENSIONS)Variable

Optional. Comma-separated list of file extensions to treat as video. Empty uses the built-in default list (mkv, mp4, avi, mov, wmv, and more).

Target
AUTOMATED_CONVERSION_VIDEO_FILE_EXTENSIONS
Ignore Directories (AUTOMATED_CONVERSION_IGNORE_DIRECTORIES)Variable

Optional. Space-separated directory names (e.g. sync-client metadata folders) pruned from every watch-folder scan, matched anywhere in the tree.

Target
AUTOMATED_CONVERSION_IGNORE_DIRECTORIES
Active Hours (AUTOMATED_CONVERSION_ACTIVE_HOURS)Variable

Optional. Restrict automated conversion to a daily window, HH-HH in 24h clock (e.g. 22-06 for overnight only). Empty means always active. Uses the container's TZ.

Target
AUTOMATED_CONVERSION_ACTIVE_HOURS
Staging Directory (AUTOMATED_CONVERSION_STAGING_DIR)Variable

Optional. Where in-progress conversions are written. Empty means a hidden folder under the output root. Set to /staging (map that path above to a cache pool) to keep the array out of the write path during a transcode.

Target
AUTOMATED_CONVERSION_STAGING_DIR
Source Stable Time (AUTOMATED_CONVERSION_SOURCE_STABLE_TIME)Variable

Seconds a source file must stop changing (size + mtime) before it is picked up, so a file still being copied in is never touched.

Target
AUTOMATED_CONVERSION_SOURCE_STABLE_TIME
Default
5
Value
5
Check Interval (AUTOMATED_CONVERSION_CHECK_INTERVAL)Variable

Seconds between watch-folder scans.

Target
AUTOMATED_CONVERSION_CHECK_INTERVAL
Default
5
Value
5
Max Watch Folders (AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS)Variable

How many numbered watch folders (/watch..N) to scan when the watch directory is left at AUTO.

Target
AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS
Default
5
Value
5
Custom HandBrakeCLI Args (AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS)Variable

Optional. Extra HandBrakeCLI arguments appended to every automated job, e.g. --encoder nvenc_h265 for HEVC instead of H.264.

Target
AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS
Web File Manager (WEB_FILE_MANAGER)Variable

1 = browse, upload and download the watch/output/storage folders at https://host:3001/files/ (default). 0 disables the endpoint entirely.

Target
WEB_FILE_MANAGER
Default
1|0
Value
1
File Manager Allowed Paths (WEB_FILE_MANAGER_ALLOWED_PATHS)Variable

AUTO publishes the watch folders, the output folder and /storage, whichever exist. Otherwise a comma-separated list of absolute paths. /config is always refused, since it holds the WebUI's TLS private key.

Target
WEB_FILE_MANAGER_ALLOWED_PATHS
Default
AUTO
Value
AUTO
File Manager Denied Paths (WEB_FILE_MANAGER_DENIED_PATHS)Variable

Optional. Comma-separated paths inside the allowed ones that must answer 403 instead of being browsable.

Target
WEB_FILE_MANAGER_DENIED_PATHS
Web Terminal (WEB_TERMINAL)Variable

1 enables a terminal on the web desktop with Ctrl+Alt+T. 0 (default) disables every terminal program in the container.

Target
WEB_TERMINAL
Default
0|1
Value
0
Web Terminal Shell (WEB_TERMINAL_SHELL_PATH)Variable

The shell the web terminal opens.

Target
WEB_TERMINAL_SHELL_PATH
Default
/bin/bash
Value
/bin/bash
Desktop Notifications (WEB_NOTIFICATION)Variable

1 shows a popup on the web desktop when a conversion finishes or fails. 0 (default) is off.

Target
WEB_NOTIFICATION
Default
0|1
Value
0
Optical Drive Permissions (ATTACHED_DEVICES_PERMS)Variable

Device glob the container is granted group access to for optical-drive ripping, e.g. /dev/sr*. Also pass the device itself under Extra Parameters, e.g. --device /dev/sr0. Unverified: no optical drive was available to test a rip end to end.

Target
ATTACHED_DEVICES_PERMS
Default
/dev/sr*
Value
/dev/sr*
WebUI UsernameVariable

Optional. Username for HTTP-basic-auth on the WebUI. Leave EMPTY together with the password for no login. Set both fields to enable login (recommended outside trusted LANs).

Target
CUSTOM_USER
WebUI PasswordVariable

Optional. Password for HTTP-basic-auth on the WebUI. Leave EMPTY together with the username for no login. STRONGLY recommended whenever the container is reachable from outside your LAN.

Target
PASSWORD
Timezone (TZ)Variable

Container timezone (affects log timestamps and file mtimes). Use this instead of a /etc/localtime bind-mount — the LSIO base image manages /etc/localtime internally via TZ.

Target
TZ
Default
Europe/Vienna|Africa/Abidjan|Africa/Accra|Africa/Addis_Ababa|Africa/Algiers|Africa/Asmera|Africa/Bamako|Africa/Bangui|Africa/Banjul|Africa/Bissau|Africa/Blantyre|Africa/Brazzaville|Africa/Bujumbura|Africa/Cairo|Africa/Casablanca|Africa/Ceuta|Africa/Conakry|Africa/Dakar|Africa/Dar_es_Salaam|Africa/Djibouti|Africa/Douala|Africa/El_Aaiun|Africa/Freetown|Africa/Gaborone|Africa/Harare|Africa/Johannesburg|Africa/Juba|Africa/Kampala|Africa/Khartoum|Africa/Kigali|Africa/Kinshasa|Africa/Lagos|Africa/Libreville|Africa/Lome|Africa/Luanda|Africa/Lubumbashi|Africa/Lusaka|Africa/Malabo|Africa/Maputo|Africa/Maseru|Africa/Mbabane|Africa/Mogadishu|Africa/Monrovia|Africa/Nairobi|Africa/Ndjamena|Africa/Niamey|Africa/Nouakchott|Africa/Ouagadougou|Africa/Porto-Novo|Africa/Sao_Tome|Africa/Tripoli|Africa/Tunis|Africa/Windhoek|America/Adak|America/Anchorage|America/Anguilla|America/Antigua|America/Araguaina|America/Argentina/La_Rioja|America/Argentina/Rio_Gallegos|America/Argentina/Salta|America/Argentina/San_Juan|America/Argentina/San_Luis|America/Argentina/Tucuman|America/Argentina/Ushuaia|America/Aruba|America/Asuncion|America/Bahia|America/Bahia_Banderas|America/Barbados|America/Belem|America/Belize|America/Blanc-Sablon|America/Boa_Vista|America/Bogota|America/Boise|America/Buenos_Aires|America/Cambridge_Bay|America/Campo_Grande|America/Cancun|America/Caracas|America/Catamarca|America/Cayenne|America/Cayman|America/Chicago|America/Chihuahua|America/Ciudad_Juarez|America/Coral_Harbour|America/Cordoba|America/Costa_Rica|America/Coyhaique|America/Creston|America/Cuiaba|America/Curacao|America/Danmarkshavn|America/Dawson|America/Dawson_Creek|America/Denver|America/Detroit|America/Dominica|America/Edmonton|America/Eirunepe|America/El_Salvador|America/Fort_Nelson|America/Fortaleza|America/Glace_Bay|America/Godthab|America/Goose_Bay|America/Grand_Turk|America/Grenada|America/Guadeloupe|America/Guatemala|America/Guayaquil|America/Guyana|America/Halifax|America/Havana|America/Hermosillo|America/Indiana/Knox|America/Indiana/Marengo|America/Indiana/Petersburg|America/Indiana/Tell_City|America/Indiana/Vevay|America/Indiana/Vincennes|America/Indiana/Winamac|America/Indianapolis|America/Inuvik|America/Iqaluit|America/Jamaica|America/Jujuy|America/Juneau|America/Kentucky/Monticello|America/Kralendijk|America/La_Paz|America/Lima|America/Los_Angeles|America/Louisville|America/Lower_Princes|America/Maceio|America/Managua|America/Manaus|America/Marigot|America/Martinique|America/Matamoros|America/Mazatlan|America/Mendoza|America/Menominee|America/Merida|America/Metlakatla|America/Mexico_City|America/Miquelon|America/Moncton|America/Monterrey|America/Montevideo|America/Montserrat|America/Nassau|America/New_York|America/Nome|America/Noronha|America/North_Dakota/Beulah|America/North_Dakota/Center|America/North_Dakota/New_Salem|America/Ojinaga|America/Panama|America/Paramaribo|America/Phoenix|America/Port-au-Prince|America/Port_of_Spain|America/Porto_Velho|America/Puerto_Rico|America/Punta_Arenas|America/Rankin_Inlet|America/Recife|America/Regina|America/Resolute|America/Rio_Branco|America/Santarem|America/Santiago|America/Santo_Domingo|America/Sao_Paulo|America/Scoresbysund|America/Sitka|America/St_Barthelemy|America/St_Johns|America/St_Kitts|America/St_Lucia|America/St_Thomas|America/St_Vincent|America/Swift_Current|America/Tegucigalpa|America/Thule|America/Tijuana|America/Toronto|America/Tortola|America/Vancouver|America/Whitehorse|America/Winnipeg|America/Yakutat|Antarctica/Casey|Antarctica/Davis|Antarctica/DumontDUrville|Antarctica/Macquarie|Antarctica/Mawson|Antarctica/McMurdo|Antarctica/Palmer|Antarctica/Rothera|Antarctica/Syowa|Antarctica/Troll|Antarctica/Vostok|Arctic/Longyearbyen|Asia/Aden|Asia/Almaty|Asia/Amman|Asia/Anadyr|Asia/Aqtau|Asia/Aqtobe|Asia/Ashgabat|Asia/Atyrau|Asia/Baghdad|Asia/Bahrain|Asia/Baku|Asia/Bangkok|Asia/Barnaul|Asia/Beirut|Asia/Bishkek|Asia/Brunei|Asia/Calcutta|Asia/Chita|Asia/Colombo|Asia/Damascus|Asia/Dhaka|Asia/Dili|Asia/Dubai|Asia/Dushanbe|Asia/Famagusta|Asia/Gaza|Asia/Hebron|Asia/Hong_Kong|Asia/Hovd|Asia/Irkutsk|Asia/Jakarta|Asia/Jayapura|Asia/Jerusalem|Asia/Kabul|Asia/Kamchatka|Asia/Karachi|Asia/Katmandu|Asia/Khandyga|Asia/Krasnoyarsk|Asia/Kuala_Lumpur|Asia/Kuching|Asia/Kuwait|Asia/Macau|Asia/Magadan|Asia/Makassar|Asia/Manila|Asia/Muscat|Asia/Nicosia|Asia/Novokuznetsk|Asia/Novosibirsk|Asia/Omsk|Asia/Oral|Asia/Phnom_Penh|Asia/Pontianak|Asia/Pyongyang|Asia/Qatar|Asia/Qostanay|Asia/Qyzylorda|Asia/Rangoon|Asia/Riyadh|Asia/Saigon|Asia/Sakhalin|Asia/Samarkand|Asia/Seoul|Asia/Shanghai|Asia/Singapore|Asia/Srednekolymsk|Asia/Taipei|Asia/Tashkent|Asia/Tbilisi|Asia/Tehran|Asia/Thimphu|Asia/Tokyo|Asia/Tomsk|Asia/Ulaanbaatar|Asia/Urumqi|Asia/Ust-Nera|Asia/Vientiane|Asia/Vladivostok|Asia/Yakutsk|Asia/Yekaterinburg|Asia/Yerevan|Atlantic/Azores|Atlantic/Bermuda|Atlantic/Canary|Atlantic/Cape_Verde|Atlantic/Faeroe|Atlantic/Madeira|Atlantic/Reykjavik|Atlantic/South_Georgia|Atlantic/St_Helena|Atlantic/Stanley|Australia/Adelaide|Australia/Brisbane|Australia/Broken_Hill|Australia/Darwin|Australia/Eucla|Australia/Hobart|Australia/Lindeman|Australia/Lord_Howe|Australia/Melbourne|Australia/Perth|Australia/Sydney|Europe/Amsterdam|Europe/Andorra|Europe/Astrakhan|Europe/Athens|Europe/Belgrade|Europe/Berlin|Europe/Bratislava|Europe/Brussels|Europe/Bucharest|Europe/Budapest|Europe/Busingen|Europe/Chisinau|Europe/Copenhagen|Europe/Dublin|Europe/Gibraltar|Europe/Guernsey|Europe/Helsinki|Europe/Isle_of_Man|Europe/Istanbul|Europe/Jersey|Europe/Kaliningrad|Europe/Kiev|Europe/Kirov|Europe/Lisbon|Europe/Ljubljana|Europe/London|Europe/Luxembourg|Europe/Madrid|Europe/Malta|Europe/Mariehamn|Europe/Minsk|Europe/Monaco|Europe/Moscow|Europe/Oslo|Europe/Paris|Europe/Podgorica|Europe/Prague|Europe/Riga|Europe/Rome|Europe/Samara|Europe/San_Marino|Europe/Sarajevo|Europe/Saratov|Europe/Simferopol|Europe/Skopje|Europe/Sofia|Europe/Stockholm|Europe/Tallinn|Europe/Tirane|Europe/Ulyanovsk|Europe/Vaduz|Europe/Vatican|Europe/Vilnius|Europe/Volgograd|Europe/Warsaw|Europe/Zagreb|Europe/Zurich|Indian/Antananarivo|Indian/Chagos|Indian/Christmas|Indian/Cocos|Indian/Comoro|Indian/Kerguelen|Indian/Mahe|Indian/Maldives|Indian/Mauritius|Indian/Mayotte|Indian/Reunion|Pacific/Apia|Pacific/Auckland|Pacific/Bougainville|Pacific/Chatham|Pacific/Easter|Pacific/Efate|Pacific/Enderbury|Pacific/Fakaofo|Pacific/Fiji|Pacific/Funafuti|Pacific/Galapagos|Pacific/Gambier|Pacific/Guadalcanal|Pacific/Guam|Pacific/Honolulu|Pacific/Kiritimati|Pacific/Kosrae|Pacific/Kwajalein|Pacific/Majuro|Pacific/Marquesas|Pacific/Midway|Pacific/Nauru|Pacific/Niue|Pacific/Norfolk|Pacific/Noumea|Pacific/Pago_Pago|Pacific/Palau|Pacific/Pitcairn|Pacific/Ponape|Pacific/Port_Moresby|Pacific/Rarotonga|Pacific/Saipan|Pacific/Tahiti|Pacific/Tarawa|Pacific/Tongatapu|Pacific/Truk|Pacific/Wake|Pacific/Wallis
Value
Europe/Vienna
User ID (PUID)Variable

User-ID HandBrake runs as. Default 99 (nobody on Unraid).

Target
PUID
Default
99
Value
99
Group ID (PGID)Variable

Group-ID. Default 100 (users on Unraid).

Target
PGID
Default
100
Value
100
UMASKVariable

Permission mask for newly created files. Use 000 if you want every container user to read/write everything.

Default
022|000|002|077
Value
022