How to Deploy LunaTV Using Docker: Multi-Stage Builds and Production Configuration
Deploy LunaTV using Docker by pulling the pre-built GHCR image or building the multi-stage Dockerfile locally, setting required authentication and storage environment variables, and exposing port 3000 for the Next.js application.
The MoonTechLab/LunaTV repository packages this streaming platform as an optimized, production-ready container. Understanding how to deploy LunaTV using Docker ensures consistent deployments across Docker Desktop, Kubernetes, and cloud-native platforms.
Anatomy of the LunaTV Multi-Stage Dockerfile
The production image defined in Dockerfile at the repository root employs a three-stage build strategy to minimize attack surface and image size while maximizing build cache efficiency.
Stage 1: Dependency Installation (deps)
The deps stage copies only package.json and the pnpm lockfile to leverage Docker layer caching. It installs all Node.js dependencies—including devDependencies—using pnpm, creating a reusable base layer for subsequent builds.
Stage 2: Application Build (builder)
The builder stage copies the installed node_modules from deps along with the full source tree. It sets DOCKER_ENV=true and executes pnpm run build to generate a standalone Next.js output in .next/standalone. This stage compiles the TypeScript source and prepares optimized production assets.
Stage 3: Production Runtime (runner)
The final runner stage starts from a clean Alpine Linux image, creates a non-root nextjs user for security, and copies only the essential artifacts: the standalone build, public assets, and the custom start.js entry point. The container exposes port 3000 and launches the application via node start.js.
Required Environment Variables
LunaTV requires specific environment variables at runtime for authentication and storage configuration. These are read by src/lib/config.ts and consumed by the custom start.js initialization script.
- USERNAME / PASSWORD: Administrator credentials (mandatory).
- NEXT_PUBLIC_STORAGE_TYPE: Backend for playback records—set to
redis,kvrocks, orupstash. - Connection URLs: Provide
REDIS_URL,KVROCKS_URL, orUPSTASH_URL/UPSTASH_TOKENbased on your storage selection. - Optional Branding: Configure
SITE_BASE,NEXT_PUBLIC_SITE_NAME, andANNOUNCEMENTfor site customization.
Deployment Methods
Choose between ephemeral single-container testing or persistent orchestrated deployments.
Single-Container Deployment with Docker Run
For rapid testing against an existing Redis instance, run the pre-built image from GitHub Container Registry:
docker run -d \
--name lunatv \
-p 3000:3000 \
-e USERNAME=admin \
-e PASSWORD=SuperSecretPassword \
-e NEXT_PUBLIC_STORAGE_TYPE=redis \
-e REDIS_URL=redis://host.docker.internal:6379 \
ghcr.io/moontechlab/lunatv:latest
This command binds port 3000 to localhost and configures Redis as the storage backend.
Local Development with Docker Compose
For local development with persistent storage, use the example docker-compose.dev.yml. This orchestrates both the LunaTV application and a Redis service with health checks:
version: '3.8'
services:
redis:
image: redis:7-alpine
container_name: lunatv-redis
volumes:
- redis-data:/data
command: redis-server --appendonly yes
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 5s
timeout: 3s
retries: 5
app:
build:
context: .
dockerfile: Dockerfile
container_name: lunatv-app
ports:
- '3000:3000'
depends_on:
redis:
condition: service_healthy
environment:
- NEXT_PUBLIC_STORAGE_TYPE=redis
- REDIS_URL=redis://redis:6379
- USERNAME=admin
- PASSWORD=admin123
- NEXT_PUBLIC_SITE_NAME=MoonTV
volumes:
redis-data:
The app service builds from the local Dockerfile while the redis service provides durable storage with volume persistence.
Production Deployment with Kvrocks
For production workloads requiring higher throughput, replace Redis with Apache Kvrocks. Update your Compose file to define the Kvrocks service and adjust environment variables:
services:
kvrocks:
image: apache/kvrocks
container_name: moontv-kvrocks
restart: unless-stopped
volumes:
- kvrocks-data:/var/lib/kvrocks
app:
build:
context: .
dockerfile: Dockerfile
environment:
- NEXT_PUBLIC_STORAGE_TYPE=kvrocks
- KVROCKS_URL=redis://kvrocks:6666
- USERNAME=admin
- PASSWORD=securepassword
Set NEXT_PUBLIC_STORAGE_TYPE=kvrocks and provide KVROCKS_URL to connect to the Kvrocks instance on its default port 6666.
Key Implementation Files
Understanding these critical files helps troubleshoot deployment issues:
Dockerfile: Defines the multi-stage build pipeline producing the production image.docker-compose.dev.yml: Provides the reference implementation for local Redis-backed deployments.start.js: Custom entry point executed by therunnerstage; pre-loads configuration before initializing the Next.js server.src/lib/config.ts: Centralized configuration loader that validates and exposes environment variables to the application.
Summary
- Deploy LunaTV using Docker by leveraging the multi-stage
Dockerfilethat separates dependency installation, application building, and production runtime into discrete layers. - The
runnerstage executes as the non-rootnextjsuser on Alpine Linux, listening on port 3000. - Required environment variables include authentication credentials (
USERNAME,PASSWORD) and storage configuration (NEXT_PUBLIC_STORAGE_TYPEplus connection URLs). - Choose Redis for local development via
docker-compose.dev.yml, or Kvrocks for production deployments requiring persistent, high-performance storage. - The container is self-contained and compatible with Docker Desktop, Kubernetes, and platform-as-a-service providers like Zeabur.
Frequently Asked Questions
What storage backends does LunaTV support?
LunaTV supports three storage backends for playback records: Redis (ideal for development), Kvrocks (recommended for production), and Upstash (serverless Redis). Configure the backend using NEXT_PUBLIC_STORAGE_TYPE and provide the corresponding connection URL.
Why does the Dockerfile use a multi-stage build?
The multi-stage build minimizes the final image size and attack surface by discarding build dependencies and source code. Only the compiled standalone Next.js output from .next/standalone and the start.js script are copied into the production runner stage based on Alpine Linux.
How do I persist data when deploying LunaTV?
Data persistence depends on your storage backend. When using Docker Compose, mount named volumes (e.g., redis-data or kvrocks-data) to the respective storage containers. For Redis, use the --appendonly yes flag to enable AOF persistence. The LunaTV container itself is stateless.
Can I run LunaTV as a non-root user?
Yes, the production image explicitly creates and runs as the nextjs user within the runner stage. This security hardening ensures the application process lacks privileges to modify system files inside the container, following container security best practices.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →