feat: Enhance game station setup and configuration

- Updated README with detailed instructions for creating a dedicated Ansible user on Linux, including SSH key setup and passwordless sudo.
- Added userConfigurations.json for Steam ROM Manager with configurations for various gaming consoles.
- Introduced scripts for managing Gamescope and Steam sessions, including launch scripts for various emulators (Genesis, PSP, RPCS3, SNES).
- Created systemd service for Gamescope session management.
- Developed Ansible playbook for configuring Fedora for optimized Sunshine and Gamescope streaming, including user setup and system configurations.
- Updated Prometheus configuration to reflect changes in exporter targets.
- Commented out the Devolo exporter module in Terraform configuration for future reference.
This commit is contained in:
2025-10-25 23:54:05 +02:00
parent 161efa5230
commit adc893de6e
18 changed files with 1078 additions and 18 deletions
+33 -5
View File
@@ -30,15 +30,43 @@ sectool exec cntb get instances --oauth2-clientid="$CONTABO_CLIENT_ID" --oauth2-
# Windows # Windows
## Create a Dedicated “Ansible” User (One-Time Setup) ## Create a Dedicated “Ansible” User (One-Time Setup) — Linux
``` ```
net user provision <secure_password> /add # Create the provision user (Debian/Ubuntu)
net localgroup Administrators provision /add sudo useradd -m -s /bin/bash -G sudo provision
# Prevent password expiration sudo passwd provision
wmic UserAccount where "Name='provision'" set PasswordExpires=FALSE
# OR (RHEL/CentOS/Fedora)
sudo useradd -m -s /bin/bash -G wheel provision
sudo passwd provision
``` ```
```
# Allow passwordless sudo for the provision user (recommended for Ansible)
echo 'provision ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/provision
sudo chmod 440 /etc/sudoers.d/provision
# Or edit safely:
sudo visudo -f /etc/sudoers.d/provision
# and add:
# provision ALL=(ALL) NOPASSWD:ALL
```
```
# Install SSH authorized key for the provision user (recommended over passwords)
sudo -u provision mkdir -p /home/provision/.ssh
sudo -u provision chmod 700 /home/provision/.ssh
echo "<your_public_key_here>" | sudo -u provision tee /home/provision/.ssh/authorized_keys
sudo -u provision chmod 600 /home/provision/.ssh/authorized_keys
```
Notes:
- Replace <your_public_key_here> with the actual public key.
- Use a strong password if you must set one; prefer SSH keys.
- For tighter security, restrict the sudoers entry to only the commands Ansible requires instead of ALL.
- Validate sudoers syntax with visudo to avoid lockout.
## Configure windows to allow Ansible to connect via WinRM ## Configure windows to allow Ansible to connect via WinRM
Copy the script located in scripts "ConfigureRemotingForAnsible.ps1" and run it on the target machine. Copy the script located in scripts "ConfigureRemotingForAnsible.ps1" and run it on the target machine.
@@ -0,0 +1,368 @@
[
{
"parserType": "Glob",
"configTitle": "Sony PlayStation 3 - RPCS3 (Extracted ISO)",
"steamDirectory": "${steamdirglobal}",
"romDirectory": "/home/gameuser/.config/rpcs3/games",
"steamCategories": [
"PS3"
],
"executableArgs": "\"${filePath}\"",
"executableModifier": "\"${exePath}\"",
"startInDirectory": "",
"titleModifier": "${fuzzyTitle}",
"steamInputEnabled": "1",
"imageProviders": [
"sgdb"
],
"onlineImageQueries": [
"${fuzzyTitle}"
],
"imagePool": "${fuzzyTitle}",
"drmProtect": false,
"userAccounts": {
"specifiedAccounts": [
"Global"
]
},
"parserInputs": {
"glob": "${title}/PS3_GAME/USRDIR/@(eboot.bin|EBOOT.BIN)"
},
"executable": {
"path": "/home/gameuser/.local/bin/launch_rpcs3.sh",
"shortcutPassthrough": false,
"appendArgsToExecutable": true
},
"titleFromVariable": {
"limitToGroups": [
"PS3"
],
"caseInsensitiveVariables": false,
"skipFileIfVariableWasNotFound": false
},
"fuzzyMatch": {
"replaceDiacritics": true,
"removeCharacters": true,
"removeBrackets": true
},
"controllers": {
"ps4": null,
"ps5": null,
"ps5_edge": null,
"xbox360": null,
"xboxone": null,
"xboxelite": null,
"switch_joycon_left": null,
"switch_joycon_right": null,
"switch_pro": null,
"neptune": null,
"steamcontroller_gordon": null
},
"imageProviderAPIs": {
"sgdb": {
"nsfw": false,
"humor": false,
"styles": [],
"stylesHero": [],
"stylesLogo": [],
"stylesIcon": [],
"imageMotionTypes": [
"static"
],
"sizes": [],
"sizesHero": [],
"sizesIcon": []
}
},
"defaultImage": {
"tall": "",
"long": "",
"hero": "",
"logo": "",
"icon": ""
},
"localImages": {
"tall": "",
"long": "",
"hero": "",
"logo": "",
"icon": ""
},
"parserId": "176098777083347867",
"disabled": false,
"version": 25
},
{
"parserType": "Glob",
"configTitle": "Sega Genesis/Mega Drive - Retroarch - Genesis Plus GX",
"steamDirectory": "${steamdirglobal}",
"romDirectory": "/home/gameuser/Emulation/genesis",
"steamCategories": [
"Genesis/Mega Drive"
],
"executableArgs": "\"${filePath}\"",
"executableModifier": "\"${exePath}\"",
"startInDirectory": "",
"titleModifier": "${fuzzyTitle}",
"steamInputEnabled": "1",
"imageProviders": [
"sgdb"
],
"onlineImageQueries": [
"${fuzzyTitle}"
],
"imagePool": "${fuzzyTitle}",
"drmProtect": false,
"userAccounts": {
"specifiedAccounts": [
"Global"
]
},
"parserInputs": {
"glob": "${title}@(.7z|.7Z|.gen|.GEN|.md|.MD|.smd|.SMD|.zip|.ZIP|.bin|.BIN)"
},
"executable": {
"path": "/home/gameuser/.local/bin/launch_genesis.sh",
"shortcutPassthrough": false,
"appendArgsToExecutable": true
},
"titleFromVariable": {
"limitToGroups": [],
"caseInsensitiveVariables": false,
"skipFileIfVariableWasNotFound": false
},
"fuzzyMatch": {
"replaceDiacritics": true,
"removeCharacters": true,
"removeBrackets": true
},
"controllers": {
"ps4": null,
"ps5": null,
"ps5_edge": null,
"xbox360": null,
"xboxone": null,
"xboxelite": null,
"switch_joycon_left": null,
"switch_joycon_right": null,
"switch_pro": null,
"neptune": null,
"steamcontroller_gordon": null
},
"imageProviderAPIs": {
"sgdb": {
"nsfw": false,
"humor": false,
"styles": [],
"stylesHero": [],
"stylesLogo": [],
"stylesIcon": [],
"imageMotionTypes": [
"static"
],
"sizes": [],
"sizesHero": [],
"sizesIcon": []
}
},
"defaultImage": {
"tall": "",
"long": "",
"hero": "",
"logo": "",
"icon": ""
},
"localImages": {
"tall": "",
"long": "",
"hero": "",
"logo": "",
"icon": ""
},
"parserId": "176029625316137679",
"disabled": false,
"version": 25
},
{
"parserType": "Glob",
"configTitle": "Sony PlayStation Portable - Retroarch - PPSSPP",
"steamDirectory": "${steamdirglobal}",
"romDirectory": "/home/gameuser/Emulation/psp",
"steamCategories": [
"PSP"
],
"executableArgs": "\"${filePath}\"",
"executableModifier": "\"${exePath}\"",
"startInDirectory": "",
"titleModifier": "${fuzzyTitle}",
"steamInputEnabled": "1",
"imageProviders": [
"sgdb"
],
"onlineImageQueries": [
"${fuzzyTitle}"
],
"imagePool": "${fuzzyTitle}",
"drmProtect": false,
"userAccounts": {
"specifiedAccounts": [
"Global"
]
},
"parserInputs": {
"glob": "${title}@(.7z|.7Z|.elf|.ELF|.cso|.CSO|.iso|.ISO|.pbp|.PBP|.prx|.PRX)"
},
"executable": {
"path": "/home/gameuser/.local/bin/launch_ppspp.sh",
"shortcutPassthrough": false,
"appendArgsToExecutable": true
},
"titleFromVariable": {
"limitToGroups": [],
"caseInsensitiveVariables": false,
"skipFileIfVariableWasNotFound": false
},
"fuzzyMatch": {
"replaceDiacritics": true,
"removeCharacters": true,
"removeBrackets": true
},
"controllers": {
"ps4": null,
"ps5": null,
"ps5_edge": null,
"xbox360": null,
"xboxone": null,
"xboxelite": null,
"switch_joycon_left": null,
"switch_joycon_right": null,
"switch_pro": null,
"neptune": null,
"steamcontroller_gordon": null
},
"imageProviderAPIs": {
"sgdb": {
"nsfw": false,
"humor": false,
"styles": [],
"stylesHero": [],
"stylesLogo": [],
"stylesIcon": [],
"imageMotionTypes": [
"static"
],
"sizes": [],
"sizesHero": [],
"sizesIcon": []
}
},
"defaultImage": {
"tall": "",
"long": "",
"hero": "",
"logo": "",
"icon": ""
},
"localImages": {
"tall": "",
"long": "",
"hero": "",
"logo": "",
"icon": ""
},
"parserId": "176029685701892152",
"disabled": false,
"version": 25
},
{
"parserType": "Glob",
"configTitle": "Nintendo SNES - Retroarch - Mesen-S",
"steamDirectory": "${steamdirglobal}",
"romDirectory": "/home/gameuser/Emulation/snes",
"steamCategories": [
"SNES"
],
"executableArgs": "\"${filePath}\"",
"executableModifier": "\"${exePath}\"",
"startInDirectory": "",
"titleModifier": "${fuzzyTitle}",
"steamInputEnabled": "1",
"imageProviders": [
"sgdb"
],
"onlineImageQueries": [
"${fuzzyTitle}"
],
"imagePool": "${fuzzyTitle}",
"drmProtect": false,
"userAccounts": {
"specifiedAccounts": [
"Global"
]
},
"parserInputs": {
"glob": "${title}@(.7z|.7Z|.bml|.BML|.sfc|.SFC|.smc|.SMC|.zip|.ZIP)"
},
"executable": {
"path": "/home/gameuser/.local/bin/launch_snes.sh",
"shortcutPassthrough": false,
"appendArgsToExecutable": true
},
"titleFromVariable": {
"limitToGroups": [],
"caseInsensitiveVariables": false,
"skipFileIfVariableWasNotFound": false
},
"fuzzyMatch": {
"replaceDiacritics": true,
"removeCharacters": true,
"removeBrackets": true
},
"controllers": {
"ps4": null,
"ps5": null,
"ps5_edge": null,
"xbox360": null,
"xboxone": null,
"xboxelite": null,
"switch_joycon_left": null,
"switch_joycon_right": null,
"switch_pro": null,
"neptune": null,
"steamcontroller_gordon": null
},
"imageProviderAPIs": {
"sgdb": {
"nsfw": false,
"humor": false,
"styles": [],
"stylesHero": [],
"stylesLogo": [],
"stylesIcon": [],
"imageMotionTypes": [
"static"
],
"sizes": [],
"sizesHero": [],
"sizesIcon": []
}
},
"defaultImage": {
"tall": "",
"long": "",
"hero": "",
"logo": "",
"icon": ""
},
"localImages": {
"tall": "",
"long": "",
"hero": "",
"logo": "",
"icon": ""
},
"parserId": "176029713768938935",
"disabled": false,
"version": 25
}
]
@@ -0,0 +1,9 @@
#!/bin/bash
set -euo pipefail
LOGFILE="$HOME/.local/logs/jupiter-biosupdate.log"
log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; }
log "Starting Jupiter BIOS update..."
log "Arguments passed: ${@}"
echo "Not applicable for this OS"
@@ -0,0 +1,39 @@
#!/bin/bash
set -euo pipefail
LOGFILE="$HOME/.local/logs/gamescope.log"
log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; }
log "Starting Gamescope session..."
CONF_FILE="$HOME/.config/gamescope/gamescope.conf"
[ -f "$CONF_FILE" ] && source "$CONF_FILE"
OUTPUT_CONNECTOR=${OUTPUT_CONNECTOR:-HDMI-A-1}
FRAMERATE=${FRAMERATE:-60}
RESOLUTION=${RESOLUTION:-1920x1080}
WIDTH="${RESOLUTION%x*}"
HEIGHT="${RESOLUTION#*x}"
export __GL_GSYNC_ALLOWED=1
export __GL_VRR_ALLOWED=1
# export __GL_THREADED_OPTIMIZATIONS=1
export __GL_SHADER_DISK_CACHE=1
export __GL_SYNC_TO_VBLANK=0
GAMESCOPE_BIN="$(command -v gamescope || true)"
if [ -z "$GAMESCOPE_BIN" ]; then
log "ERROR: gamescope not found in PATH"
exit 127
fi
HDR_FLAG=""
if [[ "$HDR_ENABLED" == "1" || "$HDR_ENABLED" == "true" || "$HDR_ENABLED" == "yes" ]]; then
HDR_FLAG="--hdr-enabled"
log "HDR flag added: --hdr-enabled"
else
log "HDR disabled, no HDR flag added"
fi
GAMESCOPE_ARGS="--generate-drm-mode fixed --fade-out-duration 200 --cursor-scale-height 720 -f -w $WIDTH -h $HEIGHT --rt --mangoapp -e -O \"$OUTPUT_CONNECTOR\" -r $FRAMERATE $HDR_FLAG"
log "Launching Gamescope: $GAMESCOPE_BIN $GAMESCOPE_ARGS -- /usr/local/bin/launch_steam.sh"
exec "$GAMESCOPE_BIN" ${GAMESCOPE_ARGS} -- /usr/local/bin/launch_steam.sh >>"$LOGFILE" 2>&1
@@ -0,0 +1,112 @@
#!/usr/bin/env bash
set -euo pipefail
LOGFILE="$HOME/.local/logs/steam.log"
export PATH="$HOME/.local/bin:$PATH"
export SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS=0
# There is no way to set a color space for an NV12
# buffer in Wayland. And the color management protocol that is
# meant to let this happen is missing the color range...
# So just workaround this with an ENV var that Remote Play Together
# and Gamescope will use for now.
export GAMESCOPE_NV12_COLORSPACE=k_EStreamColorspace_BT601
export STEAM_GAMESCOPE_HDR_SUPPORTED=1
# Workaround older versions of vkd3d-proton setting this
# too low (desc.BufferCount), resulting in symptoms that are potentially like
# swapchain starvation.
export VKD3D_SWAPCHAIN_LATENCY_FRAMES=3
# Let's try this across the board to see if it breaks anything
# Helps performance in HZD, Cyberpunk, at least
# Expose 8 physical cores, instead of 4c/8t
export WINE_CPU_TOPOLOGY=8:0,1,2,3,4,5,6,7
# To expose vram info from radv's patch we're including
export WINEDLLOVERRIDES=dxgi=n
# Disable automatic audio device switching in steam, now handled by wireplumber
export STEAM_DISABLE_AUDIO_DEVICE_SWITCHING=1
# Enable support for xwayland isolation per-game in Steam
# export STEAM_MULTIPLE_XWAYLANDS=0
# We have NIS support
export STEAM_GAMESCOPE_NIS_SUPPORTED=1
# Enable tearing controls in steam
export STEAM_GAMESCOPE_TEARING_SUPPORTED=1
# Enable VRR controls in steam
export STEAM_GAMESCOPE_VRR_SUPPORTED=1
# When set to 1, a toggle will show up in the steamui to control whether dynamic refresh rate is applied to the steamui
export STEAM_GAMESCOPE_DYNAMIC_REFRESH_IN_STEAM_SUPPORTED=0
# Don't wait for buffers to idle on the client side before sending them to gamescope
export vk_xwayland_wait_ready=false
# Scaling support
export STEAM_GAMESCOPE_FANCY_SCALING_SUPPORT=1
# Color management support
export STEAM_GAMESCOPE_COLOR_MANAGED=1
export STEAM_GAMESCOPE_VIRTUAL_WHITE=1
# Temporary crutch until dummy plane interactions / etc are figured out
export GAMESCOPE_DISABLE_ASYNC_FLIPS=1
export XCURSOR_THEME=steam
export XCURSOR_SCALE=256
log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; }
if [ -r /proc/sys/user/max_user_namespaces ]; then
max_ns="$(cat /proc/sys/user/max_user_namespaces || echo 0)"
if [ "${max_ns:-0}" -eq 0 ]; then
log "ERROR: user.max_user_namespaces is 0. Enable it with: sudo sysctl -w user.max_user_namespaces=15000"
exit 1
fi
fi
if command -v bwrap >/dev/null 2>&1; then
bwrap_bin="$(command -v bwrap)"
if ! [ -u "$bwrap_bin" ]; then
# Not fatal if user namespaces are enabled, but warn for visibility
log "WARN: $bwrap_bin is not setuid root. If Steam still fails, run: sudo dnf reinstall bubblewrap && sudo chmod 4755 /usr/bin/bwrap"
fi
else
log "WARN: bubblewrap (bwrap) not found. Steam may fail to start."
fi
if findmnt -no OPTIONS / | grep -qw nosuid; then
log "WARN: root filesystem is mounted nosuid. Setuid helpers like bubblewrap will not work."
fi
STEAM_BIN="$(command -v steam || true)"
if [ -z "$STEAM_BIN" ]; then
log "ERROR: steam not found in PATH"
exit 127
fi
log "Updating steam: /opt/steamcmd/steamcmd.sh +quit"
/opt/steamcmd/steamcmd.sh +quit >>"$LOGFILE" 2>&1 || {
log "ERROR: Steam update failed"
exit 1
}
log "Updating Steam ROM Manager"
srm add >> "$LOGFILE" 2>&1 || log "ERROR: Steam ROM Manager update failed"
STEAM_ARGS=("-steamdeck" "-steamos3" "-steampal" "-gamepadui" "-pipewire-dmabuf")
log "Launching Steam: $STEAM_BIN ${STEAM_ARGS[*]}"
exec steam "${STEAM_ARGS[@]}" &
sleep 5
systemd-run --user --slice=sunshine.slice --scope sunshine >>"$LOGFILE" 2>&1 || {
log "ERROR: Failed to start Sunshine"
exit 1
} &
tail -f /dev/null
@@ -0,0 +1,30 @@
#!/bin/bash
set -euo pipefail
LOGFILE="$HOME/.local/logs/steamos-select-branch.log"
log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; }
if [[ $# -eq 1 ]]; then
case "$1" in
"-c")
log "Current branch requested"
echo "stable"
exit 0
;;
"-l")
log "Listing available branches"
exit 0
;;
"rel")
log "Legacy branch 'rel' requested"
exit 0
;;
"stable" | "rc" | "beta" | "bc" | "preview" | "pc" | "main" | "staging")
log "Branch '$1' requested"
exit 0
;;
esac
fi
echo "Usage: steamos-select-branch <-c|-l|rel|rc|beta|bc|preview|pc|main>" 1>&2
@@ -0,0 +1,11 @@
#!/bin/bash
set -euo pipefail
LOGFILE="$HOME/.local/logs/steamos-update.log"
log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; }
log "Starting SteamOS update..."
log "Arguments passed: ${@}"
echo "Not applicable for this OS"
# TODO: Implement SteamOS update logic for now inform no update available
exit 7
@@ -0,0 +1,29 @@
[Unit]
Description=Weston Wayland compositor for user gameuser
Wants=graphical.target
Conflicts=getty@tty1.service
After=getty@tty1.service
After=rc-local.service plymouth-start.service systemd-user-sessions.service
[Service]
Slice=gamescope.slice
User=gameuser
PAMName=login
TTYPath=/dev/tty1
TTYReset=yes
TTYVHangup=yes
StandardInput=tty
StandardOutput=journal
StandardError=journal
UtmpIdentifier=tty1
UtmpMode=user
Environment=XDG_SEAT=seat0
Environment=XDG_RUNTIME_DIR=/run/user/%U
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus
ExecStartPre=/usr/bin/chvt 1
ExecStart=/usr/bin/bash /usr/local/bin/launch_gamescope.sh
Restart=always
KeyringMode=shared
[Install]
WantedBy=graphical.target
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
LOGFILE="$HOME/.local/logs/retroarch-genesis.log"
log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; }
RETROARCH_HOME="$HOME/.local/share/Steam/steamapps/common/RetroArch"
if [ ! -d "$RETROARCH_HOME" ]; then
log "ERROR: RetroArch directory not found at $RETROARCH_HOME, install it via Steam"
exit 127
fi
RETROARCH_BIN="$RETROARCH_HOME/retroarch"
RETROARCH_CORE=genesis_plus_gx_libretro.so
if [ ! -f "$RETROARCH_BIN" ] || [ ! -f "$RETROARCH_HOME/cores/$RETROARCH_CORE" ]; then
log "ERROR: retroarch or core not found, install it via Steam"
exit 127
fi
log "Launching RetroArch: $RETROARCH_BIN -L \"$RETROARCH_HOME/cores/$RETROARCH_CORE\" \"${@}\""
cd "$RETROARCH_HOME"
$HOME/.steam/steam/ubuntu12_32/steam-runtime/run.sh "$RETROARCH_BIN" -L "$RETROARCH_HOME/cores/$RETROARCH_CORE" "${@}" >>"$LOGFILE"
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
LOGFILE="$HOME/.local/logs/retroarch-ppsspp.log"
log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; }
RETROARCH_HOME="$HOME/.local/share/Steam/steamapps/common/RetroArch"
if [ ! -d "$RETROARCH_HOME" ]; then
log "ERROR: RetroArch directory not found at $RETROARCH_HOME, install it via Steam"
exit 127
fi
RETROARCH_BIN="$RETROARCH_HOME/retroarch"
RETROARCH_CORE=ppsspp_libretro.so
if [ ! -f "$RETROARCH_BIN" ] || [ ! -f "$RETROARCH_HOME/cores/$RETROARCH_CORE" ]; then
log "ERROR: retroarch or core not found, install it via Steam"
exit 127
fi
log "Launching RetroArch: $RETROARCH_BIN -L \"$RETROARCH_HOME/cores/$RETROARCH_CORE\" \"${@}\""
"$RETROARCH_BIN" -L "$RETROARCH_HOME/cores/$RETROARCH_CORE" "${@}" >>"$LOGFILE"
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
LOGFILE="$HOME/.local/logs/rpcs3.log"
log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; }
RPCS_BIN="$(command -v rpcs3 || true)"
if [ -z "$RPCS_BIN" ]; then
log "ERROR: rpcs3 not found in PATH"
exit 127
fi
log "Launching RPCS3: $RPCS_BIN \"${@}\""
"$RPCS_BIN" --no-gui --fullscreen "${@}" >>"$LOGFILE"
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
LOGFILE="$HOME/.local/logs/retroarch-snes.log"
log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; }
RETROARCH_HOME="$HOME/.local/share/Steam/steamapps/common/RetroArch"
if [ ! -d "$RETROARCH_HOME" ]; then
log "ERROR: RetroArch directory not found at $RETROARCH_HOME, install it via Steam"
exit 127
fi
RETROARCH_BIN="$RETROARCH_HOME/retroarch"
RETROARCH_CORE=mesen-s_libretro.so.so
if [ ! -f "$RETROARCH_BIN" ] || [ ! -f "$RETROARCH_HOME/cores/$RETROARCH_CORE" ]; then
log "ERROR: retroarch or core not found, install it via Steam"
exit 127
fi
log "Launching RetroArch: $RETROARCH_BIN -L \"$RETROARCH_HOME/cores/$RETROARCH_CORE\" \"${@}\""
cd "$RETROARCH_HOME"
"$RETROARCH_BIN" -L "$RETROARCH_HOME/cores/$RETROARCH_CORE" "${@}" >>"$LOGFILE"
+293
View File
@@ -0,0 +1,293 @@
---
- name: Configure Fedora 42 for optimized Sunshine + Gamescope streaming
hosts: game_station
vars:
user_name: "gameuser"
gamescope_conf_dir: "/home/{{ user_name }}/.config/gamescope"
system_bin_dir: "/usr/local/bin"
user_bin_dir: "/home/{{ user_name }}/.local/bin"
systemd_user_dir: "/home/{{ user_name }}/.config/systemd/user"
systemd_system_dir: "/etc/systemd/system"
grub_cfg: "/etc/default/grub"
system_cores: "0,8"
gamescope_cores: "2-7,10-15"
sunshine_cores: "1,9"
tasks:
# --- Base dependencies ---
- name: Run 'dnf copr enable lizardbyte/stable'
become: true
ansible.builtin.command: dnf copr enable -y lizardbyte/stable
failed_when: false
changed_when: false
- name: Ensure core gaming and streaming packages are installed
become: true
ansible.builtin.dnf:
name:
- gamescope
- Sunshine
- steam
- mangohud
- kernel-tools
- util-linux
- mesa-dri-drivers
- vulkan-tools
- jq
- xorg-x11-drv-nvidia
- vulkan
- vulkan-loader
- nvidia-settings
- libepoxy
- weston
- bubblewrap
- waypipe
state: present
- name: Ensure user namespaces are enabled
become: true
ansible.posix.sysctl:
name: user.max_user_namespaces
value: "15000"
state: present
sysctl_set: true
reload: true
- name: Ensure bubblewrap is setuid root (Fedora default)
become: true
ansible.builtin.file:
path: /usr/bin/bwrap
owner: root
group: root
mode: "04755"
- name: Enable cpupower at boot
become: true
ansible.builtin.systemd:
name: cpupower
enabled: true
state: started
# --- Performance kernel options ---
- name: Tune kernel command line for isolation
become: true
ansible.builtin.lineinfile:
path: "{{ grub_cfg }}"
regexp: "^GRUB_CMDLINE_LINUX_DEFAULT="
line: 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash amd_pstate=active mitigations=off threadirqs nohz_full=1-7,9-15 rcu_nocbs=1-7,9-15"'
notify: Update grub
- name: Ensure cpupower governor is performance
become: true
ansible.builtin.command: cpupower frequency-set -g performance
changed_when: false
failed_when: false
- name: Set default target to graphical
become: true
ansible.builtin.command: systemctl set-default graphical.target
changed_when: false
- name: Disable GDM display manager
become: true
ansible.builtin.systemd:
name: gdm
enabled: false
state: stopped
# System actions
- name: Create Gamescope slice
become: true
ansible.builtin.copy:
dest: "{{ systemd_system_dir }}/gamescope.slice"
owner: root
group: root
mode: "0644"
content: |
[Slice]
CPUWeight=100
AllowedCPUs={{ gamescope_cores }}
- name: Install Systemd service files
become: true
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/systemd/system/{{ item | basename }}"
mode: "0644"
owner: root
group: root
loop: "{{ query('fileglob', 'game_station/systemd/system/*.service') }}"
notify: Reload systemd daemon for system services
- name: Install System scripts
become: true
ansible.builtin.copy:
src: "{{ item }}"
dest: "{{ system_bin_dir }}/{{ item | basename }}"
owner: root
group: root
mode: "0755"
loop: "{{ query('fileglob', 'game_station/system/*') }}"
- name: Create system directories
become: true
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: root
group: root
mode: "0755"
loop:
- /root/.local/logs
- name: Create log file for Jupiter BIOS update (dummy file)
become: true
ansible.builtin.file:
path: /root/.local/logs/jupiter-biosupdate.log
state: touch
owner: root
group: root
mode: "0644"
# User actions
- name: Create game group
become: true
ansible.builtin.group:
name: "{{ user_name }}"
state: present
- name: Create dedicated game user
become: true
ansible.builtin.user:
name: "{{ user_name }}"
groups:
- "{{ user_name }}"
- wheel
- video
- audio
- input
shell: /bin/bash
create_home: true
state: present
- name: Add user to sudoers with no password
become: true
ansible.builtin.copy:
dest: "/etc/sudoers.d/{{ user_name }}"
owner: root
group: root
mode: "0440"
content: "{{ user_name }} ALL=(ALL) NOPASSWD: ALL"
- name: Create directories
become: true
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: "0755"
loop:
- "{{ gamescope_conf_dir }}"
- "{{ user_bin_dir }}"
- "{{ systemd_user_dir }}"
- "/home/{{ user_name }}/.local/logs"
- "/opt/steamcmd"
- "/home/{{ user_name }}/.config/steam-rom-manager/userData"
- "/home/{{ user_name }}/Emulation"
- "/home/{{ user_name }}/Emulation/snes"
- "/home/{{ user_name }}/Emulation/psp"
- "/home/{{ user_name }}/Emulation/genesis"
- "/home/{{ user_name }}/RetroArch/shaders"
- "/home/{{ user_name }}/RetroArch/config"
- name: Download steamtools
become: true
ansible.builtin.get_url:
url: "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz"
dest: "/tmp/steamcmd_linux.tar.gz"
mode: "0644"
owner: "{{ user_name }}"
group: "{{ user_name }}"
register: steamcmd_download
- name: Extract steamtools
become: true
ansible.builtin.unarchive:
src: "/tmp/steamcmd_linux.tar.gz"
dest: "/opt/steamcmd"
remote_src: true
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: "0755"
- name: Create symlink for Steam logs
become: true
ansible.builtin.file:
src: "/home/{{ user_name }}/.steam/steam/logs"
dest: "/home/{{ user_name }}/.local/logs/steam"
state: link
owner: "{{ user_name }}"
group: "{{ user_name }}"
- name: Copy steam-rom-manager configurations
become: true
ansible.builtin.copy:
src: "game_station/srm/userConfigurations.json"
dest: "/home/{{ user_name }}/.config/steam-rom-manager/userData/userConfigurations.json"
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: "0644"
- name: Write Gamescope configuration
become: true
ansible.builtin.copy:
dest: "{{ gamescope_conf_dir }}/gamescope.conf"
owner: "{{ user_name }}"
mode: "0644"
content: |
OUTPUT_CONNECTOR=HDMI-A-1
FRAMERATE=120
RESOLUTION={{ lookup('env', 'GAME_RESOLUTION') | default('1920x1080') }}
HDR_ENABLED={{ lookup('env', 'HDR_ENABLED') | default('false') }}
DRM_DEVICE=/dev/dri/card1
- name: Create Sunshine slice
become: true
ansible.builtin.copy:
dest: "{{ systemd_user_dir }}/sunshine.slice"
owner: "{{ user_name }}"
mode: "0644"
content: |
[Slice]
CPUWeight=100
AllowedCPUs={{ sunshine_cores }}
- name: Install User scripts
become: true
ansible.builtin.copy:
src: "{{ item }}"
dest: "{{ user_bin_dir }}/{{ item | basename }}"
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: "0755"
loop: "{{ query('fileglob', 'game_station/user/*') }}"
- name: Enable Gamescope session service on boot
become: true
ansible.builtin.systemd:
name: gamescope-session.service
enabled: true
state: started
handlers:
- name: Update grub
ansible.builtin.command: grub2-mkconfig -o /boot/grub2/grub.cfg
become: true
changed_when: false
- name: Reload systemd daemon for system services
become: true
ansible.builtin.systemd:
daemon_reload: true
+3
View File
@@ -110,3 +110,6 @@ dev-01.lab.alexpires.me
[windows_prometheus] [windows_prometheus]
game-01.lab.alexpires.me game-01.lab.alexpires.me
hpz440.lab.alexpires.me hpz440.lab.alexpires.me
[game_station]
steambox.local
+59
View File
@@ -0,0 +1,59 @@
#!/bin/bash
echo "Starting sunshine service..."
if [ -f "$HOME/.config/gamescope/gamescope.conf" ]; then
source "$HOME/.config/gamescope/gamescope.conf"
fi
OUTPUT_CONNECTOR=${OUTPUT_CONNECTOR:-HDMI-A-1}
FRAMERATE=${FRAMERATE:-120}
RESOLUTION=${RESOLUTION:-1920x1080}
HDR_ENABLED=${HDR_ENABLED:-${HDR:-1}}
echo "Building gamescope command..."
# Choose backend based on environment
BACKEND_ARGS=""
DRM_ARGS=""
IN_WAYLAND=0
if [ -n "${WAYLAND_DISPLAY:-}" ] || [ "${XDG_SESSION_TYPE:-}" = "wayland" ]; then
IN_WAYLAND=1
BACKEND_ARGS="--backend wayland"
fi
# HDR only relevant for DRM path generally
HDR_FLAG=""
if [[ "$HDR_ENABLED" == "1" || "$HDR_ENABLED" == "true" || "$HDR_ENABLED" == "yes" ]]; then
HDR_FLAG="--hdr-enabled"
echo " HDR flag added: --hdr-enabled"
else
echo " HDR disabled, no HDR flag added"
fi
WIDTH="${RESOLUTION%x*}"
HEIGHT="${RESOLUTION#*x}"
if [ "$IN_WAYLAND" -eq 0 ]; then
DRM_ARGS="-O \"$OUTPUT_CONNECTOR\" -r \"$FRAMERATE\" $HDR_FLAG"
fi
echo ""
echo "Final Configuration Summary:"
echo " Backend: $([ "$IN_WAYLAND" -eq 1 ] && echo Wayland || echo DRM/KMS)"
echo " Output Connector: ${OUTPUT_CONNECTOR}"
echo " Framerate: ${FRAMERATE}Hz"
echo " Resolution: ${RESOLUTION}"
echo " HDR: $([ -n "$HDR_FLAG" ] && echo "enabled" || echo "disabled")"
echo " MangoHUD: enabled"
echo " Steam Mode: SteamOS3"
echo ""
echo "Launching gamescope session..."
echo "Full command:"
echo " gamescope $BACKEND_ARGS $DRM_ARGS --mangoapp -w $WIDTH -h $HEIGHT -e -- /usr/bin/steamos"
echo ""
echo "========================================="
LOGDIR="${HOME}/.local/logs"
mkdir -p "$LOGDIR"
echo "[$(date --iso-8601=seconds)] Launching (backend: $([ "$IN_WAYLAND" -eq 1 ] && echo wayland || echo drm)): gamescope $BACKEND_ARGS $DRM_ARGS --mangoapp -w $WIDTH -h $HEIGHT -e -- /usr/bin/steamos" >>"$LOGDIR/gamescope-launch.log"
exec bash -lc "gamescope $BACKEND_ARGS $DRM_ARGS --mangoapp -w $WIDTH -h $HEIGHT -e -- /usr/bin/steamos"
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
LOGDIR="${HOME}/.local/logs"
mkdir -p "$LOGDIR"
echo "Starting steamos session..."
systemctl --user start sunshine.service
LOGFILE="${LOGDIR}/steam.log"
steam -steamos3 -pipewire-dmabuf -gamepadui >>"$LOGFILE" 2>&1
+6 -6
View File
@@ -16,10 +16,10 @@ module "disk_exporter" {
standby_mode = false standby_mode = false
} }
module "devolo_exporter" { # module "devolo_exporter" {
for_each = local.devolo_devices # for_each = local.devolo_devices
source = "../../modules/utils/devolo-expporter" # source = "../../modules/utils/devolo-expporter"
devolo_ip = each.value.ip # devolo_ip = each.value.ip
devolo_model = each.value.model # devolo_model = each.value.model
} # }
@@ -11,7 +11,7 @@ scrape_configs:
scrape_interval: 10s scrape_interval: 10s
static_configs: static_configs:
- targets: - targets:
- "auth-exporter.prometheus.svc.cluster.local:9100" - " -exporter.prometheus.svc.cluster.local:9100"
- labels: - labels:
cluster: "dev-01" cluster: "dev-01"
- job_name: disk-exporter - job_name: disk-exporter
@@ -21,9 +21,3 @@ scrape_configs:
- "disk-exporter.prometheus.svc.cluster.local:9100" - "disk-exporter.prometheus.svc.cluster.local:9100"
- labels: - labels:
cluster: "dev-01" cluster: "dev-01"
- job_name: devolo-exporter
scrape_interval: 30s
static_configs:
- targets:
- "devolo-exporter-620.prometheus.svc.cluster.local:9100"
# - "devolo-exporter-326.prometheus.svc.cluster.local:9100"