Install Finetic with Docker Compose
Deploy Finetic with the maintained Docker Compose stack, persistent PostgreSQL and application volumes, read-only media, GPU acceleration, reverse proxies, upgrades and tested disaster recovery.
What the official stack includes#
Finetic's maintained Docker deployment runs the compiled server beside PostgreSQL 15. It is intended for Linux Docker hosts, Unraid, TrueNAS SCALE, Proxmox guests, Synology, QNAP and existing Compose environments.
The published image supports Linux amd64 and arm64. It contains Node.js 24 and Debian 12's FFmpeg/FFprobe 5.1 generation. The maintained Compose file pins the database to postgres:15-alpine. Those are the tested Docker versions; do not change PostgreSQL major versions as part of an ordinary application update.
Quick installation#
Install Docker Engine and the Docker Compose v2 plugin using your operating system or appliance, then download and inspect the bootstrap script:
curl -fsSLO https://youngstudio.uk/downloads/install-finetic-docker.sh
less install-finetic-docker.sh
bash install-finetic-docker.sh
The script creates a finetic-docker directory, downloads the maintained Compose files, generates a random PostgreSQL password, records your numeric user and group IDs, creates a media directory and starts the stable image.
Open the APP_URL recorded in finetic-docker/.env. A new installation can begin the complete 30-day trial with an email address. No card or pre-issued key is required. If you already received an installation key, use it instead.
Persistent volumes#
The Compose stack keeps durable data outside the application container:
| Volume | What it stores | Recovery rule |
|---|---|---|
finetic-database | PostgreSQL operational, catalogue, history, telemetry and scheduling data | Back up with pg_dump |
finetic-configuration | Installation identity, accounts, configuration, sessions and entitlement state | Archive while Finetic is stopped |
finetic-artwork | Downloaded and generated artwork | Archive for a complete recovery point |
finetic-cache | HLS fragments, keyframes and regenerable cache data | Optional |
finetic-backups | Backups created through Finetic | Copy off-host |
Recreating or replacing a container preserves these named volumes. docker compose down -v deletes them and must not be part of an upgrade.
Read-only media#
The maintained stack maps one host media root to /media read-only:
MEDIA_PATH=/mnt/media
Choose /media/Movies, /media/TV Shows or narrower child paths in the graphical library browser. Keeping media read-only prevents an application or container fault from modifying the source library.
Confirm the boundary:
docker compose -f finetic-compose.yaml exec finetic find /media -maxdepth 2 -type f | head
docker compose -f finetic-compose.yaml exec finetic sh -c 'touch /media/should-fail'
The write test should fail with Read-only file system.
UID and GID permissions#
Finetic drops from the container entrypoint to the numeric PUID:PGID before Node.js starts. Set those values to a host account that can read and traverse the media folders:
id
stat -c '%u:%g %A %n' /mnt/media
PUID=1000
PGID=1000
The account needs read permission on media files and read/execute permission on every directory in their paths. It does not need write access. NAS ACLs still apply even when ordinary UNIX mode bits look correct.
NFS and SMB shares#
Mount a network share on the Docker host, verify it, and only then bind it into Finetic. This keeps storage credentials outside the application container.
NFS /etc/fstab example:
nas.example.lan:/media /mnt/media nfs4 ro,_netdev,nofail,x-systemd.automount,x-systemd.device-timeout=30s 0 0
SMB /etc/fstab example using a root-readable credentials file:
//nas.example.lan/media /mnt/media cifs ro,_netdev,nofail,x-systemd.automount,credentials=/root/.smb-finetic,uid=1000,gid=1000,file_mode=0440,dir_mode=0550,vers=3.1.1 0 0
Run findmnt /mnt/media and list a few files before starting Finetic. If the mount is unavailable, restore it before scanning. Finetic treats missing configured roots as unavailable storage rather than as evidence that every title was deleted.
Intel and AMD acceleration#
Intel Quick Sync and Intel/AMD VAAPI use the maintained VAAPI override. Find the host's actual group IDs:
getent group video
getent group render
ls -l /dev/dri
Record them in .env, then apply both Compose files:
VIDEO_GID=44
RENDER_GID=109
docker compose -f finetic-compose.yaml -f finetic-compose-vaapi.yaml up -d --wait
docker compose -f finetic-compose.yaml -f finetic-compose-vaapi.yaml exec finetic vainfo
Group IDs vary. On a Proxmox LXC, the GPU device and its groups must first be delegated to the Docker guest.
NVIDIA acceleration#
Install a compatible NVIDIA driver and NVIDIA Container Toolkit on the host. Prove GPU access independently, then apply the NVIDIA override:
docker run --rm --gpus all nvidia/cuda:12.6.3-base-ubuntu24.04 nvidia-smi
docker compose -f finetic-compose.yaml -f finetic-compose-nvidia.yaml up -d --wait
docker compose -f finetic-compose.yaml -f finetic-compose-nvidia.yaml exec finetic ffmpeg -hide_banner -hwaccels
A detected backend is not proof of correct playback. Verify a real stream in Admin → Playback & Transcoding and inspect whether the hardware path was actually selected.
Reverse proxy examples#
Set APP_URL to the exact HTTPS address used by clients. Leave TRUST_PROXY empty for direct LAN access; behind a proxy, set it only to the trusted proxy hop, address or CIDR.
Nginx starting point:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_request_buffering off;
proxy_buffering off;
proxy_read_timeout 3600s;
}
Caddy starting point:
media.example.com {
reverse_proxy 127.0.0.1:3000
}
Do not strip /api, rewrite HLS paths, cache private JSON, decompress ranges or buffer live event streams. Use Admin → Remote Access after setup to verify DNS, certificate trust, the exact Finetic route, seeking ranges, HLS, WebSockets and safe guest routing from outside the home.
Health and startup order#
PostgreSQL must pass pg_isready before Finetic starts. The Finetic entrypoint also waits up to 60 seconds for the configured database. The application health check calls /api/app/version every 15 seconds.
docker compose -f finetic-compose.yaml ps
docker compose -f finetic-compose.yaml exec database pg_isready -U finetic -d finetic
curl -fsS http://127.0.0.1:3000/api/app/version
The PostgreSQL network is internal and has no published host port. Finetic publishes only the configured application port. Both services use restart: unless-stopped and no-new-privileges.
Upgrade#
Docker installations use external orchestration. The Software Updates page can explain that a release exists, but Finetic never receives the Docker socket and cannot replace itself.
cd finetic-docker
docker compose -f finetic-compose.yaml pull
docker compose -f finetic-compose.yaml up -d --wait
docker compose -f finetic-compose.yaml logs --tail=100 finetic
Create a recovery point first. Never add -v to the down command during an upgrade.
Version pinning and rollback#
For controlled rollout, set an exact released version in .env:
FINETIC_IMAGE=ghcr.io/360john360/finetic:0.1.49
Use the version from the release history rather than copying this example. To roll the application back, select the previous known-good tag, then run:
docker compose -f finetic-compose.yaml pull finetic
docker compose -f finetic-compose.yaml up -d --no-deps --wait finetic
docker compose -f finetic-compose.yaml logs --tail=150 finetic
If a release changed the database schema incompatibly, restore the matching pre-upgrade database backup rather than running an old application against a newer schema.
Complete backup#
Finetic's Backup & Restore page creates verified archives in the backup volume. Copy those off-host. A complete container recovery point also includes a logical PostgreSQL dump and the configuration, artwork and backup volumes.
cd finetic-docker
mkdir -p backup-$(date +%F)
BACKUP_DIR="$PWD/backup-$(date +%F)"
docker compose -f finetic-compose.yaml stop finetic
docker compose -f finetic-compose.yaml exec -T database \
pg_dump -U finetic -d finetic --no-owner --no-privileges \
| gzip > "$BACKUP_DIR/database.sql.gz"
for volume in configuration artwork backups; do
docker run --rm --user 0 --entrypoint sh \
-v "finetic_finetic-$volume:/data:ro" \
-v "$BACKUP_DIR:/backup" \
postgres:15-alpine \
-c "tar -C /data -czf /backup/$volume.tgz ."
done
docker compose -f finetic-compose.yaml start finetic
sha256sum "$BACKUP_DIR"/* > "$BACKUP_DIR/SHA256SUMS"
The cache volume is intentionally omitted because it can be regenerated.
Restore after container and volume recreation#
This procedure deletes the target stack's data. Confirm the backup and keep it outside Docker volumes:
cd finetic-docker
BACKUP_DIR=/absolute/path/to/backup
sha256sum -c "$BACKUP_DIR/SHA256SUMS"
docker compose -f finetic-compose.yaml down -v
docker compose -f finetic-compose.yaml create database finetic
for volume in configuration artwork backups; do
docker run --rm --user 0 --entrypoint sh \
-v "finetic_finetic-$volume:/data" \
-v "$BACKUP_DIR:/backup:ro" \
postgres:15-alpine \
-c "tar -C /data -xzf /backup/$volume.tgz"
done
docker compose -f finetic-compose.yaml up -d database --wait
gzip -dc "$BACKUP_DIR/database.sql.gz" \
| docker compose -f finetic-compose.yaml exec -T database psql -U finetic -d finetic
docker compose -f finetic-compose.yaml up -d finetic --wait
Verify the installation identity, subscription, account login, libraries, artwork, watch state and one playback path before removing the recovery point.
What was directly tested#
On 20 July 2026, this stack was tested in a disposable Proxmox LXC using Docker Engine 26.1.5 and Compose 2.26.1. The validation covered a clean compiled-only image build, PostgreSQL-dependent health, runtime UID/GID, read-only media, absence of TypeScript and source maps, signed 30-day trial activation, application-container replacement, and a complete PostgreSQL plus persistent-volume restore after deleting the disposable containers and volumes.
The image reported Node.js 24.18.0, FFmpeg 5.1.9 and PostgreSQL client/server 15.18. GPU Compose mappings are supplied, but actual encode/decode success depends on the host, driver and passed-through hardware and must be verified on that device.