How to Deploy LunaTV Using Docker Compose: Complete Self-Hosting Guide

Deploy LunaTV by running the multi-stage container with required environment variables (USERNAME, PASSWORD, STORAGE_TYPE) and connecting it to Redis or Kvrocks via Docker Compose for persistent storage.

LunaTV from MoonTechLab/LunaTV provides a production-ready Docker setup that packages the Next.js application into a lightweight Alpine image. According to the repository source code, the deployment leverages a three-stage build process defined in Dockerfile to create a self-contained runtime that serves the UI on port 3000.

Understanding the Multi-Stage Build Architecture

The Dockerfile implements an optimized build pipeline that minimizes final image size and maximizes cache efficiency:

  • deps stage – Copies only package.json and the lockfile to install Node dependencies using pnpm, ensuring layer caching remains effective when source code changes.

  • builder stage – Inherits the node_modules from the previous stage, copies the full source tree, sets DOCKER_ENV=true, and executes pnpm run build to generate a standalone Next.js output in .next/standalone.

  • runner stage – Uses a clean Alpine base image, creates a non-root nextjs user, and copies only the essential artifacts: the standalone build, public assets, and the custom [start.js](https://github.com/MoonTechLab/LunaTV/blob/main/start.js) entry point. The container launches via node start.js listening on 0.0.0.0:3000.

Required Environment Variables

The container reads configuration from environment variables processed by [src/lib/config.ts](https://github.com/MoonTechLab/LunaTV/blob/main/src/lib/config.ts). You must provide the following at runtime:

Variable Purpose
USERNAME / PASSWORD Administrator credentials for accessing the LunaTV dashboard (required).
NEXT_PUBLIC_STORAGE_TYPE Backend for playback records: redis, kvrocks, or upstash.
REDIS_URL / KVROCKS_URL / UPSTASH_URL / UPSTASH_TOKEN Connection string for the chosen storage backend.
SITE_BASE / NEXT_PUBLIC_SITE_NAME Optional branding and base URL configuration.

Single Container Deployment

For quick testing without Docker Compose, run the pre-built image directly from the GitHub Container Registry. This example connects to an external Redis instance:

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

Access the application at http://localhost:3000 after the container starts.

Docker Compose Deployment Strategies

Local Development with Redis

The repository provides [docker-compose.dev.yml](https://github.com/MoonTechLab/LunaTV/blob/main/docker-compose.dev.yml) as a reference implementation. This configuration builds the image from source and pairs it with a Redis container featuring persistent volume storage and 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:

Production Deployment with Kvrocks

For production environments, the MoonTechLab/LunaTV source recommends Kvrocks (Redis-compatible persistent storage on SSD). Replace the Redis service in your Compose file with the following configuration:

services:
  kvrocks:
    image: apache/kvrocks
    container_name: moontv-kvrocks
    restart: unless-stopped
    volumes:
      - kvrocks-data:/var/lib/kvrocks
    ports:
      - "6666:6666"

  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: lunatv-app
    ports:
      - '3000:3000'
    depends_on:
      - kvrocks
    environment:
      - NEXT_PUBLIC_STORAGE_TYPE=kvrocks
      - KVROCKS_URL=redis://kvrocks:6666
      - USERNAME=admin
      - PASSWORD=SecureProductionPass

volumes:
  kvrocks-data:

Configuration Deep Dive

When the container starts, [start.js](https://github.com/MoonTechLab/LunaTV/blob/main/start.js) serves as the custom entry point that pre-loads and validates environment variables before launching the Next.js standalone server. The [src/lib/config.ts](https://github.com/MoonTechLab/LunaTV/blob/main/src/lib/config.ts) module parses these variables at runtime, ensuring the storage backend connection and authentication credentials are properly initialized before accepting requests on port 3000.

Summary

  • LunaTV uses a three-stage Dockerfile (deps → builder → runner) to create optimized, production-ready images based on Alpine Linux.
  • Required variables: Set USERNAME, PASSWORD, and NEXT_PUBLIC_STORAGE_TYPE (plus the corresponding backend URL) to launch the container successfully.
  • Development setup: Use [docker-compose.dev.yml](https://github.com/MoonTechLab/LunaTV/blob/main/docker-compose.dev.yml) with Redis for local testing with automatic health checks.
  • Production setup: Deploy with Kvrocks for better persistence characteristics and configure restart policies for high availability.
  • Access: The application binds to 0.0.0.0:3000 inside the container, requiring port mapping to reach the UI externally.

Frequently Asked Questions

What storage backends does LunaTV support?

LunaTV supports three storage backends for playback records: Redis (for caching/labs), Kvrocks (recommended for production SSD persistence), and Upstash (managed Redis cloud service). Configure your choice via NEXT_PUBLIC_STORAGE_TYPE and the corresponding URL environment variable.

Why does the Dockerfile use a multi-stage build?

The multi-stage build defined in Dockerfile separates dependency installation, application compilation, and runtime execution. This approach reduces the final image size by excluding build tools and node_modules, resulting in a lightweight Alpine-based runner stage that contains only the compiled standalone output and the [start.js](https://github.com/MoonTechLab/LunaTV/blob/main/start.js) launcher.

Can I run LunaTV without Docker Compose?

Yes. Since the LunaTV image is self-contained, you can deploy it using simple docker run commands as long as you provide all required environment variables and network access to your chosen storage backend (Redis, Kvrocks, or Upstash). This works on Docker Desktop, Kubernetes, or platforms like Zeabur.

How do I persist data when using Docker Compose for LunaTV?

Data persistence depends on your storage backend selection. For Redis, mount a named volume to /data with the appendonly yes configuration. For Kvrocks, mount a volume to /var/lib/kvrocks. The example [docker-compose.dev.yml](https://github.com/MoonTechLab/LunaTV/blob/main/docker-compose.dev.yml) demonstrates Redis persistence using Docker volumes, while production Kvrocks deployments should use the same volume strategy to prevent data loss during container restarts.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →