Configuration

All configuration is done through environment variables passed to the Docker container, plus a few in-app settings.

HTTPS / SSL

Black Candy Store can handle HTTPS natively with automatic Let's Encrypt certificates — no reverse proxy needed.

docker run -p 80:80 -p 443:443 \
  -e TLS_DOMAIN=music.example.com \
  -v ./storage_data:/rails/storage \
  ghcr.io/ajeskey/blackcandystore:latest

Requirements:

Certificates are provisioned on first request and renewed automatically. You can pass multiple domains as a comma-separated list.

Using a Reverse Proxy

If you prefer to terminate TLS at a reverse proxy (Caddy, Nginx, Traefik), leave TLS_DOMAIN unset and configure your proxy to forward traffic to the container's HTTP port.

Database

SQLite is the default and works great for personal use. For larger deployments or cloud hosting, switch to PostgreSQL.

SQLite (default)

No configuration needed. The database file is stored in /rails/storage.

PostgreSQL

docker run \
  -e DB_ADAPTER=postgresql \
  -e DB_URL=postgresql://user:pass@host:5432/blackcandystore \
  -e CABLE_DB_URL=postgresql://user:pass@host:5432/blackcandystore_cable \
  -e QUEUE_DB_URL=postgresql://user:pass@host:5432/blackcandystore_queue \
  -e CACHE_DB_URL=postgresql://user:pass@host:5432/blackcandystore_cache \
  -p 80:80 \
  ghcr.io/ajeskey/blackcandystore:latest

In-App Settings

Some settings are managed through the web UI rather than environment variables. To access them:

  1. Log in as an admin user
  2. Click Settings in the sidebar navigation (gear icon)

The Settings page has the following sections:

Library

At the top of the Settings page:

Integration

Below the Library section:

Transcoding

Media Clients

Each section has its own Save button — make sure to click it after changing values.

Secret Key Base

Used for encrypting sessions and security-sensitive data. Generate one with:

openssl rand -hex 64

Then pass it to the container:

docker run -e SECRET_KEY_BASE=your_generated_secret -p 80:80 ghcr.io/ajeskey/blackcandystore:latest

If SECRET_KEY_BASE is not set, a new one is generated on each startup, which invalidates all existing sessions.

Encryption Keys

Cross-server sharing uses Active Record encryption to protect access tokens at rest. Set these three variables in production:

If unset, development defaults are used — fine for testing, not for production.

Environment Variables Reference

Variable Default Description
MEDIA_PATH Path to music files inside the container
DB_ADAPTER sqlite sqlite or postgresql
DB_URL PostgreSQL connection URL
CABLE_DB_URL Pub/Sub database URL (PostgreSQL only)
QUEUE_DB_URL Background job database URL (PostgreSQL only)
CACHE_DB_URL Cache database URL (PostgreSQL only)
SECRET_KEY_BASE random Secret for sessions and encryption
TLS_DOMAIN Domain(s) for automatic HTTPS
HTTP_PORT 80 Internal port the server listens on
FORCE_SSL false Force all access over HTTPS
SERVER_BASE_URL http://localhost:3000 Public URL for cross-server sharing
CATALOG_SYNC_POLL_INTERVAL 15 Minutes between catalog sync pulls
DEMO_MODE false Lock down admin access for demos
AR_ENCRYPTION_PRIMARY_KEY Primary key for Active Record encryption
AR_ENCRYPTION_DETERMINISTIC_KEY Deterministic key for Active Record encryption
AR_ENCRYPTION_KEY_DERIVATION_SALT Key-derivation salt for Active Record encryption

Logging

Logs go to STDOUT by default. Use Docker's built-in logging drivers to route them wherever you need:

docker run --log-driver=json-file --log-opt max-size=10m -p 80:80 ghcr.io/ajeskey/blackcandystore:latest

Next Steps