1
0
Fork
You've already forked media-stack
0
No description
  • Python 56.7%
  • Shell 23.5%
  • Makefile 11.7%
  • Dockerfile 4.2%
  • PHP 3.3%
  • Other 0.6%
2026年06月26日 21:26:34 -05:00
cci Add uv-managed CCI Black Book MCP service 2026年06月26日 21:26:34 -05:00
channels fix(channels): use unless-stopped; document and start stack 2026年05月03日 09:46:31 -05:00
core feat: add matrix stack with Tuwunel homeserver and Element Web 2026年06月12日 15:54:34 -05:00
grow Point grow app deployment at stackdrift image 2026年06月21日 16:48:23 -05:00
immich chore: apply ruff/yamllint baseline to existing files 2026年05月06日 13:01:16 -05:00
iptv feat: enable Pangolin target health monitoring on all public resources 2026年05月05日 14:45:57 -05:00
kanban Support non-padded Kanboard issue refs 2026年06月21日 14:02:54 -05:00
matrix Wire Matrix alert routing 2026年06月20日 11:48:00 -05:00
media feat: enable Pangolin target health monitoring on all public resources 2026年05月05日 14:45:57 -05:00
monitoring Prefer public Kanboard task refs 2026年06月20日 17:43:56 -05:00
mqtt Deploy LAN grow app stack 2026年06月13日 16:39:22 -05:00
pangolin chore: apply ruff/yamllint baseline to existing files 2026年05月06日 13:01:16 -05:00
penpot Add Penpot design workspace stack 2026年06月20日 11:55:12 -05:00
.editorconfig chore: introduce ruff/shellcheck/yamllint tooling 2026年05月06日 13:00:58 -05:00
.gitignore chore: update gitignore 2026年06月12日 11:19:00 -05:00
.shellcheckrc chore: introduce ruff/shellcheck/yamllint tooling 2026年05月06日 13:00:58 -05:00
.yamllint.yml chore: introduce ruff/shellcheck/yamllint tooling 2026年05月06日 13:00:58 -05:00
AGENTS.md Add uv-managed CCI Black Book MCP service 2026年06月26日 21:26:34 -05:00
Makefile Add uv-managed CCI Black Book MCP service 2026年06月26日 21:26:34 -05:00
Makefile.include Add grow app image pull target 2026年06月20日 11:55:17 -05:00
pyproject.toml chore: introduce ruff/shellcheck/yamllint tooling 2026年05月06日 13:00:58 -05:00
README.md Add uv-managed CCI Black Book MCP service 2026年06月26日 21:26:34 -05:00

Self-hosted stack for sharing media with family and friends

I made this Docker-based streaming media platform to offer my family and friends a better way to access services I've provided ad-hoc for years. A major goal of this iteration is giving my users a polished experience that hides complexity and minimizes the learning curve.

In an ideal world, users are shielded from:

  • installing VPN or similar software for access
  • having to know about the components involved
  • keeping track of many 'weird' links to complicated apps
  • having different credentials for each thing

As an engineer that loves my friends but has very little time to spare, I needed:

  • enterprise identity (SSO) and access management
  • familiar git-based devops patterns
  • containerized runtime and deployment
  • support and user login portal

Technical Summary

Using Pangolin and this Docker stack, I can securely share apps running at home without my users installing VPN or other special software. Users visit friendly links using my domain and have a single account for all services, with Google and Apple social login available.

Each app is exposed under a familiar, branded domain with automated TLS certificate provisioning and maintenance. Exposing new apps involves only adding a few labels to its container, which Pangolin uses to auto-configure and discover its resources for proxying.

Hugo landing page

I'm using a Hugo static site to write support guides in Markdown and quickly deploy them for users to reference. The site works as a landing page for users with support, login and other helpful links in one place. The hugo site is intended to be built with Docker via CI actions, published to a container registry and pulled on deployment via Docker or Kubernetes.

Using Pangolin's auth layer (backed by my Keycloak instance), logged in users are able to access an apps page which has a grid with links to services available in different categories like streaming, AI, photos, etc.

Identity and access management

Identity for everything is managed by Keycloak. Services with native OIDC or SAML support (like Immich or Pangolin) use Keycloak as their identity provider. Pangolin provides an auth layer for apps and services that don't support auth or OIDC.

