Sign inSign up

blackoutsecure/emulationstation-de

By blackoutsecure

•Updated 6 months ago

LinuxServer.io–style containerized build of a fast, modern frontend for retro game browsing.

Image
Developer tools
Web servers
Operating systems
0

100K+

blackoutsecure/emulationstation-de repository overview

emulationstation-de logo

⁠docker-emulationstation-de

GitHub Stars Docker Pulls GitHub Release Release CI Docker CI License

Unofficial community image for ES-DE Frontend⁠, built with LinuxServer.io-style container patterns for Ubuntu, hardened runtime defaults, direct local-display operation, and optional Balena publishing. Available in two base image variants: standard (local X) and Selkies (browser-based streaming).

Sponsored and maintained by Blackout Secure⁠.

Important

This repository is not an official LinuxServer.io image release.

⁠Overview

This project packages upstream ES-DE Frontend⁠ into an easy-to-run container image for cabinets, desktops, HTPCs, and handheld Linux systems where direct GPU and input passthrough matters more than browser remoting.

Quick links:

balena deploy button


⁠Table of Contents


⁠Quick Start

5-minute standalone setup (internal X server — no host X required):

docker compose up -d

The default docker-compose.yml⁠ starts its own Xorg server inside the container (ESDE_USE_INTERNAL_X=1), so no host display server is needed. This is ideal for kiosk, cabinet, HTPC, and Balena deployments.

Alternative: use an existing host X server:

xhost +local:docker
docker run -d \
  --name=emulationstation \
  -e TZ=Etc/UTC \
  -e DISPLAY=:0 \
  -v /path/to/config:/config \
  -v /path/to/roms:/roms:ro \
  -v /tmp/.X11-unix:/tmp/.X11-unix:ro \
  --device=/dev/dri:/dev/dri \
  --device=/dev/input:/dev/input \
  --shm-size=1gb \
  --restart unless-stopped \
  blackoutsecure/emulationstation-de:latest

For compose examples, device passthrough, Balena deployment, and local build options, see Usage⁠ below.


⁠Image Availability

Docker Hub (Recommended):

  • All images are published to Docker Hub⁠
  • Simple pull command: docker pull blackoutsecure/emulationstation-de:latest
  • Multi-arch support: amd64, arm64
  • No registry prefix needed when pulling from Docker Hub
  • Two base image variants: default (local X) and selkies (browser-based streaming via docker-baseimage-selkies⁠)

Default variant — based on linuxserver/baseimage-ubuntu:noble:

# Pull latest stable
docker pull blackoutsecure/emulationstation-de:latest

# Pull specific upstream version
docker pull blackoutsecure/emulationstation-de:<version>

# Pull dev channel
docker pull blackoutsecure/emulationstation-de:latest-dev

Selkies variant — based on linuxserver/baseimage-selkies:ubuntunoble:

# Pull latest stable selkies
docker pull blackoutsecure/emulationstation-de:latest-selkies

# Pull specific upstream version selkies
docker pull blackoutsecure/emulationstation-de:<version>-selkies

# Pull dev channel selkies
docker pull blackoutsecure/emulationstation-de:latest-dev-selkies

⁠About The ES-DE Application

ES-DE Frontend⁠ is an EmulationStation-derived frontend used to browse ROM libraries, present metadata and media, and launch external emulators from a controller-friendly interface.

This container packages ES-DE for direct local-display environments. The default mode starts an internal Xorg server inside the container, requiring no host display server. Alternatively, it can connect to an existing host X11 server via socket mounting. The runtime supports writable config persistence and optional passthrough for GPU, input, audio, and USB devices.

Upstream project details:


⁠Supported Architectures

This image is published as a multi-arch manifest. Pulling blackoutsecure/emulationstation-de:latest retrieves the correct image for your host architecture.

The architectures supported by this image are:

ArchitectureDefault TagsSelkies Tags
x86-64latest, latest-devlatest-selkies, latest-dev-selkies
arm64latest, latest-devlatest-selkies, latest-dev-selkies

