16 Commits

Author SHA1 Message Date
benvin 26d399b8d5 Merge pull request 'Bake LDAP + SSO auth plugins into the image' (#8) from benvin/auth-plugins into main
ci/woodpecker/tag/docker Pipeline was successful
Reviewed-on: #8
2026-08-29 12:03:44 +10:00
unkin-agent ac61265ea0 Route LDAP plugin through artifactapi remote for secure image builds.
ci/woodpecker/pr/build Pipeline was successful
Replace direct repo.jellyfin.org download with artifactapi.k8s.syd1.au.unkin.net
remote. SHA256 pin guarantees integrity over HTTP. Both plugins now consistent
in sourcing from artifactapi infrastructure.
2026-08-29 12:00:03 +10:00
unkin-agent 72290bbacd fix(ci): pull SSO plugin via artifactapi github proxy
ci/woodpecker/pr/build Pipeline failed
The PR build failed at the plugins stage: the CI build network can reach
artifactapi and package mirrors (repo.jellyfin.org) but not github.com
directly, so the SSO plugin download from github failed (curl exit 7).
Route the SSO fetch through the artifactapi github remote proxy instead;
SSO_SHA256 still pins the exact bytes. LDAP is unchanged.
2026-08-26 23:28:56 +10:00
unkin-agent 2001204e0b Bake LDAP + SSO auth plugins into the image
ci/woodpecker/pr/build Pipeline failed
Phase-1 SSO/app-passwords for jellyfin needs the ldapauth and sso plugins
present without relying on the in-app catalog (which the plugins-baked PVC
would otherwise let drift). Pin the newest release of each whose targetAbi
is <= the pinned server version (10.11.6) and let the image own the version.

- Add a plugins build stage that downloads, sha256-verifies (matching each
  release's published .sha256), and unpacks the plugin zips into versioned
  dirs baked at /usr/share/jellyfin/plugins-baked.
- LDAP Authentication 22.0.0.0 (targetAbi 10.11.2.0; v23 needs 10.11.9).
- SSO Authentication 4.0.0.4 (targetAbi 10.11.0.0).
- Add docker-entrypoint.sh that syncs baked plugin dirs into /config/plugins
  on every start, removing any stale versioned dir of the same plugin so the
  image controls the version across restarts; preserves plugin configurations.
- Point ENTRYPOINT at the new script.
2026-08-26 22:13:40 +10:00
benvin 4a4965921f Merge pull request 'fix: align runtime image .NET to the app (9.0)' (#7) from benvin/jellyfin-dotnet9 into main
ci/woodpecker/tag/docker Pipeline was successful
Reviewed-on: #7
2026-08-15 18:44:51 +10:00
unkin-agent c7409d0812 fix: align runtime image .NET to the app (9.0)
ci/woodpecker/pr/build Pipeline was successful
The runtime image based on aspnet:10.0 provides only .NET 10.x, but the
publish step builds framework-dependent against SDK 9.0, so the app requires
Microsoft.NETCore.App 9.0.0 and crashes on start under 10.x.

Pin the runtime base to aspnet:9.0 to match the SDK 9.0 publish.
2026-08-15 18:40:05 +10:00
benvin 248027aaea Merge pull request 'ci: use CA-baked plugin-docker-buildx image for artifactapi push' (#6) from benvin/jellyfin-buildx-plugin-image into main
ci/woodpecker/tag/docker Pipeline was successful
Reviewed-on: #6
2026-08-15 18:20:05 +10:00
unkin-agent 0020ee2a58 ci: use CA-baked plugin-docker-buildx image for artifactapi push
ci/woodpecker/pr/build Pipeline was successful
Point the release docker step at the custom
artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx
image, which bakes artifactapi's internal Vault CA into
/etc/docker/certs.d/<registry>/ca.crt.

- Swap the docker step image from upstream woodpeckerci/plugin-docker-buildx
  to the CA-baked custom image.
- Drop the separate ca-trust step (and its almalinux9-base dependency) that
  staged the CA into the workspace.
- Repoint buildkit_config ca= at the in-image baked CA path so the buildx
  docker-container builder still hands the CA to buildkitd for the push.
2026-08-15 18:06:11 +10:00
benvin b1470f3158 Merge pull request 'ci: trust artifactapi internal CA when pushing docker-internal' (#5) from benvin/jellyfin-buildkit-ca into main
ci/woodpecker/tag/docker Pipeline failed
Reviewed-on: #5
2026-08-15 16:42:06 +10:00
unkin-agent ec04b35b39 ci: trust artifactapi internal CA when pushing docker-internal
ci/woodpecker/pr/build Pipeline was successful
The v0.1.0 release pipeline built the runtime image fine but failed the
push to artifactapi.k8s.syd1.au.unkin.net/docker-internal with a TLS
x509 unknown-authority error: buildkit did not trust artifactapi's
Vault-signed cert.

Stage the internal CA into the shared workspace via the almalinux9-base
image (already trusts the unkin CA; same image the RPM release pipelines
use to reach artifactapi over HTTPS) and point the docker-buildx plugin
at it through buildkit_config. buildx copies the referenced CA into the
buildkitd container at builder-create time, so the push handshake now
verifies. No credentials needed: anonymous push to docker-internal is
allowed for trusted clients.
2026-08-15 16:34:44 +10:00
benvin a369c49457 Merge pull request 'build: source release image from fork main (scan-leader)' (#4) from benvin/upstream-ref-scanleader into main
ci/woodpecker/tag/docker Pipeline failed
Reviewed-on: #4
2026-08-12 00:30:32 +10:00
unkinben 8738315c52 build: bump UPSTREAM_REF to fork main with scan-leader
ci/woodpecker/pr/build Pipeline was successful
2026-08-11 22:03:13 +10:00
benvin ac507021f3 Merge pull request 'build: container build from the unkin jellyfin-ha-src fork' (#3) from benvin/jellyfin-ha-build into main
Reviewed-on: #3
2026-08-11 21:13:46 +10:00
unkinben 26e57c8655 ci: pin .NET SDK image to 9.0 to match global.json
ci/woodpecker/pr/build Pipeline was successful
The pinned jellyfin-ha-src fork sets global.json sdk 9.0.0 (rollForward
latestMinor), so the publish steps in build.yaml and docker.yaml must run
on the .NET 9 SDK. They referenced sdk:10.0, which fails the pinned build.
Repoint both publish steps to mcr.microsoft.com/dotnet/sdk:9.0.
2026-08-11 20:41:43 +10:00
unkinben 9f8d9014d3 build: source from the unkin jellyfin-ha-src fork
Why:
- The build should pull from our own source fork so local HA patches can be
  carried and pinned, rather than cloning the upstream GitHub tree directly.

How:
- Point the clone URL in the Makefile and both Woodpecker pipelines at
  https://git.unkin.net/unkin/jellyfin-ha-src.git.
- Keep UPSTREAM_REF at d4f9c12c22d3a640f3b0a3622b23b8cd01d044ad, which is the
  seeded fork main, so the produced image is byte-identical for now; the
  feature bump is a later change.
2026-08-11 07:25:03 +10:00
unkinben 84f9158e9b ci: push images to artifactapi registry instead of gitea
Hard switch of the docker push target from the Gitea registry to the
artifactapi local docker registry (docker-internal); the Gitea VM and its
registry are being retired. Drops the droneci/DRONECI_PASSWORD creds since
artifactapi accepts unauthenticated in-cluster pushes. Also repoints the Makefile IMAGE and README image paths.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-30 00:34:59 +10:00
7 changed files with 95 additions and 24 deletions
+3 -3
View File
@@ -5,11 +5,11 @@ steps:
# Clone the pinned upstream jellyfin-ha source and publish the .NET server
# into ./publish-output (consumed by Dockerfile.runtime).
- name: publish
image: mcr.microsoft.com/dotnet/sdk:10.0
image: mcr.microsoft.com/dotnet/sdk:9.0
commands:
- |
REF=$$(cat UPSTREAM_REF)
git clone https://github.com/ZoltyMat/jellyfin-ha.git src
git clone https://git.unkin.net/unkin/jellyfin-ha-src.git src
git -C src checkout "$$REF"
dotnet publish src/Jellyfin.Server/Jellyfin.Server.csproj \
-c Release -r linux-x64 --self-contained false -o ./publish-output
@@ -28,7 +28,7 @@ steps:
- name: docker-build
image: woodpeckerci/plugin-docker-buildx
settings:
repo: git.unkin.net/unkin/jellyfin-ha
repo: artifactapi.k8s.syd1.au.unkin.net/docker-internal/jellyfin-ha
dockerfile: Dockerfile.runtime
dry_run: true
depends_on: [publish]
+14 -9
View File
@@ -5,11 +5,11 @@ when:
steps:
# Same publish step as the PR pipeline: clone pinned upstream + dotnet publish.
- name: publish
image: mcr.microsoft.com/dotnet/sdk:10.0
image: mcr.microsoft.com/dotnet/sdk:9.0
commands:
- |
REF=$$(cat UPSTREAM_REF)
git clone https://github.com/ZoltyMat/jellyfin-ha.git src
git clone https://git.unkin.net/unkin/jellyfin-ha-src.git src
git -C src checkout "$$REF"
dotnet publish src/Jellyfin.Server/Jellyfin.Server.csproj \
-c Release -r linux-x64 --self-contained false -o ./publish-output
@@ -24,16 +24,21 @@ steps:
memory: 6Gi
cpu: 4
# Build the runtime image and push it to the Gitea registry.
# Build the runtime image and push it to the artifactapi local docker registry.
# The plugin image bakes artifactapi's internal (Vault) CA at
# /etc/docker/certs.d/<registry>/ca.crt; buildkit_config points the buildx
# docker-container builder at that in-image CA. buildkitd runs in its own
# container and performs the push, so it needs the CA via --config even though
# the plugin image already trusts it — buildx copies the referenced file in.
- name: docker
image: woodpeckerci/plugin-docker-buildx
image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx:latest
settings:
registry: git.unkin.net
repo: git.unkin.net/unkin/jellyfin-ha
registry: artifactapi.k8s.syd1.au.unkin.net
repo: artifactapi.k8s.syd1.au.unkin.net/docker-internal/jellyfin-ha
dockerfile: Dockerfile.runtime
username: droneci
password:
from_secret: DRONECI_PASSWORD
buildkit_config: |
[registry."artifactapi.k8s.syd1.au.unkin.net"]
ca = ["/etc/docker/certs.d/artifactapi.k8s.syd1.au.unkin.net/ca.crt"]
tags:
- ${CI_COMMIT_TAG}
- latest
+42 -5
View File
@@ -21,8 +21,45 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends "jellyfin-web=10.11.6+deb12" \
&& rm -rf /var/lib/apt/lists/*
# ── Plugin stage ──────────────────────────────────────────────────────────────
# Download and verify the auth plugins, unpacked into versioned dirs baked into
# the image and synced into /config/plugins at start (docker-entrypoint.sh).
# Versions are the newest each plugin publishes whose targetAbi <= the pinned
# Jellyfin server version (10.11.6):
# LDAP Authentication 22.0.0.0 targetAbi 10.11.2.0 (v23 needs 10.11.9)
# SSO Authentication 4.0.0.4 targetAbi 10.11.0.0
# sha256 pins match each release's published .sha256 asset for reproducibility.
FROM --platform=linux/amd64 debian:bookworm-slim AS plugins
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates unzip \
&& rm -rf /var/lib/apt/lists/*
ARG LDAP_URL=http://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/jellyfin/files/plugin/ldap-authentication/ldap-authentication_22.0.0.0.zip
ARG LDAP_SHA256=c2386c001be439c9946280a02d62610f29e325d4094e83bd31221de3f7aa20ae
# LDAP is served through artifactapi remote. SSO is served through the artifactapi
# github proxy, which the CI build network can reach (github is not directly reachable).
# SHA256 pins match each release's published asset for reproducibility and integrity.
ARG SSO_URL=http://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/github/9p4/jellyfin-plugin-sso/releases/download/v4.0.0.4/sso-authentication_4.0.0.4.zip
ARG SSO_SHA256=c09f16ba31059a434ddd7f811e4f9608d4b4c4514cc80a5bf1ca33bee61e1107
WORKDIR /plugins
RUN set -eu; \
curl -fsSL "$LDAP_URL" -o ldap.zip; \
echo "$LDAP_SHA256 ldap.zip" | sha256sum -c -; \
mkdir -p "LDAP Authentication_22.0.0.0"; \
unzip -oq ldap.zip -d "LDAP Authentication_22.0.0.0"; \
curl -fsSL "$SSO_URL" -o sso.zip; \
echo "$SSO_SHA256 sso.zip" | sha256sum -c -; \
mkdir -p "SSO Authentication_4.0.0.4"; \
unzip -oq sso.zip -d "SSO Authentication_4.0.0.4"; \
rm -f ldap.zip sso.zip
# ── Runtime stage ─────────────────────────────────────────────────────────────
FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:10.0
# .NET 9 runtime: matches the SDK 9.0 publish step (framework-dependent), so the
# app's required Microsoft.NETCore.App 9.0 is present. Keep in lockstep with the
# `mcr.microsoft.com/dotnet/sdk` major in .woodpecker/*.yaml and the Makefile.
FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:9.0
# FFmpeg and the native deps required by SkiaSharp and fontconfig.
RUN apt-get update \
@@ -39,6 +76,9 @@ WORKDIR /jellyfin
COPY publish-output/ .
# jellyfin-web client assets from the webclient stage.
COPY --from=webclient /usr/share/jellyfin/web ./jellyfin-web/
# Baked auth plugins; docker-entrypoint.sh syncs these into /config/plugins.
COPY --from=plugins /plugins /usr/share/jellyfin/plugins-baked
COPY --chmod=0755 docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
# Jellyfin default ports
EXPOSE 8096
@@ -51,7 +91,4 @@ ENV JELLYFIN_DATA_DIR=/config \
JELLYFIN_CACHE_DIR=/cache \
JELLYFIN_LOG_DIR=/config/log
ENTRYPOINT ["./jellyfin", \
"--datadir", "/config", \
"--cachedir", "/cache", \
"--webdir", "/jellyfin/jellyfin-web"]
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
+2 -2
View File
@@ -1,6 +1,6 @@
.PHONY: publish build clean patch minor major
IMAGE ?= git.unkin.net/unkin/jellyfin-ha
IMAGE ?= artifactapi.k8s.syd1.au.unkin.net/docker-internal/jellyfin-ha
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "0.0.0-dev")
REF := $(shell cat UPSTREAM_REF)
@@ -8,7 +8,7 @@ REF := $(shell cat UPSTREAM_REF)
# ./publish-output (consumed by Dockerfile.runtime). Mirrors CI.
publish:
rm -rf src publish-output
git clone https://github.com/ZoltyMat/jellyfin-ha.git src
git clone https://git.unkin.net/unkin/jellyfin-ha-src.git src
git -C src checkout $(REF)
dotnet publish src/Jellyfin.Server/Jellyfin.Server.csproj \
-c Release -r linux-x64 --self-contained false -o ./publish-output
+4 -4
View File
@@ -4,12 +4,12 @@ Build-orchestration repo for [ZoltyMat/jellyfin-ha](https://github.com/ZoltyMat/
that adds distributed, Redis-backed transcoding for multi-pod Kubernetes (lease-aware cleanup, HA session
takeover, optional PostgreSQL).
This repo does **not** vendor the fork's source. It pins an upstream commit, builds the .NET 10 server, and
This repo does **not** vendor the fork's source. It pins an upstream commit, builds the .NET 9 server, and
produces a runtime container image pushed to the Gitea registry.
## What it produces
`git.unkin.net/unkin/jellyfin-ha:<tag>` — an `mcr.microsoft.com/dotnet/aspnet:10.0` based image with ffmpeg and
`artifactapi.k8s.syd1.au.unkin.net/docker-internal/jellyfin-ha:<tag>` — an `mcr.microsoft.com/dotnet/aspnet:9.0` based image with ffmpeg and
the prebuilt `jellyfin-web` client, running the published `jellyfin-ha` server.
## Layout
@@ -26,7 +26,7 @@ the prebuilt `jellyfin-web` client, running the published `jellyfin-ha` server.
1. To track a newer upstream, update `UPSTREAM_REF` to the desired commit SHA and merge via PR.
2. Cut a release: `make patch` (or `minor` / `major`) tags `vX.Y.Z` and pushes it, which triggers
`.woodpecker/docker.yaml` to build and push `git.unkin.net/unkin/jellyfin-ha:vX.Y.Z` + `:latest`.
`.woodpecker/docker.yaml` to build and push `artifactapi.k8s.syd1.au.unkin.net/docker-internal/jellyfin-ha:vX.Y.Z` + `:latest`.
## Local build
@@ -34,7 +34,7 @@ the prebuilt `jellyfin-web` client, running the published `jellyfin-ha` server.
make build # clones pinned upstream, dotnet publish, docker build
```
Requires the .NET 10 SDK and Docker. `make publish` runs just the clone + publish into `./publish-output`.
Requires the .NET 9 SDK and Docker. `make publish` runs just the clone + publish into `./publish-output`.
## Deployment
+1 -1
View File
@@ -1 +1 @@
d4f9c12c22d3a640f3b0a3622b23b8cd01d044ad
2e1e445e470c2f2c1520f66678a73faa226c2058
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
# Sync image-baked plugins into the /config (datadir) plugins directory on every
# start. /config is a PVC that overlays the image, so plugins baked into the
# image are invisible until copied in here. Removing any existing versioned dir
# of the same plugin first lets the image version win across restarts/downgrades.
set -eu
BAKED_DIR=/usr/share/jellyfin/plugins-baked
PLUGIN_DIR=/config/plugins
if [ -d "$BAKED_DIR" ]; then
mkdir -p "$PLUGIN_DIR"
for src in "$BAKED_DIR"/*; do
[ -d "$src" ] || continue
name=$(basename "$src") # e.g. "LDAP Authentication_22.0.0.0"
base=${name%_*} # plugin name without the trailing _<version>
for existing in "$PLUGIN_DIR/$base"_*; do
[ -e "$existing" ] && rm -rf "$existing"
done
rm -rf "$PLUGIN_DIR/$name"
cp -a "$src" "$PLUGIN_DIR/$name"
done
fi
exec ./jellyfin \
--datadir /config \
--cachedir /cache \
--webdir /jellyfin/jellyfin-web \
"$@"