diff --git a/romm-automation-compose.yml b/romm-automation-compose.yml new file mode 100644 index 0000000..b2b8ed4 --- /dev/null +++ b/romm-automation-compose.yml @@ -0,0 +1,172 @@ +# RomM Automation / Intake trial stack +# Purpose: test request -> Romarr -> staging -> validation -> RomM workflow. +# Keep this as a staging/test stack first. Do not point staging output directly at production RomM. +# +# Romarr caveat: upstream documents image romarr/romarr:latest, but the public Docker Hub +# image was not pullable during scaffold creation. The service is included in the stack +# with a profile so the rest of the stack can be started/tested while we confirm the +# Romarr image/build path. + +name: romm-automation + +services: + ggrequestz: + image: ghcr.io/xtreemmak/ggrequestz:latest + container_name: ggrequestz + restart: unless-stopped + depends_on: + ggrequestz-postgres: + condition: service_healthy + ggrequestz-redis: + condition: service_healthy + ggrequestz-typesense: + condition: service_healthy + ports: + - "${GGREQUESTZ_PORT:-3003}:3000" + environment: + PUID: ${PUID:-1000} + PGID: ${PGID:-1000} + TZ: ${TZ:-America/Chicago} + NODE_ENV: production + APP_PORT: 3000 + PUBLIC_SITE_URL: ${GGREQUESTZ_PUBLIC_SITE_URL:-http://localhost:3003} + POSTGRES_HOST: ggrequestz-postgres + POSTGRES_PORT: 5432 + POSTGRES_DB: ${GGREQUESTZ_POSTGRES_DB:-ggrequestz} + POSTGRES_USER: ${GGREQUESTZ_POSTGRES_USER:-ggrequestz} + POSTGRES_PASSWORD: ${GGREQUESTZ_POSTGRES_PASSWORD:?set GGREQUESTZ_POSTGRES_PASSWORD in .env} + REDIS_URL: redis://:${GGREQUESTZ_REDIS_PASSWORD:?set GGREQUESTZ_REDIS_PASSWORD in .env}@ggrequestz-redis:6379 + TYPESENSE_HOST: ggrequestz-typesense + TYPESENSE_PORT: 8108 + TYPESENSE_PROTOCOL: http + TYPESENSE_API_KEY: ${GGREQUESTZ_TYPESENSE_API_KEY:?set GGREQUESTZ_TYPESENSE_API_KEY in .env} + AUTH_METHOD: ${GGREQUESTZ_AUTH_METHOD:-basic} + AUTHENTIK_CLIENT_ID: ${GGREQUESTZ_AUTHENTIK_CLIENT_ID:-} + AUTHENTIK_CLIENT_SECRET: ${GGREQUESTZ_AUTHENTIK_CLIENT_SECRET:-} + AUTHENTIK_ISSUER: ${GGREQUESTZ_AUTHENTIK_ISSUER:-} + SESSION_SECRET: ${GGREQUESTZ_SESSION_SECRET:?set GGREQUESTZ_SESSION_SECRET in .env} + IGDB_CLIENT_ID: ${IGDB_CLIENT_ID:?set IGDB_CLIENT_ID in .env} + IGDB_CLIENT_SECRET: ${IGDB_CLIENT_SECRET:?set IGDB_CLIENT_SECRET in .env} + ROMM_SERVER_URL: ${ROMM_SERVER_URL:-} + ROMM_USERNAME: ${ROMM_USERNAME:-} + ROMM_PASSWORD: ${ROMM_PASSWORD:-} + volumes: + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/ggrequestz/app:/app/data + networks: + - romm-automation + + ggrequestz-postgres: + image: postgres:16-alpine + container_name: ggrequestz-postgres + restart: unless-stopped + environment: + POSTGRES_DB: ${GGREQUESTZ_POSTGRES_DB:-ggrequestz} + POSTGRES_USER: ${GGREQUESTZ_POSTGRES_USER:-ggrequestz} + POSTGRES_PASSWORD: ${GGREQUESTZ_POSTGRES_PASSWORD:?set GGREQUESTZ_POSTGRES_PASSWORD in .env} + TZ: ${TZ:-America/Chicago} + volumes: + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/ggrequestz/postgres:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${GGREQUESTZ_POSTGRES_USER:-ggrequestz} -d ${GGREQUESTZ_POSTGRES_DB:-ggrequestz}"] + interval: 30s + timeout: 5s + retries: 5 + networks: + - romm-automation + + ggrequestz-redis: + image: redis:7-alpine + container_name: ggrequestz-redis + restart: unless-stopped + command: ["redis-server", "--appendonly", "yes", "--requirepass", "${GGREQUESTZ_REDIS_PASSWORD:?set GGREQUESTZ_REDIS_PASSWORD in .env}"] + volumes: + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/ggrequestz/redis:/data + healthcheck: + test: ["CMD", "redis-cli", "-a", "${GGREQUESTZ_REDIS_PASSWORD:?set GGREQUESTZ_REDIS_PASSWORD in .env}", "ping"] + interval: 30s + timeout: 5s + retries: 5 + networks: + - romm-automation + + ggrequestz-typesense: + image: typesense/typesense:27.1 + container_name: ggrequestz-typesense + restart: unless-stopped + command: ["--data-dir", "/data", "--api-key", "${GGREQUESTZ_TYPESENSE_API_KEY:?set GGREQUESTZ_TYPESENSE_API_KEY in .env}", "--enable-cors"] + volumes: + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/ggrequestz/typesense:/data + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8108/health"] + interval: 30s + timeout: 5s + retries: 5 + networks: + - romm-automation + + romarr: + image: ${ROMARR_IMAGE:-romarr/romarr:latest} + container_name: romarr + restart: unless-stopped + profiles: ["romarr"] + ports: + - "${ROMARR_PORT:-9797}:9797" + environment: + PUID: ${PUID:-1000} + PGID: ${PGID:-1000} + TZ: ${TZ:-America/Chicago} + volumes: + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/romarr/config:/config + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/staging/romarr-library:/roms + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/staging/downloads:/downloads + networks: + - romm-automation + + romm-comm: + image: idiosync000/romm-comm:latest + container_name: romm-comm + restart: unless-stopped + profiles: ["discord"] + environment: + TZ: ${TZ:-America/Chicago} + TOKEN: ${ROMMCOMM_DISCORD_TOKEN:?set ROMMCOMM_DISCORD_TOKEN in .env} + GUILD: ${ROMMCOMM_GUILD_ID:?set ROMMCOMM_GUILD_ID in .env} + API_URL: ${ROMM_SERVER_URL:?set ROMM_SERVER_URL in .env} + USER: ${ROMM_USERNAME:?set ROMM_USERNAME in .env} + PASS: ${ROMM_PASSWORD:?set ROMM_PASSWORD in .env} + ADMIN_ID: ${ROMMCOMM_ADMIN_ID:-} + DOMAIN: ${ROMMCOMM_DOMAIN:-} + REQUESTS_ENABLED: ${ROMMCOMM_REQUESTS_ENABLED:-true} + IGDB_CLIENT_ID: ${IGDB_CLIENT_ID:-} + IGDB_CLIENT_SECRET: ${IGDB_CLIENT_SECRET:-} + CHANNEL_ID: ${ROMMCOMM_CHANNEL_ID:-} + RECENT_ROMS_ENABLED: ${ROMMCOMM_RECENT_ROMS_ENABLED:-true} + RECENT_ROMS_CHANNEL_ID: ${ROMMCOMM_RECENT_ROMS_CHANNEL_ID:-} + GGREQUESTZ_ENABLED: ${ROMMCOMM_GGREQUESTZ_ENABLED:-true} + GGREQUESTZ_URL: http://ggrequestz:3000 + GGREQUESTZ_API_KEY: ${GGREQUESTZ_API_KEY:-} + volumes: + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/romm-comm/data:/app/data + networks: + - romm-automation + + igir-worker: + image: node:22-alpine + container_name: igir-worker + restart: unless-stopped + profiles: ["validation"] + working_dir: /work + command: ["sh", "-c", "npm install -g igir@latest && sleep infinity"] + volumes: + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/staging:/staging + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/dat:/dat:ro + - ${ROMM_AUTOMATION_DATA:-/opt/docker/romm-automation}/reports:/reports + # Mount production RomM only after staging tests are verified. + # - ${ROMM_LIBRARY_PATH:?set ROMM_LIBRARY_PATH in .env}:/romm/library + networks: + - romm-automation + +networks: + romm-automation: + name: romm-automation + driver: bridge diff --git a/romm-automation.env.example b/romm-automation.env.example new file mode 100644 index 0000000..7cad0eb --- /dev/null +++ b/romm-automation.env.example @@ -0,0 +1,63 @@ +# RomM Automation / Intake trial stack example environment +# Copy to .env on the Docker host/Portainer stack and fill in real values. +# Do not commit real secrets. + +TZ=America/Chicago +PUID=1000 +PGID=1000 + +# Docker-Test trial data root. Keep this staging-only until validated. +ROMM_AUTOMATION_DATA=/opt/docker/romm-automation + +# Published ports on the Docker host +GGREQUESTZ_PORT=3003 +ROMARR_PORT=9797 + +# GG Requestz support services +GGREQUESTZ_POSTGRES_DB=ggrequestz +GGREQUESTZ_POSTGRES_USER=ggrequestz +GGREQUESTZ_POSTGRES_PASSWORD=change_me_generate_long_random +GGREQUESTZ_REDIS_PASSWORD=change_me_generate_long_random +GGREQUESTZ_TYPESENSE_API_KEY=change_me_generate_long_random +GGREQUESTZ_SESSION_SECRET=change_me_generate_32_plus_chars +GGREQUESTZ_AUTH_METHOD=basic +GGREQUESTZ_PUBLIC_SITE_URL=http://192.168.20.226:3003 + +# Optional Authentik/OIDC later. Leave blank for basic auth first. +GGREQUESTZ_AUTHENTIK_CLIENT_ID= +GGREQUESTZ_AUTHENTIK_CLIENT_SECRET= +GGREQUESTZ_AUTHENTIK_ISSUER= + +# IGDB/Twitch credentials required by GG Requestz and useful for RomM-ComM requests. +IGDB_CLIENT_ID=fill_me +IGDB_CLIENT_SECRET=fill_me + +# Existing RomM connection. Fill after confirming current RomM URL/account. +ROMM_SERVER_URL=http://your-romm-host:port +ROMM_USERNAME=fill_me +ROMM_PASSWORD=fill_me + +# Romarr image. Upstream docs list romarr/romarr:latest, but the public image was not pullable +# when this scaffold was created. Override this if we build/publish a local image. +ROMARR_IMAGE=romarr/romarr:latest + +# Existing Arr stack connections for manual configuration inside Romarr/GG Requestz. +# These are documented here for setup reference; the apps may store them internally after UI config. +PROWLARR_URL=http://your-prowlarr-host:9696 +QBITTORRENT_URL=http://your-vpn-qbit-host:8080 +QBITTORRENT_CATEGORY=romarr + +# RomM-ComM / Discord bot. Only needed if starting the discord profile. +ROMMCOMM_DISCORD_TOKEN=fill_me +ROMMCOMM_GUILD_ID=fill_me +ROMMCOMM_ADMIN_ID= +ROMMCOMM_DOMAIN= +ROMMCOMM_CHANNEL_ID= +ROMMCOMM_RECENT_ROMS_CHANNEL_ID= +ROMMCOMM_REQUESTS_ENABLED=true +ROMMCOMM_RECENT_ROMS_ENABLED=true +ROMMCOMM_GGREQUESTZ_ENABLED=true +GGREQUESTZ_API_KEY= + +# Production RomM library path. Do not mount until staging/validation is proven. +# ROMM_LIBRARY_PATH=/path/to/romm/library