Tag scheme:

VariantStableDevPinned
Defaultlatest, <version>latest-devsha-<commit>-stable, sha-<commit>-dev
Selkieslatest-selkies, <version>-selkieslatest-dev-selkiessha-<commit>-stable-selkies, sha-<commit>-dev-selkies

⁠Usage

Standalone (internal X server — recommended for dedicated devices):

---
services:
  emulationstation:
    image: blackoutsecure/emulationstation-de:latest
    container_name: emulationstation
    environment:
      - TZ=Etc/UTC
      - DISPLAY_NUM=0
      - XDG_RUNTIME_DIR=/run/esde
      - ESDE_USE_INTERNAL_X=1
      - UDEV=1
    volumes:
      - /path/to/config:/config
      - /path/to/roms:/roms:ro
      - /path/to/bios:/bios:ro
    devices:
      - /dev/dri:/dev/dri
      - /dev/input:/dev/input
      - /dev/uinput:/dev/uinput
      - /dev/snd:/dev/snd
    privileged: true
    tmpfs:
      - /var/tmp
      - /run:exec
    shm_size: 1gb
    restart: unless-stopped

Using an existing host X server:

---
services:
  emulationstation:
    image: blackoutsecure/emulationstation-de:latest
    container_name: emulationstation
    environment:
      - TZ=Etc/UTC
      - DISPLAY=:0
      - UDEV=1
    volumes:
      - /path/to/config:/config
      - /path/to/roms:/roms:ro
      - /path/to/bios:/bios:ro
      - /tmp/.X11-unix:/tmp/.X11-unix:ro
    devices:
      - /dev/dri:/dev/dri
      - /dev/input:/dev/input
    privileged: true
    security_opt:
      - no-new-privileges:true
    tmpfs:
      - /tmp:exec,nosuid,nodev,size=512m
      - /var/tmp:nosuid,nodev,size=256m
      - /run:exec,nosuid,nodev,size=64m
    shm_size: 1gb
    restart: unless-stopped
⁠Docker Compose Hardware Examples

Intel/AMD GPU + input:

---
services:
  emulationstation:
    image: blackoutsecure/emulationstation-de:latest
    container_name: emulationstation
    environment:
      - TZ=Etc/UTC
      - DISPLAY_NUM=0
      - XDG_RUNTIME_DIR=/run/esde
      - ESDE_USE_INTERNAL_X=1
      - UDEV=1
    volumes:
      - /path/to/config:/config
      - /path/to/roms:/roms:ro
      - /path/to/bios:/bios:ro
    devices:
      - /dev/dri:/dev/dri
      - /dev/input:/dev/input
      - /dev/snd:/dev/snd
    privileged: true
    tmpfs:
      - /var/tmp
      - /run:exec
    shm_size: 1gb
    restart: unless-stopped

Nvidia GPU:

---
services:
  emulationstation:
    image: blackoutsecure/emulationstation-de:latest
    container_name: emulationstation
    environment:
      - TZ=Etc/UTC
      - DISPLAY_NUM=0
      - XDG_RUNTIME_DIR=/run/esde
      - ESDE_USE_INTERNAL_X=1
      - UDEV=1
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all
    volumes:
      - /path/to/config:/config
      - /path/to/roms:/roms:ro
      - /path/to/bios:/bios:ro
    gpus: all
    devices:
      - /dev/input:/dev/input
      - /dev/snd:/dev/snd
    privileged: true
    tmpfs:
      - /var/tmp
      - /run:exec
    shm_size: 1gb
    restart: unless-stopped

Arcade input and USB passthrough:

