LinuxServer.io–style containerized build of a fast, modern frontend for retro game browsing.
100K+
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.
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:
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.
Docker Hub (Recommended):
docker pull blackoutsecure/emulationstation-de:latestDefault 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
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:
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:
| Architecture | Default Tags | Selkies Tags |
|---|---|---|
| x86-64 | latest, latest-dev | latest-selkies, latest-dev-selkies |
| arm64 | latest, latest-dev | latest-selkies, latest-dev-selkies |
Tag scheme:
| Variant | Stable | Dev | Pinned |
|---|---|---|---|
| Default | latest, <version> | latest-dev | sha-<commit>-stable, sha-<commit>-dev |
| Selkies | latest-selkies, <version>-selkies | latest-dev-selkies | sha-<commit>-stable-selkies, sha-<commit>-dev-selkies |
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
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
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
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.
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:
/run/retrostack-emulators/<name>.cmd and .status, then wait for a launch command (or time out after RETROSTACK_IDLE_TIMEOUT seconds)retrostack-emulator-launch as each emulator name on PATHretrostack-emulator-launch writes the args to the .cmd pipe.status pipe, giving control back to ES-DE. The emulator container then stopsStartup 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
Both containers share a volume at /run/retrostack-emulators/. Each emulator creates:
| File | Direction | Purpose |
|---|---|---|
<name>.cmd | ES-DE → Emulator | FIFO — write emulator args (one line, shell-quoted) |
<name>.status | Emulator → ES-DE | FIFO — read exit code after game finishes |
ES-DE supports many emulators. RetroStack currently packages:
| Emulator | Docker Image Tag | What It Runs |
|---|---|---|
| RetroArch | retrostack:retroarch | Multi-system via libretro cores (recommended) |
| PPSSPP | retrostack:ppsspp | PlayStation Portable |
| Dolphin | retrostack:dolphin-emu | GameCube / Wii |
See docker-retrostack for adding new emulators.
These variables are set in the x-retrostack-common anchor and inherited by all RetroStack services:
| Parameter | Default | Function |
|---|---|---|
DISPLAY | :0 | X11 display for emulator rendering |
PULSE_SERVER | unix:/run/pulse/native | PulseAudio server socket |
RETROSTACK_IDLE_TIMEOUT | 600 | Seconds to wait for a launch command before the container exits (default: 600, set to 0 to disable) |
RETROSTACK_FRONTEND_MODE | daemon | standalone (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-emulators | Control pipe directory (client-side) |
RETROSTACK_USE_INTERNAL_X | 1 | Start an internal Xorg server in standalone mode (1=auto, 0=disabled — use external X socket). Not used in daemon mode |
RETROSTACK_AUDIO_OUTPUT | auto | Audio output selection: auto (USB > analog > HDMI), analog, hdmi, usb. Matches ES-DE's ESDE_AUDIO_OUTPUT behavior |
| Profile | Command | Description |
|---|---|---|
default | docker compose --profile default up -d | Local display / kiosk — direct output to a connected monitor via KMSDRM or X11. Best for arcade cabinets, HTPC, and Balena with a physical display. |
selkies | docker compose --profile selkies up -d | Selkies WebRTC streaming — stream |
Content type
Image
Digest
sha256:c6ea0d858…
Size
320.3 MB
Last updated
6 months ago
docker pull blackoutsecure/emulationstation-de