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

> Deploy LunaTV with Docker Compose. Follow this complete self-hosting guide to set up your own media server easily and securely. Get started now.

- Repository: [MoonTechLab/LunaTV](https://github.com/MoonTechLab/LunaTV)
- Tags: how-to-guide
- Published: 2026-09-09

---

**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`](https://github.com/MoonTechLab/LunaTV/blob/main/Dockerfile) to create a self-contained runtime that serves the UI on port 3000.

## Understanding the Multi-Stage Build Architecture

The [`Dockerfile`](https://github.com/MoonTechLab/LunaTV/blob/main/Dockerfile) implements an optimized build pipeline that minimizes final image size and maximizes cache efficiency:

- **`deps` stage** – Copies only [`package.json`](https://github.com/MoonTechLab/LunaTV/blob/main/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)](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)](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:

```bash
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)](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:

```yaml
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:

```yaml
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)](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)](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)](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`](https://github.com/MoonTechLab/LunaTV/blob/main/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)](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)](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.