---
services:
  emulationstation:
    image: blackoutsecure/emulationstation-de:latest
    container_name: emulationstation
    environment:
      - TZ=Etc/UTC
      - DISPLAY_NUM=0
      - XDG_RUNTIME_DIR=/run/esde
      - ESDE_USE_INTERNAL_X=1
      - UDEV=1
    volumes:
      - /path/to/config:/config
      - /path/to/roms:/roms:ro
      - /path/to/bios:/bios:ro
    devices:
      - /dev/dri:/dev/dri
      - /dev/input:/dev/input
      - /dev/uinput:/dev/uinput
      - /dev/bus/usb:/dev/bus/usb
      - /dev/snd:/dev/snd
    privileged: true
    tmpfs:
      - /var/tmp
      - /run:exec
    shm_size: 1gb
    restart: unless-stopped
⁠Docker CLI (click here for more info⁠)

Standalone (internal X server):

docker run -d \
  --name=emulationstation \
  --restart unless-stopped \
  --privileged \
  -e TZ=Etc/UTC \
  -e DISPLAY_NUM=0 \
  -e XDG_RUNTIME_DIR=/run/esde \
  -e ESDE_USE_INTERNAL_X=1 \
  -e UDEV=1 \
  -v /path/to/config:/config \
  -v /path/to/roms:/roms:ro \
  -v /path/to/bios:/bios:ro \
  --device=/dev/dri:/dev/dri \
  --device=/dev/input:/dev/input \
  --device=/dev/snd:/dev/snd \
  --tmpfs /var/tmp \
  --tmpfs /run:exec \
  --shm-size=1gb \
  blackoutsecure/emulationstation-de:latest

Using an existing host X server:

xhost +local:docker
docker run -d \
  --name=emulationstation \
  --restart unless-stopped \
  --privileged \
  -e TZ=Etc/UTC \
  -e DISPLAY=:0 \
  -e UDEV=1 \
  -v /path/to/config:/config \
  -v /path/to/roms:/roms:ro \
  -v /path/to/bios:/bios:ro \
  -v /tmp/.X11-unix:/tmp/.X11-unix:ro \
  --device=/dev/dri:/dev/dri \
  --device=/dev/input:/dev/input \
  --device=/dev/snd:/dev/snd \
  --shm-size=1gb \
  blackoutsecure/emulationstation-de:latest
⁠Balena Deployment

This image can also be deployed to Balena-powered devices using the included docker-compose.yml⁠ file (Balena labels are included and harmlessly ignored by standard Docker).

balena push <your-app-slug>

Recommended Balena fleet variables for Raspberry Pi 4:

Set these via the Balena dashboard or CLI to ensure proper GPU and audio support:

# Allocate GPU memory for OpenGL rendering (default is only 16MB)
balena env set RESIN_HOST_CONFIG_gpu_mem 128 --fleet <your-fleet>

# Force HDMI output even if no display is detected at boot
balena env set BALENA_HOST_CONFIG_hdmi_force_hotplug 1 --fleet <your-fleet>

# Ensure audio device tree overlay is enabled
balena env set RESIN_HOST_CONFIG_dtparam '"i2c_arm=on","spi=on","audio=on"' --fleet <your-fleet>

For deployment via the web interface, use the deploy button in this repository. See Balena documentation⁠ for details.


⁠RetroStack Emulator Integration

Important

ES-DE is a **frontend only** — it browses your game library and provides a controller-friendly UI, but it does **not** include any emulator. It launches emulators (typically RetroArch) as child processes. Without an emulator running, games will fail to launch with: ``` Error: %EMULATOR_RETROARCH% -L %CORE_RETROARCH%/gambatte_libretro.so %ROM% ```

Emulators are provided by RetroStack⁠ — a companion project that packages RetroArch, PPSSPP, and Dolphin as separate Docker containers. Each RetroStack image can run standalone (starting its own internal Xorg server and launching the emulator GUI directly — no host X required) or in daemon mode for integration with ES-DE. In daemon mode, both containers share a control volume and the same X11 display. ES-DE communicates with emulator containers via FIFO control pipes. The emulator container exits automatically after the emulator process ends, or after an idle timeout (default 10 minutes, configurable via RETROSTACK_IDLE_TIMEOUT).

