--- - 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 Unwanted services become: true ansible.builtin.systemd: name: "{{ item }}" enabled: false state: stopped loop: - gdm - sddm # 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: file 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/zsh 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