kv-music/DOCKER.md
2026-03-11 23:04:04 +00:00

7.1 KiB

Docker Deployment Guide

Quick Start

Monochrome Only

docker compose up -d

Visit http://localhost:3000

Development

docker compose --profile dev up -d

Visit http://localhost:5173 (hot-reload enabled)


How It Works

Profiles

Docker Compose profiles control which services start. A service with no profile always runs. A service with a profile only runs when that profile is activated.

Command What starts
docker compose up -d Monochrome
docker compose --profile pocketbase up -d Monochrome + PocketBase
docker compose --profile dev up -d Monochrome + Dev server
docker compose --profile dev --profile pocketbase up -d Monochrome + Dev server + PocketBase

In docker-compose.yml, it looks like this:

services:
    monochrome: # no profile -- always starts

    pocketbase:
        profiles: ['pocketbase'] # opt-in

    monochrome-dev:
        profiles: ['dev'] # opt-in

Override File

Docker Compose automatically merges docker-compose.override.yml into docker-compose.yml if it exists in the same directory. No flags needed.

This is useful for forks that need to add custom services or configuration (Traefik labels, extra containers, custom networks) without modifying the base docker-compose.yml.

The override file does not exist in the upstream repo, don't search it!

Example -- adding Traefik labels to PocketBase in your fork:

# docker-compose.override.yml
services:
    pocketbase:
        labels:
            - traefik.enable=true
            - traefik.http.routers.pocketbase.rule=Host(`pocketbase.example.com`)
            - traefik.http.routers.pocketbase.entrypoints=websecure
            - traefik.http.routers.pocketbase.tls.certresolver=letsencrypt
            - traefik.http.services.pocketbase.loadbalancer.server.port=8090
        networks:
            - proxy-network

networks:
    proxy-network:
        external: true

Example -- adding a custom service in your fork:

# docker-compose.override.yml
services:
    my-custom-api:
        image: my-api:latest
        restart: unless-stopped
        ports:
            - '4000:4000'
        networks:
            - monochrome-network

Override files can extend existing services (add labels, env vars, networks) and define entirely new services. See the Docker docs for the full merge behavior.


Configuration

The application is configured via environment variables. Copy .env.example to .env and edit it to match your setup.

Authentication (Appwrite)

Monochrome uses Appwrite for user authentication. While it defaults to official instances, you can use your own self-hosted Appwrite instance:

  1. Create a project in Appwrite.
  2. Enable the Google or Email/Password providers in the Appwrite Console.
  3. Set these variables in your .env:
    • APPWRITE_ENDPOINT: Your Appwrite API endpoint (e.g., https://auth.yourdomain.com/v1).
    • APPWRITE_PROJECT_ID: Your Appwrite project ID (e.g., auth-for-monochrome).

Database (PocketBase)

Monochrome uses PocketBase to store user data (playlists, favorites, profiles, etc.). You can run it alongside Monochrome using the pocketbase profile:

docker compose --profile pocketbase up -d

PocketBase Schema Note

If you are setting up a new PocketBase collection for user data, ensure it has a field named firebase_id (this is a legacy name we use when we first started the accounts system, we used firebase. and im too lazy to change it so yea fuck you).


Portainer Deployment

Portainer can deploy directly from your GitHub fork with auto-updates on push.

Setup

  1. In Portainer, go to Stacks > Add Stack > Repository
  2. Enter your fork URL and branch
  3. Compose path: docker-compose.yml
  4. If your fork has a docker-compose.override.yml, Portainer loads it automatically
  5. Under Environment variables, add:
    • COMPOSE_PROFILES=pocketbase (to enable PocketBase -- omit if not needed)
    • PB_ADMIN_EMAIL=your@email.com
    • PB_ADMIN_PASSWORD=your_secure_password
    • Any other variables from .env.example
  6. Enable GitOps updates to auto-redeploy on push

Tip: COMPOSE_PROFILES is a built-in Docker Compose variable. Setting it to pocketbase is equivalent to passing --profile pocketbase on the command line.

Warning: The dev profile is for local development only. It uses volume mounts to enable hot-reload, which requires the source code to be present on the host machine. Do not include dev in COMPOSE_PROFILES on Portainer deployments from GitHub — it will fail because there's no local source code to mount.

Fork Workflow

To add custom services (Traefik, monitoring, etc.) to your fork:

  1. Create docker-compose.override.yml in your fork
  2. Remove the docker-compose.override.yml line from .gitignore
  3. Commit both changes to your fork
  4. Portainer will auto-load the override file alongside the base compose

When pulling updates from upstream (git pull upstream main), there are no conflicts -- the upstream repo does not have an override file.


Common Operations

# View logs
docker compose logs -f
docker compose logs -f pocketbase

# Rebuild after code changes
docker compose up -d --build

# Stop everything (include all profiles you started)
docker compose --profile pocketbase down

# Stop and remove volumes (data loss!)
docker compose --profile pocketbase down -v

# Backup PocketBase data
docker compose exec pocketbase tar czf - /pb_data > backup.tar.gz

# Restore PocketBase data
docker compose exec pocketbase tar xzf - -C / < backup.tar.gz

Architecture

Production (Dockerfile)

Node.js Alpine image (multi-arch: amd64 + arm64). Installs dependencies, runs vite build, then serves the built files with vite preview on port 4173.

Development (Dockerfile.dev)

Node.js Alpine image with source code mounted as a volume for hot-reload.

Files

File Purpose In upstream repo
docker-compose.yml All services with profiles Yes
docker-compose.override.yml Fork-specific customizations No
.env.example Environment variable template Yes
.env Your local configuration No
Dockerfile Production build Yes
Dockerfile.dev Development build Yes
.dockerignore Build context exclusions Yes