┌──────────────────────────────┐                 ┌──────────────────────────┐
│  RetroStack                  │                 │  emulationstation-de     │
│  (docker-retrostack)         │                 │  (this repo)             │
│                              │                 │                          │
│  Emulator binary stays here  │  control pipe   │  User selects game       │
│  Listens on FIFO for launch  │◀────────────────│  retrostack-emulator-    │
│  commands, runs emulator on  │  /run/retro*/   │  launch writes to FIFO   │
│  shared X11 display          │────────────────▶│  reads exit code back    │
│                              │  exit status    │                          │
└──────────────────────────────┘                 └──────────────────────────┘
# Start ES-DE + RetroStack emulators
docker compose --profile default --profile retrostack up -d

How it works:

  1. Startup: RetroStack emulator containers create FIFO pipes at /run/retrostack-emulators/<name>.cmd and .status, then wait for a launch command (or time out after RETROSTACK_IDLE_TIMEOUT seconds)
  2. Discovery: ES-DE discovers the pipes on startup and symlinks retrostack-emulator-launch as each emulator name on PATH
  3. Game launch: When the user selects a game, ES-DE calls the symlink. retrostack-emulator-launch writes the args to the .cmd pipe
  4. Play: The emulator container reads it and runs the game on the shared X11 display
  5. Return: When the game exits, the emulator writes the exit code to the .status pipe, giving control back to ES-DE. The emulator container then stops

Startup logs when RetroStack is connected:

[svc-esde] Emulator: RetroStack [retroarch]
[svc-esde] RetroStack: retroarch (FIFO @ /run/retrostack-emulators)

Startup logs when no emulators are found:

[svc-esde] Emulator: WARNING no emulators found — games will fail
[svc-esde]   Start RetroStack: docker compose --profile retrostack up -d
⁠Control Pipe Protocol

Both containers share a volume at /run/retrostack-emulators/. Each emulator creates:

FileDirectionPurpose
<name>.cmdES-DE → EmulatorFIFO — write emulator args (one line, shell-quoted)
<name>.statusEmulator → ES-DEFIFO — read exit code after game finishes
⁠Supported Emulators

ES-DE supports many emulators⁠. RetroStack currently packages:

EmulatorDocker Image TagWhat It Runs
RetroArchretrostack:retroarchMulti-system via libretro cores (recommended)
PPSSPPretrostack:ppssppPlayStation Portable
Dolphinretrostack:dolphin-emuGameCube / Wii

See docker-retrostack⁠ for adding new emulators.

⁠RetroStack Environment Variables

These variables are set in the x-retrostack-common anchor and inherited by all RetroStack services:

ParameterDefaultFunction
DISPLAY:0X11 display for emulator rendering
PULSE_SERVERunix:/run/pulse/nativePulseAudio server socket
RETROSTACK_IDLE_TIMEOUT600Seconds to wait for a launch command before the container exits (default: 600, set to 0 to disable)
RETROSTACK_FRONTEND_MODEdaemonstandalone (default in RetroStack) launches the emulator's own GUI; daemon listens on FIFO for ES-DE integration. Set to daemon here for integration mode
RETROSTACK_EMULATORS_CONTROL/run/retrostack-emulatorsControl pipe directory (client-side)
RETROSTACK_USE_INTERNAL_X1Start an internal Xorg server in standalone mode (1=auto, 0=disabled — use external X socket). Not used in daemon mode
RETROSTACK_AUDIO_OUTPUTautoAudio output selection: auto (USB > analog > HDMI), analog, hdmi, usb. Matches ES-DE's ESDE_AUDIO_OUTPUT behavior

⁠Parameters

⁠Compose Profiles
ProfileCommandDescription
defaultdocker compose --profile default up -dLocal display / kiosk — direct output to a connected monitor via KMSDRM or X11. Best for arcade cabinets, HTPC, and Balena with a physical display.
selkiesdocker compose --profile selkies up -dSelkies WebRTC streaming — stream

Tag summary

Content type

Image

Digest

sha256:c6ea0d858…

Size

320.3 MB

Last updated

6 months ago

docker pull blackoutsecure/emulationstation-de