Jellyfin only supports managing users and auth by federating with an LDAP directory. To make this work in a low friction way, I configure Keycloak to federate with an OpenLDAP service. This makes the OpenLDAP directory become the password backend for Keycloak.

When Keycloak or Jellyfin need to authenticate a user by password, they ask OpenLDAP. Keycloak handles syncing its users and groups to OpenLDAP's expected directory schema, so Jellyfin is able to see what Keycloak groups have been assigned to a given user.

Jellyfin is configured to check for group membership when a Keycloak user tries to sign in. If they are a member of the streaming group, they get a Jellyfin account and are able to login. If they are a member of streaming and admin groups, they're made a Jellyfin admin.

Users have a single username and password for everything, regardless if the auth is proxied by Pangolin for non-OIDC/SAML apps or by Keycloak or by LDAP for Jellyfin. And they don't need to be aware Pangolin or OpenLDAP exist, as they only interact with Keycloak.

What’s inside

I group sets of services into separate Docker compose projects in this repo:

  • core: key things for providing the service
    • newt
    • auth (keycloak)
    • ldap
    • homepage (hugo landing site)
    • update-manager (wud — image-update notifications)
  • media
    • jellyfin
    • seerr (jellyseerr)
    • sonarr
    • radarr
    • nzbget
  • immich
    • server
    • machine-learning
    • database
    • redis
  • iptv: iptvboss services
    • web vnc to access iptvboss app
    • XtremeCodes API for IPTV client playlist and guide data
  • channels: Channels DVR (fancybits/channels-dvr) — host networking; config and recordings under /mnt/data/channels-dvr/ on the Docker host. Start with make channels-up or make up (channels/docker-compose.yml).
  • monitoring: notification + probe machinery (apprise-api + events-watcher + service-checks) plus two SaaS witnesses (UptimeRobot for external HTTP probes; Healthchecks.io for dead-man checks). Local Apprise alerts land in Matrix + Discord during the migration window; UptimeRobot remains Discord + mobile push only. Public status page at status.dephekt.net. See monitoring/README.md.
  • pangolin: the Pangolin reverse-proxy / control-plane itself, deployed via a separate Docker context (pangolin-edge) to the edge VPS. The Makefile auto-routes pangolin-up etc. to the right host. See pangolin/README.md.
  • mqtt: Mosquitto site broker + central aggregator for the grow-control MQTT spine. See mqtt/README.md.
  • grow: Daniel's LAN-local grow-app site HMI on port 3080. See grow/README.md.
  • matrix: Tuwunel homeserver with Element Web for family/friends chat. Tuwunel uses built-in RocksDB (no PostgreSQL). Exposed via Pangolin at matrix.${DOMAIN} (homeserver) and chat.${DOMAIN} (Element Web). See matrix/README.md.
  • penpot: self-hosted Penpot design workspace at https://design.ai.${DOMAIN} for grow-app HMI design review. Penpot uses Keycloak OIDC directly; Pangolin only handles ingress/TLS. See penpot/README.md.
  • kanban: shared Kanboard project tracker at kanban.ai.dephekt.net, with a LAN fallback at http://containers.home.arpa:8097. See kanban/README.md.
  • cci: MCP-only CCI Black Book retrieval service at https://cci.ai.${DOMAIN}/mcp, using bearer auth and bounded cited evidence packs. See cci/README.md.

How it works (one minute)

  • Requests hit the closest Pangolin edge node
  • Pangolin authenticates users (if auth is configured) and routes to your site’s Newt
  • Newt discovers containers via Docker labels (Blueprints) and forwards to the configured target
  • Services providing their own auth (via OIDC/SAML with Keycloak) are exposed without Pangolin's auth in front

No client software is required for users. Everything is just HTTPS in a browser.

Adding a new service (Pangolin Blueprints)

Expose a container with Pangolin proxy resource labels; Newt autodiscovers:

labels:- "pangolin.proxy-resources.app.name=My App"- "pangolin.proxy-resources.app.protocol=http"- "pangolin.proxy-resources.app.full-domain=app.${DOMAIN}"- "pangolin.proxy-resources.app.targets[0].enabled=true"- "pangolin.proxy-resources.app.targets[0].port=8080"

Certificates and HTTPS

TLS termination and cert management are handled by Pangolin at the edge.

Acknowledgements

Dashboard Icons - A collection of over 1800 curated icons for services, applications and tools, designed specifically for dashboards and app directories. Used to power the homepage service icons. Browse the collection at dashboardicons.com.