A tiny cinema for you and your friends, running on your own server.
Movie Night is a small, self-hosted watch-together service for media you own in Plex. You send your friends one link. They open it — no account, no signup, no app — and land in the room. When you press play, everyone's player follows a single authoritative server clock, so the jump scare hits all of your friends at the same moment even though every browser is playing its own independent HLS stream. There is one room, no chat (that's what your voice call is for), and no public account system.
This runs my weekly movie nights. I'd love for it to run yours. It is tested with Docker Compose on linux/amd64, Plex and Authelia behind Traefik, and current Safari, Chromium, and Firefox. Other setups probably work; please tell me what breaks.
Whoever is running the night signs in through your reverse proxy and opens the projection booth. Take control, search your Plex library, start the show — three steps, designed for one person driving while everyone else is in the voice call:
Behind the scenes, Movie Night asks Plex for the media, packages one adaptive HLS ladder shared by every viewer (there is deliberately no per-viewer transcode), and publishes segments atomically so a playlist never references a half-written file. Viewers pick their own quality, audio track, and subtitles — the broadcaster never forces subtitles on anyone. Latecomers join mid-film at the right moment; reconnects and refreshes converge back to the shared clock.
- Anonymous, account-free viewing of the current room.
- Plex-backed catalog search for authorized broadcasters.
- Shared play, pause, resume, seek, and stop against a server-owned clock.
- One packaged adaptive HLS ladder shared by every viewer.
- A separate compatible
Originalpresentation when available. - Per-viewer quality, audio, and subtitle selection.
- Persistent room, principal, lease, and audit state in SQLite.
- Server-side control authorization behind an identity-aware reverse proxy.
- Bounded preparation, cache, subprocess, and media-delivery behavior.
Knowing what a project refuses to do is as useful as knowing what it does:
- Authentication is not bundled. The documented deployment uses Authelia ForwardAuth, trusted identity headers, and Movie Night's own role database.
- There is no chat, public signup, password reset, or viewer account system.
- There is no arbitrary upload, URL-fetch, or live-ingest endpoint.
- Live seek is not guaranteed for a progressively prepared presentation.
- Bitmap subtitles such as PGS and VobSub are not personal viewer tracks.
- The launch configuration is tested on linux/amd64; arm64 is not yet tested.
If you run Saltbox, Movie Night fits your existing shape with no changes to Plex and no new host port: Plex is already your catalog, Traefik your router, and Authelia your login. The Saltbox guide is a step-by-step recipe from empty directory to running room.
You need Docker Compose, a reachable Plex server, and an identity-aware reverse proxy for the protected routes. Start with:
- deploy/compose.example.yaml for the hardened service and Traefik route shape;
- config/deploy.env.example for non-secret inputs;
- config/plex.example.json for the Plex allowlist;
- config/principals.example.json for optional first-start principal bootstrap;
- deploy/traefik/movienight-middleware.example.yaml for the protected proxy-hop header.
Review every REQUIRED_ or REPLACE_ value, create the documented owner-only
secret files, install the preflight script at a trusted absolute path, and run:
./deploy/saltbox/preflight.sh host
docker compose --env-file deploy.env -f compose.yaml config --quiet
docker compose --env-file deploy.env -f compose.yaml up -dThe examples intentionally do not provide a working public origin, image digest, secret, Plex section ID, cache budget, middleware name, or TLS setting — an incomplete deployment should fail loudly at preflight, not quietly serve your library to the internet.
The viewer page, sanitized room state, room WebSocket, subtitles, and authorized media are public. Catalog browsing, preparation, playback control, seeking, and role management require authentication and server-side authorization. Control mutations also require a host-only session, trusted proxy hop, Origin check, CSRF token, and the appropriate Movie Night role.
The Plex token stays in a server-side file. Browser-visible responses and URLs never contain it or a private media path. A loopback source gateway gives FFmpeg access only to the Plex part bound to the active preparation job.
See SECURITY.md for reporting vulnerabilities and the architecture specification for the full trust-boundary design.
A supported Go toolchain and Node.js are required for the ordinary checks. Run
npm ci once to install the pinned browser-acceptance dependencies. FFmpeg,
Plex, and installed browsers are required only for the explicitly named
integration suites.
npm ci
make run
make check
make buildmake run creates ignored development state under .local/dev/, listens on
http://127.0.0.1:8080, and keeps protected routes protected. Build output is
written to bin/movienightd and bin/movienightctl.
Both binaries report the version, Git revision, and build date embedded by the
build. Ordinary local builds identify each field as dev:
./bin/movienightd --version
./bin/movienightctl versionmovienightctl changes Movie Night's authorization rows; it does not create or
reset accounts in the upstream identity provider.
./bin/movienightctl --database /absolute/path/movienight.db principal add operator --role admin
./bin/movienightctl --database /absolute/path/movienight.db principal add broadcaster --role broadcaster
./bin/movienightctl --database /absolute/path/movienight.db principal list
./bin/movienightctl --database /absolute/path/movienight.db backup /absolute/path/movienight.backup.dbThe runtime image includes both movienightd and movienightctl. Use the
control tool only from a trusted operator environment with explicit database
access; it has no HTTP route.
| Guide | What it covers |
|---|---|
| Saltbox guide | Step-by-step install on a Saltbox host |
| Deployment examples | Security envelope, inputs, preflight, route boundary |
| Configuration and secrets | Every environment variable and config file |
| Architecture specification | The full product, synchronization, and trust-boundary design |
| Security policy | Reporting vulnerabilities privately |
| Release notes | What v0.1.0 contains and its known limits |
| Third-party notices | Licenses for hls.js, FFmpeg, and Go dependencies |
This is a code drop with care, not a support contract: it exists because my friends and I wanted movie nights, and it is published because yours might too. Issues and careful bug reports are genuinely welcome — I read them, and I want this to be good — but responses are best effort. Pull requests should preserve the two boundaries everything else hangs on: viewing stays anonymous, and control stays authenticated.
Movie Night is available under the MIT License.