Skip to content

Installation

Comic Shelf is designed to be self-hosted using Docker Compose. All you need is Docker — no Node.js or build tools required.

Prerequisites

Quick Start

1. Create a docker-compose.yml

yaml
services:
  app:
    image: ghcr.io/jaccogoris/comic-shelf:latest
    container_name: comic-shelf
    restart: unless-stopped
    ports:
      - '${PORT:-3000}:3000'
    environment:
      POSTGRES_HOST: postgres
      POSTGRES_USER: ${POSTGRES_USER:-comic_shelf}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-comic_shelf}
      POSTGRES_DB: ${POSTGRES_DB:-comic_shelf}
      PORT: '3000'
      JWT_SECRET: ${JWT_SECRET:-changeme}
      JWT_EXPIRATION: ${JWT_EXPIRATION:-7d}
      METRON_USERNAME: ${METRON_USERNAME:-}
      METRON_PASSWORD: ${METRON_PASSWORD:-}
      METRON_API_BASE_URL: ${METRON_API_BASE_URL:-https://metron.cloud}
      OIDC_ISSUER_URL: ${OIDC_ISSUER_URL:-}
      OIDC_CLIENT_ID: ${OIDC_CLIENT_ID:-}
      OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-}
      OIDC_REDIRECT_URI: ${OIDC_REDIRECT_URI:-}
    depends_on:
      postgres:
        condition: service_healthy
    healthcheck:
      test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3000/api/health']
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 30s

  postgres:
    image: postgres:16-alpine
    container_name: comic-shelf-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-comic_shelf}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-comic_shelf}
      POSTGRES_DB: ${POSTGRES_DB:-comic_shelf}
    volumes:
      - comic_shelf_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-comic_shelf}']
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  comic_shelf_data:

2. Create a .env

ini
# ── Database ──────────────────────────────────────────────
POSTGRES_USER=comic_shelf
POSTGRES_PASSWORD=change-me
POSTGRES_DB=comic_shelf

# ── Auth ──────────────────────────────────────────────────
# Generate a strong secret, e.g.: openssl rand -hex 32
JWT_SECRET=change-me-to-a-long-random-secret
JWT_EXPIRATION=7d

# ── Metron API (optional) ─────────────────────────────────
# Register at https://metron.cloud to enable UPC barcode lookups
METRON_USERNAME=
METRON_PASSWORD=

# ── OIDC (optional) ───────────────────────────────────────
# Leave OIDC_CLIENT_ID empty to disable OIDC login
OIDC_ISSUER_URL=
OIDC_CLIENT_ID=
OIDC_CLIENT_SECRET=
OIDC_REDIRECT_URI=

3. Start the stack

bash
docker compose up -d

The app will be available at http://localhost:3000. On first run, the app will automatically guide you through creating the admin account.

Environment Variables

VariableRequiredDefaultDescription
POSTGRES_USERNocomic_shelfPostgreSQL username
POSTGRES_PASSWORDYesPostgreSQL password
POSTGRES_DBNocomic_shelfPostgreSQL database name
PORTNo3000Port the app listens on
JWT_SECRETYesSecret used to sign JWTs — use a long random string
JWT_EXPIRATIONNo7dHow long login sessions last
METRON_USERNAMENoMetron API username (for UPC lookup)
METRON_PASSWORDNoMetron API password (for UPC lookup)
METRON_API_BASE_URLNohttps://metron.cloudMetron API base URL
OIDC_ISSUER_URLNoOIDC provider issuer URL
OIDC_CLIENT_IDNoOIDC client ID (leave empty to disable OIDC)
OIDC_CLIENT_SECRETNoOIDC client secret
OIDC_REDIRECT_URINoOIDC callback URL

See Environment Variables for the full reference.