Phase 1/2 of the podman standardization plan: service pages updated to the quadlet reality (units, Containers data roots, env-file secret convention, the v1-generator findings each caught live), Storage Policy documents the two rootless ownership regimes and the merge-move migration, Deployment Flow's service-manager table no longer claims dankserver media is bare inventory-only. Bundle change log entry added.
8.4 KiB
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 — Hostname: romm.dankserver.local — Docs: https://docs.romm.app
Facts
| Item | Value |
|---|---|
| Latest version | 5.2.0 (released 2026-07-29) |
| Image | ghcr.io/rommapp/romm:latest |
| 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
RomM 5.2.0 requires three supporting services. The compose stack includes romm, mariadb, and redis (or 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. 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
| Container path | Host path |
|---|---|
/romm/library |
/home/dank/Containers/romm/library |
/romm/resources |
/home/dank/Containers/romm/resources |
/romm/config |
/home/dank/Containers/romm/config |
/var/lib/mysql |
/home/dank/Containers/romm/mariadb (mapped subuid owner — never chown) |
/data (redis) |
/home/dank/Containers/romm/redis (mapped subuid owner) |
The library volume contains ROM files and subdirectories per platform. The resources volume stores cached artwork, metadata, and the asset cache. The config volume holds config.yml and other configuration.
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.
- 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