- Migrate all 127 non-reserved docs to OKF v0.1 frontmatter (type/description/tags/timestamp); fix 13 YAML issues, 2 duplicate-FM blocks, strip reserved-page FM - Restructure log.md to OKF (## YYYY-MM-DD, newest-first) - Fact-check against scripts/AGENTS.md ground truth: fix 6 false 'Active' banners on retired runbooks, 96->114 GiB GTT, deployment.md vs deploy-plan.py/deploy-remote.sh, Deployment Flow frank-medium=Quadlet, Calibre 9.9.0->9.15.0 + CVE-2025-7404 conflation, Copyparty v1.20.24, RomM 5.3.0 breaking change - Move *arr docs to new FrankBook-Pro/ section (git mv, link-safe) - Write active runbook bodies from ground truth (frank-large, frank-small) - Add 3 research briefs + HTML report: Local TTS and Voice Cloning, AI Job Search and Resume Tools, Most Popular Self-Hosted AI Apps (Jun-Sep 2026) - Add upstream-version rows to ComfyUI/OpenWebUI/Hermes app docs - All 336 tests pass; 136 pages, 0 unresolved wikilinks
9.2 KiB
type, description, tags, timestamp
| type | description | tags | timestamp | ||
|---|---|---|---|---|---|
| reference | RomM (ROM Manager) is a self-hosted ROM library manager and player. |
|
2026-09-03 |
RomM
RomM (ROM Manager) is a self-hosted ROM library manager and player. It scans a ROM collection, enriches it with metadata and cover art from multiple providers, and serves it through a clean web interface. RomM also supports browser-based emulation via EmulatorJS and native emulator streaming.
Host: Dankserver — Access: romm.franksdank.cloud guarded by the
Anubis → Authentik chain (Caddy routes it post-auth to
192.168.0.235:8085) — Docs: https://docs.romm.app
Facts
| Item | Value |
|---|---|
| Running image | ghcr.io/rommapp/romm:latest (rolling tag — no pin; the version claims on this page were true at research time; verify against the live container before relying on them) |
| Port | 8085 (host) → 8080 (container) |
| Database | MariaDB (default); PostgreSQL optional |
| Cache / Queue | Redis or Valkey (required for task queue) |
| Frontend | React SPA |
| Backend | FastAPI / Node |
| Metadata providers | IGDB, Screenscraper, MobyGames, Hasheous, Playmatch, LaunchBox, Flashpoint, HowLongToBeat, SteamGridDB, RetroAchievements, TGDB, ES-DE gamelist |
| Emulator player | EmulatorJS (WebAssembly RetroArch cores) |
| Emulator streaming | Native containers (PCSX2, Dolphin, Xemu) → browser |
Architecture
Current RomM releases require MariaDB plus Redis (or Valkey) for the task
queue; this deployment runs redis (REDIS_HOST=redis in the live unit),
not valkey.
graph LR
U[User] --> C[Caddy :80/:443]
C --> R[RomM :8085]
R --> DB[(MariaDB)]
R --> Cache[(Redis)]
R --> Lib[/romm/library]
R --> Res[/romm/resources]
Configuration
Environment Variables
| Variable | Required | Description |
|---|---|---|
ROMM_USERNAME |
Yes | Initial admin username |
ROMM_PASSWORD |
Yes | Initial admin password (set on first boot) |
ROMM_AUTH_SECRET_KEY |
Yes | JWT signing key. Generate with openssl rand -hex 32. Replaces the old ROMM_SECRET_KEY. |
DB_HOST |
Yes | MariaDB hostname (e.g. mariadb) |
DB_NAME |
Yes | Database name (e.g. romm) |
DB_USER |
Yes | Database user |
DB_PASSWD |
Yes | Database password |
REDIS_HOST |
Yes | Redis hostname (e.g. redis) |
DISABLE_SETUP_WIZARD |
No | Set to true to skip the first-run wizard |
OIDC_ENABLED |
No | Enable OpenID Connect authentication |
OIDC_CLIENT_ID |
No | OIDC client ID |
OIDC_CLIENT_SECRET |
No | OIDC client secret |
OIDC_REDIRECT_URI |
No | OIDC redirect URI |
STREAMING_BROKER_SECRET |
No | Secret for native emulator streaming |
STREAMING_SAVE_TIMEOUT |
No | Timeout for save states during streaming |
KIOSK_MODE |
No | Enable kiosk mode |
ROMM_SESSION_SECURE_COOKIE |
No | Secure cookie flag for sessions |
Metadata Provider Credentials
These are set via environment variables or in config.yml:
| Variable | Provider | Notes |
|---|---|---|
IGDB_CLIENT_ID / IGDB_CLIENT_SECRET |
IGDB (Twitch OAuth2) | Create app at Twitch Developer Portal. Free tier: ~10 req/sec. |
SCREENSCRAPER_USER / SCREENSCRAPER_PASSWORD |
Screenscraper | Account credentials (not API key). Free, community-driven. |
MOBYGAMES_API_KEY |
MobyGames | Paid hobbyist API. Note: RomM recommends Screenscraper as free alternative. |
RETROACHIEVEMENTS_API_KEY |
RetroAchievements | Hash-based achievements via bundled RAHasher binary. |
STEAMGRIDDB_API_KEY |
SteamGridDB | Custom cover art via the search cover button. |
HASHEOUS_API_ENABLED |
Hasheous | Set to true in the live unit env file. Free, hash-based, proxies IGDB data. Fast scans. |
PLAYMATCH_API_ENABLED |
Playmatch | Set to true. Multi-provider hash matching (IGDB, SS, SteamGridDB, RA). |
Config File
RomM uses config.yml for scan settings, available through the admin UI (Scan Settings). Place the file at /home/dank/Containers/romm/config/config.yml on the host.
Key scan config options:
scan:
priority:
metadata:
- igdb
- ss # Screenscraper
artwork:
- igdb
- ss
region:
- us
- eu
- jp
region_mode: prefer_rom_tags # or prefer_config
media:
- box2d
- screenshot
- manual
gamelist:
export: true # Export ES-DE compatible gamelist.xml
Deployment (Quadlet)
Since 2026-09-01 the trio runs as repo-tracked quadlet units, deployed with
./scripts/deploy.sh dankserver --service romm (any of romm,
romm-mariadb, romm-redis triggers the full ordered cutover):
- Units:
dankserver/romm/quadlet/{romm,romm-mariadb,romm-redis}.container→ generatedromm.serviceetc., enabled via the quadlet generator'sdefault.target.wants(is-enabledreportsgenerated). - Secrets: host-local
/home/dank/Containers/romm/env(0600, 15 app vars — compose-provided keys only; image-baked vars likeHOME/PATHmust never enter it, they poison the podman client's service environment). - Network:
dankserver_appnetwith aliasesmariadb/redis(replaces compose service discovery;DB_HOST/REDIS_HOSTstill resolve). - Publish:
8085:8080(PublishPort=, see the seam test on published ports).
Volumes
The live unit mounts one root bind — Volume=/home/dank/Containers/romm:/romm
— so /romm/config, /romm/library, /romm/resources, and /romm/assets
all resolve inside a single host-side data root:
| Container path | Host path |
|---|---|
/romm/* (single root bind) |
/home/dank/Containers/romm/* |
/var/lib/mysql (romm-mariadb) |
/home/dank/Containers/romm/mariadb (mapped subuid owner — never chown) |
/data (romm-redis) |
/home/dank/Containers/romm/redis (mapped subuid owner) |
The cutover rescued RomM's anonymous /romm volume (assets, plus empty
mountpoint stubs that shadowed nothing) into the data root before first unit
start — the mechanism behind the original "RomM data wiped" incident is now
structurally impossible: the units declare bind mounts only.
Docker Compose (reference — retired 2026-09-01, superseded by the quadlet units above)
services:
romm:
image: ghcr.io/rommapp/romm:latest
container_name: romm
restart: unless-stopped
environment:
ROMM_USERNAME: "${ROMM_USERNAME}"
ROMM_PASSWORD: "${ROMM_PASSWORD}"
ROMM_AUTH_SECRET_KEY: "${ROMM_AUTH_SECRET_KEY}"
DB_HOST: mariadb
DB_NAME: romm
DB_USER: "${ROMM_DB_USER}"
DB_PASSWD: "${ROMM_DB_PASSWD}"
REDIS_HOST: redis
ports:
- "8085:8080"
volumes:
- /opt/romm/library:/romm/library
- /opt/romm/resources:/romm/resources
- /opt/romm/config:/romm/config
depends_on:
mariadb:
condition: service_healthy
redis:
condition: service_healthy
mariadb:
image: docker.io/mariadb:11
container_name: romm-mariadb
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: "${MARIADB_ROOT_PASSWORD}"
MARIADB_DATABASE: romm
MARIADB_USER: "${ROMM_DB_USER}"
MARIADB_PASSWORD: "${ROMM_DB_PASSWD}"
volumes:
- /opt/romm/mariadb:/var/lib/mysql
healthcheck:
test: ["CMD", "mariadb-admin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 3
redis:
image: docker.io/redis:7-alpine
container_name: romm-redis
restart: unless-stopped
volumes:
- /opt/romm/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
Healthcheck
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
Gotchas
- First login overwrites env credentials. The
ROMM_PASSWORDenv var sets the initial password. After first login, the admin password is controlled in the UI. The env var only applies on first boot. - MariaDB and Redis are required. RomM 5.2.0 no longer supports SQLite-only deployments. Both MariaDB and Redis must be running.
- 5.3.0 breaking change (2026-09-21).
filesystem.roms_folder/firmware_folderare removed; the scan root must be expressed viafilesystem.structureinconfig.yml(see the Config File section above). New env vars:SCAN_WORKERS,WEB_SERVER_CONCURRENCY,DB_POOL_RECYCLE_SECONDS. The rolling:latesttag will pick this up on the next pull — migrateconfig.ymlbefore redeploying, or the scan root silently goes empty. - Reverse proxy cache stale index.html. Purge Caddy proxy cache after RomM version bumps to avoid serving a stale frontend after an upgrade.
- RAHasher build time. Enabling RetroAchievements hashing increases the first image build. Skip unless you need achievement data.
- MobyGames is paid. The hobbyist API has strict rate limits. Screenscraper is the recommended free alternative.
- OIDC requires additional services. Authentik, Keycloak, or another OIDC provider must be running before enabling
OIDC_ENABLED.
See Also
- Dankserver Stack
- RomM-Scraping — metadata providers, cover art, naming conventions, emulator integration
- Calibre-Web — sibling library web UI