46 Commits

Author SHA1 Message Date
Josh.5
23e5ec9fa4 Add some sane defaults to Steam config
I can't imagine why we would not want compatibility on for all titles or why we would not want to have a good name and the correct path for the default library.
2025-06-23 06:03:31 +00:00
Josh.5
e39756c3bf If steam is enabled and this is the first boot, create the library config 2025-06-23 05:18:01 +00:00
Josh.5
77fc0221e5 Fix incorrect template for setting firefox as the default browser 2025-06-23 05:13:42 +00:00
Josh.5
67e55c50af Update GH workflow config 2025-06-23 04:30:19 +00:00
Josh.5
c3dc444a8f Fix up Ubnuntu server installation 2025-06-23 04:30:05 +00:00
Josh.5
0ac3a94009 Run NVIDIA driver download attempts in a loop 2025-06-23 02:56:32 +00:00
AlexanderOF
8dd20185a7 Update 60-configure_gpu_driver.sh
Add NVIDIA US Download server as alternative, when Global Download server fails
2025-06-23 14:47:22 +12:00
AlexanderOF
f0accf6102 Change NVIDIA Download Server to US
download.nvidia.com does not provide downloads for drivers and downloading the driver fails. The US Server works perfectly
2025-06-23 14:47:22 +12:00
Pablo Andres Dealbera
14c770bce6 docs: clarify installation of other game launchers 2025-02-06 08:01:43 +13:00
alansari
6db83d2a22 Another stable update for sunshine
not really needed as we arn't using the flatpak version i guess:

build(linux)!: remove legacy input option 
fix(flatpak): fix broken desktop file, icons, and service
fix(web-ui): fix new version notification conditions
chore(l10n): update translations
2025-01-27 17:54:05 +13:00
alansari
6199455ae7 remove libva-vdpau
Just to clean up the actions log, still not recommended to use
2025-01-20 08:52:39 +13:00
alansari
0c4c669ab0 switch back to stable debian sunshine 2025-01-20 08:52:10 +13:00
Josh.5
920bfa7f84 Add 'WEBUI_USER' and 'WEBUI_PASS'
These do not yet do anything, but they will soon enough.
2024-11-27 15:57:20 +13:00
Josh.5
463274d800 Add nodejs to build 2024-11-14 17:02:56 +13:00
alansari
0241c9f845 Update Dockerfile.debian
bump sunshine to latest pre-release
2024-09-05 01:17:55 +12:00
Josh.5
860451da74 Fix NVIDIA driver download for TrueNAS Scale Dragonfish
The previous fix had a few bugs. Because this is executed with `set -e`, the wget will cause the init process to fail if the url does not exist. Also, the github path was looking at an aarch64 download

Closes #156
2024-08-06 23:12:40 +12:00
Josh.5
b0ba3cfc8a Include gamescope with steam installation 2024-08-01 11:11:16 +12:00
Josh.5
77967f2845 Fix primary output detection in sunshine-run
Sometimes (perhaps with some recent update, it is listed as just "connected" not "primary".
2024-08-01 11:10:20 +12:00
Josh.5
ac9c4f29ca Fix default steam big picture launcher 2024-07-14 18:16:11 +12:00
WillKirkmanM
336a6284ec Fix(60-configure_gpu_driver.sh): Add fallback to GitHub for NVIDIA driver downloads
An issue opened https://github.com/Steam-Headless/docker-steam-headless/issues/152, specifically in TrueNas Scale where 4 versions are not available in the repository https://download.nvidia.com/XFree86/Linux-x86_64, (`545.23.08`, `555.42.06`, `545.23.08` and `555.42.06`) However, the saving grace is that these versions are required for GPU acceleration for Flatpaks.

> Thank you. I’m primarily facing issues because flatpak only has a package for .06, so all flatpak apps are no longer GPU accelerated as a result.

From: https://forums.developer.nvidia.com/t/545-23-08-is-not-listed-in-the-nvidia-driver-downloads-page/273181/3

To Solve this, FlatHub has created a NVIDIA Driver repository where these obscure version's `.run` files are available to download.
https://github.com/flathub/org.freedesktop.Platform.GL.nvidia/

The Entire process can be found in my Solution post: https://github.com/Steam-Headless/docker-steam-headless/issues/152#issuecomment-2208788858

This pull request first attempts to download the driver from the NVIDIA repository and then falls back to the Flathub repository while printing an error if it is unable to download the driver.
2024-07-06 20:23:51 +12:00
tem
9cf971f68f Update arch just so it builds 2024-06-20 13:45:38 +12:00
Josh.5
47f6f7a176 Improve documentation for Intel and AMD installations 2024-05-08 17:22:57 +12:00
Josh.5
28c19ed1b2 Update docker compose templates to not rely on NVIDIA runtime
Plenty of setups may have either nvidia container toolkit without the runtime wrapper, or no toolkit at all.
These updated templates allow for all those cases while still providing support for NVIDIA GPUs.
2024-03-15 04:52:32 +13:00
Josh.5
728acd0ba1 Remove env_file and add all env variables to a environment: section 2024-03-15 04:12:55 +13:00
Josh.5
a2caa9f4ec Add missing NVIDIA_DRIVER_VERSION variable to .env template
This is used when nvidia container toolkit is not used
2024-03-14 20:37:53 +13:00
Josh.5
9c20a0f1f5 Add ability to run NVIDIA containers without the NVIDIA container toolkit 2024-03-14 19:23:34 +13:00
Josh.5
f17d31d077 Enable support for external NVIDIA GPUs 2024-03-14 18:47:08 +13:00
Josh.5
e701b8870f Describe how to install the NVIDIA container toolkit on Ubuntu server 2024-03-14 18:38:04 +13:00
alansari
bd73b199d4 Update sunshine again to latest stable 2024-03-05 23:17:46 +13:00
tem
12a498e1eb Make SID repo optional 2024-02-29 13:55:17 +13:00
tem
63cfefa1fc Bump sunshine to stable & include res script from lyzardbyte docs 2024-02-29 13:54:19 +13:00
alansari
c3941d1f0b Quick patch for v550+ drivers 2024-02-29 13:53:37 +13:00
Josh.5
6cc9f56155 Delete out-dated run script
Better to use compose only or properly document a run command for users
2023-10-05 09:34:34 +13:00
Josh.5
a17fe91113 Hide file copy log. No need for this to be verbose 2023-10-02 20:17:29 +13:00
Josh.5
a5f189dbc3 Update to the latest nightly sunshine 2023-10-02 20:15:02 +13:00
Josh.5
8f32302c0f Improvements to the init scripts 2023-10-02 19:43:50 +13:00
Josh.5
ca7521d765 Fix build and install mesa during container startup
This brings the Mesa and Vulkan installation in-line with the NVIDIA driver installation for NVIDIA GPU users.
2023-10-02 19:14:28 +13:00
Josh.5
c165e28f07 Add variable FORCE_X11_DUMMY_CONFIG for forcing the initial use of the dummy xorg config 2023-10-02 11:13:17 +13:00
Josh.5
7f04d8df01 Pull mesa from SID 2023-09-30 13:39:37 +13:00
Josh.5
f4cad0aab0 Update documentation with new deployment configuration 2023-09-30 10:40:32 +13:00
Josh.5
12cc16459a Reduce some of the excessive sleep times for various things 2023-09-29 23:39:26 +13:00
Josh.5
c651034d13 dumb-udev needs ENABLE_EVDEV_INPUTS enabled by default 2023-09-29 23:27:35 +13:00
Josh.5
93718e1855 Update to how we choose if we are running udevd or dumb-udev
This fixes some issues I found with startup.
2023-09-29 21:26:17 +13:00
Josh.5
5a1d20daf5 Install dumb-udev further down to optimise build caches 2023-09-29 20:34:42 +13:00
Josh.5
15512a485f Fix error in Dockerfile syntax 2023-09-29 20:26:17 +13:00
Josh.5
eeca08ce38 Add dumb-udev as a replacemet for 2023-09-29 20:20:21 +13:00
44 changed files with 1387 additions and 975 deletions

View File

@@ -1,144 +1,170 @@
---
name: Build and Deploy CI
on:
workflow_dispatch:
push:
branches: [ 'dev-**', 'pr-**', staging, master ]
tags: [ '**' ]
branches: ['dev-**', 'pr-**', staging, master]
tags: ['**']
pull_request:
branches: [ staging, master ]
branches: [staging, master]
schedule:
# At 02:30 on Saturday
- cron: '30 2 * * 6'
- cron: '30 2 * * 6'
jobs:
build_docker:
name: Build Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
flavour: ["debian", "arch"]
flavour: ['debian', 'arch']
steps:
# Fetch shallow git repository
- name: Checkout
uses: actions/checkout@v2
# ---
- name: Checkout repository
uses: actions/checkout@v4
# Use QEMU to build
- name: Set up QEMU
if: success()
id: qemu
uses: docker/setup-qemu-action@v1
# ---
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 #v3.8.0
# Use docker buildx to build the docker image
- name: Build the Docker image
uses: docker/setup-buildx-action@v1
if: success()
id: buildx
with:
version: latest
# ---
- name: Prepare
if: success()
id: prepare
run: |
FLAVOUR=${{ matrix.flavour }}
echo "FLAVOUR='${FLAVOUR}'"
echo "GITHUB_REF='${GITHUB_REF}'"
echo "GITHUB_REPOSITORY='${GITHUB_REPOSITORY}'"
VERSION_TAG=${GITHUB_REF#refs/*/}
SHA_SHORT="${GITHUB_SHA::7}"
ORG=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
# Generate 'prepare' build arguments to be retrieved later on
- name: Prepare
if: success()
id: prepare
run: |
FLAVOUR=${{ matrix.flavour }}
echo "FLAVOUR='${FLAVOUR}'"
echo "GITHUB_REF='${GITHUB_REF}'"
echo "GITHUB_REPOSITORY='${GITHUB_REPOSITORY}'"
DOCKER_IMAGE=docker.io/josh5/steam-headless
VERSION_TAG=${GITHUB_REF#refs/*/}
DOCKER_TAGS=""
if [[ ${VERSION_TAG%/merge} == 'master' ]]; then
if [[ ${FLAVOUR} == 'debian' ]]; then
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_IMAGE}:latest,"
fi
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_IMAGE}:${FLAVOUR},"
elif [[ ${VERSION_TAG%/merge} == 'staging' ]]; then
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_IMAGE}:${FLAVOUR}-staging,"
elif [[ ${VERSION_TAG%/merge} =~ "dev-"* ]]; then
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_IMAGE}:${FLAVOUR}-${VERSION_TAG%/merge},"
fi
if [[ ${GITHUB_REF} == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
if [[ ${VERSION} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}[-\w]*$ ]]; then
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_IMAGE}:${FLAVOUR}-${VERSION},"
SERVICE_NAME=steam-headless
DOCKER_HUB_IMAGE=docker.io/josh5/${SERVICE_NAME:?}
GHCR_IMAGE=ghcr.io/${ORG:?}/${SERVICE_NAME:?}
DOCKER_TAGS=""
if [[ ${GITHUB_REF} == refs/heads/master ]]; then
if [[ ${FLAVOUR} == 'debian' ]]; then
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_IMAGE}:latest,"
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_HUB_IMAGE}:latest,${GHCR_IMAGE}:latest,${GHCR_IMAGE}:stable,"
fi
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_HUB_IMAGE}:${FLAVOUR},${GHCR_IMAGE}:${FLAVOUR},"
elif [[ ${GITHUB_REF} == refs/heads/staging ]]; then
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_HUB_IMAGE}:${FLAVOUR}-staging,${GHCR_IMAGE}:${FLAVOUR}-staging,"
elif [[ ${GITHUB_REF} == refs/heads/dev-* ]]; then
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_HUB_IMAGE}:${FLAVOUR}-${VERSION_TAG},${GHCR_IMAGE}:${FLAVOUR}-${VERSION_TAG},"
elif [[ ${GITHUB_REF} == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
if [[ ${VERSION} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}[-\w]*$ ]]; then
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_HUB_IMAGE}:${FLAVOUR}-${VERSION},${GHCR_IMAGE}:${FLAVOUR}-${VERSION},"
if [[ ${FLAVOUR} == 'debian' ]]; then
DOCKER_TAGS="${DOCKER_TAGS}${DOCKER_HUB_IMAGE}:latest,${GHCR_IMAGE}:latest,"
fi
fi
elif [[ ${GITHUB_REF} == refs/pull/* ]]; then
PR_NUMBER=$(echo ${GITHUB_REF} | cut -d'/' -f3)
# For PR builds, only tag the GHCR image.
DOCKER_TAGS="${GHCR_IMAGE}:pr-${PR_NUMBER},"
fi
fi
echo "DOCKER_TAGS='${DOCKER_TAGS}'"
echo "DOCKER_TAGS='${DOCKER_TAGS}'"
echo "Build: [$(date +"%F %T")] [${GITHUB_REF_NAME}] [${GITHUB_SHA}] [${FLAVOUR}]" > ./overlay/version.txt
echo "Build: [$(date +"%F %T")] [${GITHUB_REF_NAME}] [${GITHUB_SHA}] [${FLAVOUR}]" > ./overlay/version.txt
DOCKER_PUSH="true"
if [[ ${DOCKER_IMAGE} != 'docker.io/josh5/steam-headless' ]]; then
DOCKER_PUSH="false"
fi
if [[ ${VERSION_TAG%/merge} =~ "pr-"* ]]; then
DOCKER_PUSH="false"
fi
if [[ ${VERSION_TAG%/merge} =~ ^[0-9]+$ ]]; then
DOCKER_PUSH="false"
fi
if [[ "X${DOCKER_TAGS}" == "X" ]]; then
DOCKER_PUSH="false"
fi
echo "DOCKER_PUSH='${DOCKER_PUSH}'"
cat ./overlay/version.txt
DOCKER_PUSH="true"
if [[ ${DOCKER_HUB_IMAGE} != 'docker.io/josh5/steam-headless' ]]; then
DOCKER_PUSH="false"
fi
if [[ ${VERSION_TAG%/merge} =~ "pr-"* ]]; then
DOCKER_PUSH="false"
fi
if [[ ${VERSION_TAG%/merge} =~ ^[0-9]+$ ]]; then
DOCKER_PUSH="false"
fi
if [[ "X${DOCKER_TAGS}" == "X" ]]; then
DOCKER_PUSH="false"
fi
echo "DOCKER_PUSH='${DOCKER_PUSH}'"
cat ./overlay/version.txt
echo "docker_image=${DOCKER_IMAGE}" >> $GITHUB_OUTPUT
echo "docker_tags=$(echo ${DOCKER_TAGS} | sed 's/,$//')" >> $GITHUB_OUTPUT
echo "docker_platforms=linux/amd64" >> $GITHUB_OUTPUT
echo "docker_push=${DOCKER_PUSH}" >> $GITHUB_OUTPUT
echo "docker_hub_image:${DOCKER_HUB_IMAGE:?}"
echo "docker_hub_image=${DOCKER_HUB_IMAGE:?}" >> $GITHUB_OUTPUT
# Cache the build
- name: Cache Docker layers
uses: actions/cache@v2
id: cache
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ matrix.flavour }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-${{ matrix.flavour }}-
# Login to Docker Hub
- name: Login to Docker Hub
if: success() && (startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/tags/'))
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# Run docker build and push
- name: Docker Build and Push
if: success()
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile.${{ matrix.flavour }}
pull: true
platforms: ${{ steps.prepare.outputs.docker_platforms }}
push: ${{ steps.prepare.outputs.docker_push }}
tags: |
${{ steps.prepare.outputs.docker_tags }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache-new
echo "ghcr_image:${GHCR_IMAGE:?}"
echo "ghcr_image=${GHCR_IMAGE:?}" >> $GITHUB_OUTPUT
# Keep only latest cache
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
- name: Move cache
if: always()
run: |
if [[ -e /tmp/.buildx-cache-new ]]; then
echo "Cleaning up old cache..."
rm -rf /tmp/.buildx-cache
mv -v /tmp/.buildx-cache-new /tmp/.buildx-cache
fi
echo "sha_short:${SHA_SHORT:?}"
echo "sha_short=${SHA_SHORT:?}" >> $GITHUB_OUTPUT
echo "service_name:${SERVICE_NAME:?}"
echo "service_name=${SERVICE_NAME:?}" >> $GITHUB_OUTPUT
echo "docker_image:${DOCKER_HUB_IMAGE:?}"
echo "docker_image=${DOCKER_HUB_IMAGE:?}" >> $GITHUB_OUTPUT
echo "docker_tags:$(echo ${DOCKER_TAGS} | sed 's/,$//')"
echo "docker_tags=$(echo ${DOCKER_TAGS} | sed 's/,$//')" >> $GITHUB_OUTPUT
echo "docker_push:${DOCKER_PUSH:?}"
echo "docker_push=${DOCKER_PUSH:?}" >> $GITHUB_OUTPUT
echo "docker_build_date:${BUILD_DATE:?}"
echo "docker_build_date=${BUILD_DATE:?}" >> $GITHUB_OUTPUT
echo "docker_platforms=linux/amd64" >> $GITHUB_OUTPUT
# ---
- name: Log into GHCR registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# ---
- name: Log into Docker Hub registry
if: success() && (startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/tags/'))
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 #v3.3.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# ---
- name: Docker meta
if: success()
id: meta
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 #v5.6.1
with:
images: |
${{ steps.prepare.outputs.docker_image }}
labels: |
maintainer=Josh.5
source.version=${{ steps.prepare.outputs.sha_short }}
source.project=Steam Headless
source.service=${{ steps.prepare.outputs.service_name }}
org.opencontainers.image.title=${{ steps.prepare.outputs.service_name }}
org.opencontainers.image.created=${{ steps.prepare.outputs.docker_build_date }}
# ---
- name: Build Image
if: success()
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc #v6.11.0
with:
context: .
file: Dockerfile.${{ matrix.flavour }}
platforms: ${{ steps.prepare.outputs.docker_platforms }}
pull: 'true'
push: ${{ steps.prepare.outputs.docker_push }}
tags: |
${{ steps.prepare.outputs.docker_tags }}
labels: |
${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ steps.prepare.outputs.service_name }}-${{ matrix.flavour }}-main
cache-to: type=gha,scope=${{ steps.prepare.outputs.service_name }}-${{ matrix.flavour }}-main,mode=max

View File

@@ -35,6 +35,7 @@ RUN \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
@@ -49,6 +50,8 @@ RUN \
docbook-xml \
docbook-xsl \
fakeroot \
p7zip \
patch \
git \
jq \
less \
@@ -67,6 +70,7 @@ RUN \
unzip \
vim \
wget \
xmlstarlet \
xz \
&& \
echo "**** Install python ****" \
@@ -79,6 +83,7 @@ RUN \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
@@ -111,9 +116,10 @@ RUN \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /home/default/.cache/yay \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -rf \
/tmp/yay* \
&& rm -fr /var/cache/pacman/pkg/* \
&& rm -rf /tmp/yay* \
&& \
echo
@@ -126,51 +132,37 @@ RUN \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
# XFS requirements
# Install mscorefonts
RUN \
echo "**** Install XFS requirements ****" \
&& pacman -Syu --noconfirm --needed \
xfsdump \
xfsprogs \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& \
echo
# Install mesa requirements
RUN \
echo "**** Install mesa and vulkan requirements ****" \
&& pacman -Syu --noconfirm --needed \
glu \
libva-mesa-driver \
mesa-utils \
mesa-vdpau \
pciutils \
vulkan-mesa-layers \
vdpauinfo \
echo "**** Install ms fonts ****" \
&& su - default -c "yay -Syu --noconfirm --needed ttf-msfonts" \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /home/default/.cache/yay \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& rm -rf /tmp/yay* \
&& \
echo
# Install X Server requirements
ENV \
XORG_SOCKET_DIR="/tmp/.X11-unix" \
XDG_RUNTIME_DIR="/tmp/.X11-unix/run"
XDG_RUNTIME_DIR="/tmp/.X11-unix/run" \
XDG_SESSION_TYPE="x11" \
FORCE_X11_DUMMY_CONFIG="false"
RUN \
echo "**** Install X Server requirements ****" \
&& pacman -Syu --noconfirm --needed \
avahi \
dbus \
lib32-fontconfig \
ttf-liberation \
fuse2 \
x11vnc \
xorg \
xorg-apps \
@@ -190,11 +182,14 @@ RUN \
xorg-xrandr \
xorg-xsetroot \
xorg-xwininfo \
xf86-input-evdev \
xterm \
gamescope \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
@@ -213,6 +208,7 @@ RUN \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
@@ -226,110 +222,75 @@ RUN \
xfce4-goodies \
xfce4-terminal \
ttf-liberation \
# Delete these as they are not needed at all
&& rm -f \
/usr/share/applications/software-properties-drivers.desktop \
/usr/share/applications/xfce4-about.desktop \
/usr/share/applications/xfce4-session-logout.desktop \
# Hide these apps. They can be displayed if a user really wants them.
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/xfce4-accessibility-settings.desktop \
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/xfce4-color-settings.desktop \
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/xfce4-mail-reader.desktop \
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/vim.desktop \
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/thunar-settings.desktop \
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/thunar.desktop \
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/pavucontrol.desktop \
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/x11vnc.desktop \
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/xterm.desktop \
&& sed -i '/[Desktop Entry]/a\NoDisplay=true' /usr/share/applications/uxterm.desktop \
# Force these apps to be "System" Apps rather than "Categories=System;Utility;Core;GTK;Filesystem;"
&& sed -i 's/^Categories=.*$/Categories=System;/' /usr/share/applications/xfce4-appfinder.desktop \
&& sed -i 's/^Categories=.*$/Categories=System;/' /usr/share/applications/thunar-bulk-rename.desktop \
&& sed -i 's/^Categories=.*$/Categories=System;/' /usr/share/applications/org.gnome.gedit.desktop \
xdg-user-dirs \
xdg-utils \
imagemagick \
&& \
echo "**** Install WoL Manager requirements ****" \
&& pacman -Syu --noconfirm --needed \
tcpdump \
xprintidle \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
# TODO: Add support for flatpaks
# Note: Debian Bullseye had bubblewrap v0.4.1 which worked fine in the Nvidia docker runtime
# At the moment this is only working beacuse /proc is being mounted again in 10-setup_user.sh
# Need to find a better solution for this...
ARG BUBBLEWRAP_VERSION=0.8.0
# Add support for flatpaks
ENV \
XDG_DATA_DIRS="/home/default/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share/:/usr/share/"
RUN \
echo "**** Install flatpak support ****" \
&& pacman -Syu --noconfirm --needed \
flatpak \
gnome-software \
xdg-desktop-portal-gtk \
gnome-software \
&& \
#echo "**** Build and install custom bubblewrap ****" \
# && cd /tmp \
# && wget -O /tmp/bubblewrap-${BUBBLEWRAP_VERSION:?}.tar.xz https://github.com/containers/bubblewrap/releases/download/v${BUBBLEWRAP_VERSION:?}/bubblewrap-${BUBBLEWRAP_VERSION:?}.tar.xz \
# && tar -xvf /tmp/bubblewrap-${BUBBLEWRAP_VERSION:?}.tar.xz \
# && cd /tmp/bubblewrap-${BUBBLEWRAP_VERSION:?} \
# && sed -i 's|die ("Unexpected capabilities but not setuid, old file caps config?");|printf ("Unexpected capabilities but not setuid, old file caps config?");|' ./bubblewrap.c \
# && ./autogen.sh \
# && make clean \
# && make \
# && make install
#&& \
echo "**** Configure flatpak ****" \
&& chmod u-s /usr/bin/bwrap \
&& flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo \
&& su - default -c "flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo" \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
# Install noVNC
# TODO: Add nginx or remove the whole proxy setup and just connect directly for audio (I think that is the better option)
ARG NOVNC_VERSION=1.2.0
# TODO: Deprecate neko
# Install Neko server
COPY --from=m1k1o/neko:base /usr/bin/neko /usr/bin/neko
COPY --from=m1k1o/neko:base /var/www /var/www
# Install Web Frontend
ARG FRONTEND_VERSION=a8eb92f
RUN \
echo "**** Fetch noVNC ****" \
&& cd /tmp \
&& wget -O /tmp/novnc.tar.gz https://github.com/novnc/noVNC/archive/v${NOVNC_VERSION}.tar.gz \
&& \
echo "**** Extract noVNC ****" \
&& cd /tmp \
&& tar -xvf /tmp/novnc.tar.gz \
&& \
echo "**** Configure noVNC ****" \
&& cd /tmp/noVNC-${NOVNC_VERSION} \
&& sed -i 's/credentials: { password: password } });/credentials: { password: password },\n wsProtocols: ["'"binary"'"] });/g' app/ui.js \
echo "**** Fetch Web Frontend ****" \
&& mkdir -p /opt \
&& rm -rf /opt/noVNC \
&& cd /opt \
&& mv -f /tmp/noVNC-${NOVNC_VERSION} /opt/noVNC \
&& cd /opt/noVNC \
&& ln -s vnc.html index.html \
&& chmod -R 755 /opt/noVNC \
&& rm -rf /opt/frontend \
&& git clone https://github.com/Steam-Headless/frontend.git --branch master /opt/frontend \
&& cd /opt/frontend \
&& git checkout ${FRONTEND_VERSION} 2> /dev/null \
&& git submodule init \
&& git submodule update --depth 1 --recursive \
&& rm -rf /opt/frontend/.git \
&& \
echo "**** Modify noVNC title ****" \
&& sed -i '/ document.title =/c\ document.title = "Steam Headless - noVNC";' \
/opt/noVNC/app/ui.js \
&& \
echo "**** Install nginx support ****" \
&& pacman -Syu --noconfirm --needed \
nginx \
echo "**** Configure Web Frontend ****" \
&& echo '<!DOCTYPE html>' > /opt/frontend/index.html \
&& echo '<html><head><meta http-equiv="refresh" content="0;url=./web/"></head><body><p>If you are not redirected, <a href="./web/">click here</a>.</p></body></html>' >> /opt/frontend/index.html \
&& chmod -R 755 /opt/frontend \
&& convert /opt/frontend/web/images/icons/novnc-ios-180.png -resize "128x128" /tmp/steam-headless.png \
&& xdg-icon-resource install --novendor --size 128 /tmp/steam-headless.png \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -rf \
/tmp/noVNC* \
/tmp/novnc.tar.gz \
&& \
echo
&& rm -f /tmp/steam-headless.png
# Install Websockify
ARG WEBSOCKETIFY_VERSION=0.10.0
ARG WEBSOCKETIFY_VERSION=0.11.0
RUN \
echo "**** Fetch Websockify ****" \
&& cd /tmp \
@@ -345,6 +306,7 @@ RUN \
&& \
echo "**** Install Websockify to noVNC path ****" \
&& cd /tmp \
&& mkdir -p /opt/noVNC/utils \
&& mv -v /tmp/websockify-${WEBSOCKETIFY_VERSION} /opt/noVNC/utils/websockify \
&& \
echo "**** Section cleanup ****" \
@@ -365,51 +327,147 @@ RUN \
gst-plugins-good \
gst-plugins-ugly \
&& \
echo "**** Fetch ucspi-tcp ****" \
&& mkdir -p /tmp/ucspi-tcp-0.88 \
&& cd /tmp \
#&& wget -O /tmp/ucspi-tcp.tar.gz https://github.com/trafficgate/ucspi-tcp/archive/refs/heads/master.tar.gz \
&& wget -O /tmp/ucspi-tcp.tar.gz http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz \
&& cd /tmp/ucspi-tcp-0.88 \
&& tar -xvf /tmp/ucspi-tcp.tar.gz --strip-components=1 \
#echo "**** Fetch ucspi-tcp ****" \
# && mkdir -p /tmp/ucspi-tcp-0.88 \
# && cd /tmp \
# #&& wget -O /tmp/ucspi-tcp.tar.gz https://github.com/trafficgate/ucspi-tcp/archive/refs/heads/master.tar.gz \
# && wget -O /tmp/ucspi-tcp.tar.gz http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz \
# && cd /tmp/ucspi-tcp-0.88 \
# && tar -xvf /tmp/ucspi-tcp.tar.gz --strip-components=1 \
#&& \
#echo "**** Build and install ucspi-tcp ****" \
# && wget -O /tmp/ucspi-tcp-0.88/ucspi-tcp-0.88.errno.patch https://git.alpinelinux.org/aports/plain/testing/ucspi-tcp/ucspi-tcp-0.88.errno.patch \
# && wget -O /tmp/ucspi-tcp-0.88/ucspi-tcp-0.88.a_record.patch https://git.alpinelinux.org/aports/plain/testing/ucspi-tcp/ucspi-tcp-0.88.a_record.patch \
# && patch -p1 --input=ucspi-tcp-0.88.errno.patch \
# && patch -p1 --input=ucspi-tcp-0.88.a_record.patch \
# && sed -i 's|^/usr/local|/usr|' /tmp/ucspi-tcp-0.88/conf-home \
# && make \
# && for f in tcpserver tcprules tcprulescheck argv0 recordio tcpclient *\@ tcpcat mconnect mconnect-io addcr delcr fixcrio rblsmtpd; do \
# cp $f /usr/bin/$f; \
# done \
#&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo "**** Build and install ucspi-tcp ****" \
&& wget -O /tmp/ucspi-tcp-0.88/ucspi-tcp-0.88.errno.patch https://git.alpinelinux.org/aports/plain/testing/ucspi-tcp/ucspi-tcp-0.88.errno.patch \
&& wget -O /tmp/ucspi-tcp-0.88/ucspi-tcp-0.88.a_record.patch https://git.alpinelinux.org/aports/plain/testing/ucspi-tcp/ucspi-tcp-0.88.a_record.patch \
&& patch -p1 --input=ucspi-tcp-0.88.errno.patch \
&& patch -p1 --input=ucspi-tcp-0.88.a_record.patch \
&& sed -i 's|^/usr/local|/usr|' /tmp/ucspi-tcp-0.88/conf-home \
&& make \
&& for f in tcpserver tcprules tcprulescheck argv0 recordio tcpclient *\@ tcpcat mconnect mconnect-io addcr delcr fixcrio rblsmtpd; do \
cp $f /usr/bin/$f; \
done \
echo
# Setup video streaming deps
RUN \
echo "**** Install video streaming deps ****" \
&& pacman -Syu --noconfirm --needed \
libva \
libva-mesa-driver \
libva-intel-driver \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -rf \
/tmp/ucspi-tcp-* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
# Install tools for monitoring hardware
RUN \
echo "**** Install audio streaming deps ****" \
&& pacman -Syu --noconfirm --needed \
#cpu-x \
htop \
libva-utils \
vdpauinfo \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
# Install Sunshine
RUN \
echo "**** Install stable sunshine ****" \
&& su - default -c "yay -Syu --noconfirm --needed miniupnpc sunshine-bin" \
&& setcap cap_sys_admin+p $(readlink -f $(which sunshine)) \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /home/default/.cache/yay \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& rm -rf /tmp/yay* \
&& \
echo
# Install Firefox
RUN \
echo "**** Install Firefox ****" \
&& pacman -Syu --noconfirm --needed \
firefox \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
# Install Steam
RUN \
echo "**** Install X Server requirements ****" \
echo "**** Install Steam ****" \
&& pacman -Syu --noconfirm --needed \
steam \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& \
echo
# Various other tools
ARG DUMB_INIT_VERSION=1.2.5
ARG DUMB_UDEV_VERSION=64d1427
RUN \
echo "**** Install dumb-init ****" \
&& wget --no-check-certificate --no-cookies --quiet \
-O /usr/bin/dumb-init \
https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_x86_64 \
&& chmod +x /usr/bin/dumb-init \
&& \
echo "**** Install dumb-udev ****" \
&& python3 -m pip install \
--break-system-packages \
--pre \
--upgrade \
--no-cache-dir \
git+https://github.com/Steam-Headless/dumb-udev.git@${DUMB_UDEV_VERSION} \
&& \
echo
# Install Protonup replacement
RUN \
echo "**** Install PorotonUP ****" \
&& su - default -c "yay -Sy --noconfirm --needed --overwrite \"/usr/bin/normalizer\" protonup-qt" \
&& \
echo "**** Section cleanup ****" \
&& pacman -Scc --noconfirm \
&& rm -fr /home/default/.cache/yay \
&& rm -fr /var/lib/pacman/sync/* \
&& rm -fr /var/cache/pacman/pkg/* \
&& rm -rf /tmp/yay* \
&& \
echo
# Add FS overlay
COPY overlay /
# Tweaks as flatpak issue isn't sorted
RUN \
echo "**** Setup Steam Supervisor ****" \
&& sed -i 's#/usr/games/steam#/usr/bin/steam#g' /etc/supervisor.d/steam.ini \
echo "**** Tweaks for Arch ****" \
&& sed -i d /usr/bin/install_firefox.sh \
&& sed -i d /usr/bin/install_protonup.sh \
&& sed -i d /templates/home_directory_template/.local/share/xfce4/helpers/custom-WebBrowser.desktop \
&& \
echo
@@ -426,6 +484,7 @@ ENV \
NVIDIA_VISIBLE_DEVICES="all"
# Set container configuration environment variables
# APPIMAGE_EXTRACT_AND_RUN="0"
ENV \
MODE="primary" \
WEB_UI_MODE="vnc" \
@@ -434,8 +493,9 @@ ENV \
NEKO_PASSWORD_ADMIN=admin \
ENABLE_STEAM="true" \
STEAM_ARGS="-silent" \
ENABLE_SUNSHINE="false" \
ENABLE_EVDEV_INPUTS="false"
ENABLE_SUNSHINE="true" \
ENABLE_EVDEV_INPUTS="true" \
ENABLE_WOL_POWER_MANAGER="false"
# Configure required ports
ENV \

View File

@@ -144,55 +144,13 @@ RUN \
&& \
echo
# Install mesa and vulkan requirements
# TODO: Strip this section back to only what is required for all GPU types.
# Anything only required for Intel/AMD/NVIDIA should go in the container init.
RUN \
echo "**** Update apt database ****" \
&& dpkg --add-architecture i386 \
&& apt-get update \
&& \
echo "**** Install mesa requirements ****" \
&& apt-get install -y --no-install-recommends \
libgl1-mesa-dri \
libgl1-mesa-glx \
libgles2-mesa \
libglu1-mesa \
mesa-utils \
mesa-utils-extra \
&& \
echo "**** Install vulkan requirements ****" \
&& apt-get install -y --no-install-recommends \
libvulkan1 \
libvulkan1:i386 \
mesa-vulkan-drivers \
mesa-vulkan-drivers:i386 \
vulkan-tools \
&& \
echo "**** Install desktop requirements ****" \
&& apt-get install -y --no-install-recommends \
libdbus-1-3 \
libegl1 \
libgtk-3-0 \
libgtk2.0-0 \
libsdl2-2.0-0 \
&& \
echo "**** Section cleanup ****" \
&& apt-get clean autoclean -y \
&& apt-get autoremove -y \
&& rm -rf \
/var/lib/apt/lists/* \
/var/tmp/* \
/tmp/* \
&& \
echo
# Install X Server requirements
# TODO: Refine this list of packages to only what is required.
ENV \
XORG_SOCKET_DIR="/tmp/.X11-unix" \
XDG_RUNTIME_DIR="/tmp/.X11-unix/run" \
XDG_SESSION_TYPE="x11"
XDG_SESSION_TYPE="x11" \
FORCE_X11_DUMMY_CONFIG="false"
RUN \
echo "**** Update apt database ****" \
&& apt-get update \
@@ -244,7 +202,7 @@ RUN \
echo "**** Update apt database ****" \
&& apt-get update \
&& \
echo "**** Install X Server requirements ****" \
echo "**** Install pulseaudio requirements ****" \
&& apt-get install -y --no-install-recommends \
pulseaudio \
alsa-utils \
@@ -267,6 +225,14 @@ RUN \
echo "**** Update apt database ****" \
&& apt-get update \
&& \
echo "**** Install desktop requirements ****" \
&& apt-get install -y --no-install-recommends \
libdbus-1-3 \
libegl1 \
libgtk-3-0 \
libgtk2.0-0 \
libsdl2-2.0-0 \
&& \
echo "**** Install desktop environment ****" \
&& apt-get install -y \
fonts-vlgothic \
@@ -341,14 +307,21 @@ RUN \
&& \
echo
# TODO: Deprecate neko
# Install Neko server
COPY --from=m1k1o/neko:base /usr/bin/neko /usr/bin/neko
COPY --from=m1k1o/neko:base /var/www /var/www
# Install Web Frontend
ARG NODE_VERSION="v20"
ARG FRONTEND_VERSION=a8eb92f
RUN \
echo "**** Install Node ${NODE_VERSION} ****" \
&& mkdir -p /tmp/nodejs \
&& rm -rf /opt/nodejs \
&& wget -qO /tmp/nodejs/nodejs.tar.xz \
"https://nodejs.org/dist/latest-${NODE_VERSION:?}.x/node-$(wget -qO- https://nodejs.org/dist/latest-${NODE_VERSION:?}.x/ | sed -nE 's|.*>node-(.*)-linux-x64\.tar.xz</a>.*|\1|p')-linux-x64.tar.xz" \
&& tar -xJf /tmp/nodejs/nodejs.tar.xz -C /tmp/nodejs --strip-components=1 \
&& mv /tmp/nodejs /opt/nodejs \
&& ln -sf /opt/nodejs/bin/node /usr/local/bin/node \
&& ln -sf /opt/nodejs/bin/npm /usr/local/bin/npm \
&& ln -sf /opt/nodejs/bin/npx /usr/local/bin/npx \
&& \
echo "**** Fetch Web Frontend ****" \
&& mkdir -p /opt \
&& cd /opt \
@@ -486,8 +459,30 @@ RUN \
&& \
echo
# Install Steam
RUN \
echo "**** Update apt database ****" \
&& dpkg --add-architecture i386 \
&& apt-get update \
&& \
echo "**** Install Steam ****" \
&& apt-get install -y --no-install-recommends \
steam-installer \
gamescope \
&& ln -sf /usr/games/steam /usr/bin/steam \
&& \
echo "**** Section cleanup ****" \
&& apt-get clean autoclean -y \
&& apt-get autoremove -y \
&& rm -rf \
/var/lib/apt/lists/* \
/var/tmp/* \
/tmp/* \
&& \
echo
# Install Sunshine
COPY --from=lizardbyte/sunshine:b00d7af-debian-bookworm /sunshine.deb /usr/src/sunshine.deb
COPY --from=lizardbyte/sunshine:v2025.122.141614-debian-bookworm /sunshine.deb /usr/src/sunshine.deb
RUN \
echo "**** Update apt database ****" \
&& apt-get update \
@@ -510,28 +505,14 @@ RUN \
&& \
echo
# Install Steam
RUN \
echo "**** Update apt database ****" \
&& apt-get update \
&& \
echo "**** Install Steam ****" \
&& apt-get install -y --no-install-recommends \
steam \
&& ln -sf /usr/games/steam /usr/bin/steam \
&& \
echo "**** Section cleanup ****" \
&& apt-get clean autoclean -y \
&& apt-get autoremove -y \
&& rm -rf \
/var/lib/apt/lists/* \
/var/tmp/* \
/tmp/* \
&& \
echo
# TODO: Deprecate neko
# Install Neko server
COPY --from=m1k1o/neko:base /usr/bin/neko /usr/bin/neko
COPY --from=m1k1o/neko:base /var/www /var/www
# Various other tools
ARG DUMB_INIT_VERSION=1.2.5
ARG DUMB_UDEV_VERSION=64d1427
RUN \
echo "**** Install dumb-init ****" \
&& wget --no-check-certificate --no-cookies --quiet \
@@ -539,6 +520,14 @@ RUN \
https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_x86_64 \
&& chmod +x /usr/bin/dumb-init \
&& \
echo "**** Install dumb-udev ****" \
&& python3 -m pip install \
--break-system-packages \
--pre \
--upgrade \
--no-cache-dir \
git+https://github.com/Steam-Headless/dumb-udev.git@${DUMB_UDEV_VERSION} \
&& \
echo
# Add FS overlay
@@ -557,6 +546,7 @@ ENV \
NVIDIA_VISIBLE_DEVICES="all"
# Set container configuration environment variables
# TODO: Set the default WEBUI_USER & WEBUI_PASS after release of SHUI
ENV \
MODE="primary" \
WEB_UI_MODE="vnc" \
@@ -565,9 +555,12 @@ ENV \
NEKO_PASSWORD_ADMIN=admin \
ENABLE_STEAM="true" \
STEAM_ARGS="-silent" \
WEBUI_USER="" \
WEBUI_PASS="" \
ENABLE_SUNSHINE="true" \
ENABLE_EVDEV_INPUTS="false" \
ENABLE_WOL_POWER_MANAGER="false"
ENABLE_EVDEV_INPUTS="true" \
ENABLE_WOL_POWER_MANAGER="false" \
ENABLE_SID="false"
# Configure required ports
ENV \

View File

@@ -11,7 +11,7 @@ Easily deploy a Steam Docker instance in seconds.
## Features:
- Steam Client configured for running on Linux with Proton
- Moonlight compatible server for easy remote desktop streaming
- One click installation of EmeDeck, Heroic and Lutris
- Easy installation of EmeDeck, Heroic and Lutris via Flatpak
- Full video/audio noVNC web access to a Xfce4 Desktop
- NVIDIA, AMD and Intel GPU support
- Full controller support
@@ -26,6 +26,8 @@ Easily deploy a Steam Docker instance in seconds.
If you wish to install additional applications, you can generate a script inside the `~/init.d` directory ending with ".sh".
This will be executed on the container startup.
Also, you can install applications using the WebUI under **Applications > System > Software**. There you can install other game launchers like Lutris, Heroic or EmuDeck.
### STORAGE PATHS:
Everything that you wish to save in this container should be stored in the home directory or a docker container mount that you have specified.
All files that are store outside your home directory are not persistent and will be wiped if there is an update of the container or you change something in the template.

View File

@@ -1,136 +0,0 @@
#!/usr/bin/env bash
###
# File: run.sh
# Project: docker-steamos
# File Created: Saturday, 8th January 2022 2:34:23 pm
# Author: Josh.5 (jsunnex@gmail.com)
# -----
# Last Modified: Tuesday, 8th February 2022 8:00:29 am
# Modified By: Console and webGui login account (jsunnex@gmail.com)
###
script_path=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd );
project_base_path=$(realpath ${script_path}/..);
# Parse params
additional_docker_params=""
container_name="steam"
tag="develop"
for ARG in ${@}; do
case ${ARG} in
*primary)
primary="true";
;;
*nvidia)
nvidia="true";
;;
*fb)
framebuffer="true";
;;
*br0)
network="br0";
;;
stop)
script_mode="stop"
;;
tail)
script_mode="tail"
;;
user)
script_mode="user"
;;
root)
script_mode="root"
;;
*arch)
tag="arch";
;;
*debian)
tag="debian";
;;
*)
;;
esac
done
if [[ "${primary}" == "true" ]]; then
container_name="${container_name}-p"
additional_docker_params="${additional_docker_params} -e MODE=primary"
hostx="false"
elif [[ "${framebuffer}" == "true" ]]; then
# TODO: Enable xvfb
container_name="${container_name}-fb"
additional_docker_params="${additional_docker_params} -e MODE=framebuffer"
else
container_name="${container_name}-s"
additional_docker_params="${additional_docker_params} -e MODE=secondary"
fi
if [[ "${nvidia}" == "true" ]]; then
container_name="${container_name}-hw"
additional_docker_params="${additional_docker_params} --runtime=nvidia"
fi
if [[ "${network}" == "br0" ]]; then
additional_docker_params="${additional_docker_params} --network=br0 --ip='192.168.1.208'"
else
additional_docker_params="${additional_docker_params} --network=host"
fi
if [[ -e /dev/dri ]]; then
additional_docker_params="${additional_docker_params} --device=/dev/dri"
fi
# If a mode was given, run that instead
if [[ "${script_mode}" == "stop" ]]; then
docker stop ${container_name}
docker rm ${container_name}
exit $?
elif [[ "${script_mode}" == "tail" ]]; then
docker logs -f ${container_name}
exit $?
elif [[ "${script_mode}" == "user" ]]; then
docker exec -ti --user default ${container_name} bash
exit $?
elif [[ "${script_mode}" == "root" ]]; then
docker exec -ti --user 0 ${container_name} bash
exit $?
fi
# Stop previous instance
docker stop ${container_name}
docker rm ${container_name}
sleep 1
# Run
cmd="docker run -d --name='${container_name}' \
--privileged=true \
-e PUID='99' \
-e PGID='100' \
-e UMASK='000' \
-e USER_PASSWORD='password' \
-e USER='default' \
-e USER_HOME='/home/default' \
-e TZ='Pacific/Auckland' \
-e USER_LOCALES='en_US.UTF-8 UTF-8' \
-e DISPLAY_CDEPTH='24' \
-e DISPLAY_REFRESH='60' \
-e DISPLAY_SIZEH='720' \
-e DISPLAY_SIZEW='1280' \
-e DISPLAY_VIDEO_PORT='DFP' \
-e DISPLAY=':55' \
-e NVIDIA_DRIVER_CAPABILITIES='all' \
-e NVIDIA_VISIBLE_DEVICES='all' \
-e ENABLE_VNC_AUDIO='false' \
-v '${project_base_path}/config/home/default-${container_name}':'/home/default':'rw' \
-v '/tmp/.X11-unix/':'/tmp/.X11-unix/':'rw' \
-v '/dev/input':'/dev/input':'ro' \
--hostname='${container_name}' \
--add-host=${container_name}:127.0.0.1 \
--shm-size=2G \
${additional_docker_params} \
josh5/steam-headless:${tag}"
echo ${cmd}
bash -c "${cmd}"
docker logs -f ${container_name}

View File

@@ -5,18 +5,20 @@
# |____/ \__, |___/\__\___|_| |_| |_|
# |___/
#
NAME='SteamHeadless'
TZ='Pacific/Auckland'
USER_LOCALES='en_US.UTF-8 UTF-8'
DISPLAY=':55'
SHM_SIZE='2G'
## DOCKER_RUNTIME:
## Options: ['runc', 'nvidia']
## Description: The name of an implementation of OCI Runtime Spec
## Available runtimes are listed when you run `docker info`.
## Your system may have other options available. As a simple rule, if you are
## using an NVIDIA GPU, set this to 'nvidia' for anything else, set this to 'runc'.
DOCKER_RUNTIME='runc'
NAME=SteamHeadless
TZ=Pacific/Auckland
USER_LOCALES=en_US.UTF-8 UTF-8
DISPLAY=:55
SHM_SIZE=2G
## HOME_DIR:
## Description: The path to the home directory on your host. Mounts to `/home/default` inside the container.
HOME_DIR=/opt/container-data/steam-headless/home
## SHARED_SOCKETS_DIR:
## Description: Shared sockets such as pulse audio and X11.
SHARED_SOCKETS_DIR=/opt/container-data/steam-headless/sockets
## GAMES_DIR:
## Description: The path to the games directory on your host. Mounts to `/mnt/games` inside the container.
GAMES_DIR=/mnt/games
# ____ __ _ _ _ _
# | _ \ ___ / _| __ _ _ _| | |_ | | | |___ ___ _ __
@@ -25,10 +27,10 @@ DOCKER_RUNTIME='runc'
# |____/ \___|_| \__,_|\__,_|_|\__| \___/|___/\___|_|
#
#
PUID='1000'
PGID='1000'
UMASK='000'
USER_PASSWORD='password'
PUID=1000
PGID=1000
UMASK=000
USER_PASSWORD=password
# __ __ _
# | \/ | ___ __| | ___
@@ -42,7 +44,7 @@ USER_PASSWORD='password'
## Description: Steam Headless containers can run in a secondary mode that will only start
## a Steam process that will then use the X server of either the host or another
## Steam Headless container running in 'primary' mode.
MODE='primary'
MODE=primary
# ____ _
# / ___| ___ _ ____ _(_) ___ ___ ___
@@ -56,41 +58,41 @@ MODE='primary'
## Options: ['vnc', 'neko', 'none']
## Description: Configures the WebUI to use for accessing the virtual desktop.
## Supported Modes: ['primary']
WEB_UI_MODE='vnc'
WEB_UI_MODE=vnc
## ENABLE_VNC_AUDIO:
## Options: ['true', 'false']
## Description: Enables audio over for the VNC Web UI if 'WEB_UI_MODE' is set to 'vnc'.
ENABLE_VNC_AUDIO='true'
ENABLE_VNC_AUDIO=true
## PORT_NOVNC_WEB:
## Description: Configure the port to use for the WebUI.
PORT_NOVNC_WEB='8083'
PORT_NOVNC_WEB=8083
## NEKO_NAT1TO1:
## Description: Configure nat1to1 for the neko WebUI if it is enabled by setting 'WEB_UI_MODE' to 'neko'.
## This will need to be the IP address of the host.
NEKO_NAT1TO1=''
NEKO_NAT1TO1=
# Steam
## ENABLE_STEAM:
## Options: ['true', 'false']
## Description: Enable Steam to run on start. This will also cause steam to restart automatically if closed.
## Supported Modes: ['primary', 'secondary']
ENABLE_STEAM='true'
ENABLE_STEAM=true
## STEAM_ARGS:
## Description: Additional steam execution arguments.
#STEAM_ARGS='-silent -bigpicture'
STEAM_ARGS=-silent
# Sunshine
## ENABLE_SUNSHINE:
## Options: ['true', 'false']
## Description: Enable Sunshine streaming service.
## Supported Modes: ['primary']
ENABLE_SUNSHINE='false'
ENABLE_SUNSHINE=false
## SUNSHINE_USER:
## Description: Set the Sunshine service username.
#SUNSHINE_USER='admin'
SUNSHINE_USER=admin
## SUNSHINE_PASS:
## Description: Set the Sunshine service password.
#SUNSHINE_PASS='admin'
SUNSHINE_PASS=admin
# Xorg
## ENABLE_EVDEV_INPUTS:
@@ -98,16 +100,27 @@ ENABLE_SUNSHINE='false'
## Description: Enable Keyboard and Mouse Passthrough. This will configure the Xorg server to catch all
## evdev events for Keyboard, Mouse, etc.
## Supported Modes: ['primary']
ENABLE_EVDEV_INPUTS='true'
ENABLE_EVDEV_INPUTS=true
## FORCE_X11_DUMMY_CONFIG:
## Available Options: ['true', 'false']
## Description: Forces the installation of xorg.dummy.conf. This should be used when your output device does not have a monitor connected.
## Supported Modes: ['primary']
FORCE_X11_DUMMY_CONFIG=false
# Nvidia specific config (not required for non Nvidia GPUs)
## NVIDIA_DRIVER_CAPABILITIES:
## Options: ['all', 'compute', 'compat32', 'graphics', 'utility', 'video', 'display']
## Description: Controls which driver libraries/binaries will be mounted inside the container.
## Supported Modes: ['primary', 'secondary']
NVIDIA_DRIVER_CAPABILITIES='all'
NVIDIA_DRIVER_CAPABILITIES=all
## NVIDIA_DRIVER_CAPABILITIES:
## Available Options: ['all', 'none', '<GPU UUID>']
## Description: Controls which GPUs will be made accessible inside the container.
## Supported Modes: ['primary', 'secondary']
NVIDIA_VISIBLE_DEVICES='all'
NVIDIA_VISIBLE_DEVICES=all
## NVIDIA_DRIVER_VERSION:
## Description: Specify a driver version to force installation.
## Not meant to be used if nvidia container toolkit is installed.
## Detect current host driver installed with `nvidia-smi 2> /dev/null | grep NVIDIA-SMI | cut -d ' ' -f3`
## Supported Modes: ['primary', 'secondary']
NVIDIA_DRIVER_VERSION=

View File

@@ -0,0 +1,76 @@
---
version: "3.8"
services:
steam-headless:
image: josh5/steam-headless:latest
restart: unless-stopped
## NOTE: This config uses privileged to access to host to be able to access the required devices
privileged: true
shm_size: ${SHM_SIZE}
ipc: host # Could also be set to 'shareable'
ulimits:
nofile:
soft: 1024
hard: 524288
# NETWORK:
## NOTE: With this configuration, if we do not use the host network, then physical device input
## is not possible and your USB connected controllers will not work in steam games.
network_mode: host
hostname: ${NAME}
extra_hosts:
- "${NAME}:127.0.0.1"
# ENVIRONMENT:
## Read all config variables from the .env file
environment:
# System
- TZ=${TZ}
- USER_LOCALES=${USER_LOCALES}
- DISPLAY=${DISPLAY}
# User
- PUID=${PUID}
- PGID=${PGID}
- UMASK=${UMASK}
- USER_PASSWORD=${USER_PASSWORD}
# Mode
- MODE=${MODE}
# Web UI
- WEB_UI_MODE=${WEB_UI_MODE}
- ENABLE_VNC_AUDIO=${ENABLE_VNC_AUDIO}
- PORT_NOVNC_WEB=${PORT_NOVNC_WEB}
- NEKO_NAT1TO1=${NEKO_NAT1TO1}
# Steam
- ENABLE_STEAM=${ENABLE_STEAM}
- STEAM_ARGS=${STEAM_ARGS}
# Sunshine
- ENABLE_SUNSHINE=${ENABLE_SUNSHINE}
- SUNSHINE_USER=${SUNSHINE_USER}
- SUNSHINE_PASS=${SUNSHINE_PASS}
# Xorg
- ENABLE_EVDEV_INPUTS=${ENABLE_EVDEV_INPUTS}
- FORCE_X11_DUMMY_CONFIG=${FORCE_X11_DUMMY_CONFIG}
# Nvidia specific config
- NVIDIA_DRIVER_CAPABILITIES=${NVIDIA_DRIVER_CAPABILITIES}
- NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES}
- NVIDIA_DRIVER_VERSION=${NVIDIA_DRIVER_VERSION}
# VOLUMES:
volumes:
# The location of your home directory.
- ${HOME_DIR}/:/home/default/:rw
# The location where all games should be installed.
# This path needs to be set as a library path in Steam after logging in.
# Otherwise, Steam will store games in the home directory above.
- ${GAMES_DIR}/:/mnt/games/:rw
# The Xorg socket.
- ${SHARED_SOCKETS_DIR}/.X11-unix/:/tmp/.X11-unix/:rw
# Pulse audio socket.
- ${SHARED_SOCKETS_DIR}/pulse/:/tmp/pulse/:rw
# Input devices used for mouse and joypad support inside the container.
- /dev/input/:/dev/input/:ro

View File

@@ -0,0 +1,92 @@
---
version: "3.8"
services:
steam-headless:
image: josh5/steam-headless:latest
restart: unless-stopped
shm_size: ${SHM_SIZE}
ipc: host # Could also be set to 'shareable'
ulimits:
nofile:
soft: 1024
hard: 524288
cap_add:
- NET_ADMIN
- SYS_ADMIN
- SYS_NICE
security_opt:
- seccomp:unconfined
- apparmor:unconfined
# NETWORK:
## NOTE: With this configuration, if we do not use the host network, then physical device input
## is not possible and your USB connected controllers will not work in steam games.
network_mode: host
hostname: ${NAME}
extra_hosts:
- "${NAME}:127.0.0.1"
# ENVIRONMENT:
## Read all config variables from the .env file
environment:
# System
- TZ=${TZ}
- USER_LOCALES=${USER_LOCALES}
- DISPLAY=${DISPLAY}
# User
- PUID=${PUID}
- PGID=${PGID}
- UMASK=${UMASK}
- USER_PASSWORD=${USER_PASSWORD}
# Mode
- MODE=${MODE}
# Web UI
- WEB_UI_MODE=${WEB_UI_MODE}
- ENABLE_VNC_AUDIO=${ENABLE_VNC_AUDIO}
- PORT_NOVNC_WEB=${PORT_NOVNC_WEB}
- NEKO_NAT1TO1=${NEKO_NAT1TO1}
# Steam
- ENABLE_STEAM=${ENABLE_STEAM}
- STEAM_ARGS=${STEAM_ARGS}
# Sunshine
- ENABLE_SUNSHINE=${ENABLE_SUNSHINE}
- SUNSHINE_USER=${SUNSHINE_USER}
- SUNSHINE_PASS=${SUNSHINE_PASS}
# Xorg
- ENABLE_EVDEV_INPUTS=${ENABLE_EVDEV_INPUTS}
- FORCE_X11_DUMMY_CONFIG=${FORCE_X11_DUMMY_CONFIG}
# Nvidia specific config
- NVIDIA_DRIVER_CAPABILITIES=${NVIDIA_DRIVER_CAPABILITIES}
- NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES}
- NVIDIA_DRIVER_VERSION=${NVIDIA_DRIVER_VERSION}
# DEVICES:
devices:
# Use the host fuse device [REQUIRED].
- /dev/fuse
# Add the host uinput device [REQUIRED].
- /dev/uinput
# Add AMD/Intel HW accelerated video encoding/decoding devices [REQUIRED].
# NOTE: See documentation for determining which devices to configure here if you have multiple GPUs
- /dev/dri/card1
- /dev/dri/renderD128
# Ensure container access to devices 13:*
device_cgroup_rules:
- 'c 13:* rmw'
# VOLUMES:
volumes:
# The location of your home directory.
- ${HOME_DIR}/:/home/default/:rw
# The location where all games should be installed.
# This path needs to be set as a library path in Steam after logging in.
# Otherwise, Steam will store games in the home directory above.
- ${GAMES_DIR}/:/mnt/games/:rw
# The Xorg socket.
- ${SHARED_SOCKETS_DIR}/.X11-unix/:/tmp/.X11-unix/:rw
# Pulse audio socket.
- ${SHARED_SOCKETS_DIR}/pulse/:/tmp/pulse/:rw

View File

@@ -1,80 +0,0 @@
---
services:
steam-headless:
image: josh5/steam-headless:latest
restart: unless-stopped
runtime: ${DOCKER_RUNTIME}
shm_size: ${SHM_SIZE}
ipc: host # Could also be set to 'shareable'
ulimits:
nofile:
soft: 1024
hard: 524288
cap_add:
- NET_ADMIN
- SYS_ADMIN
- SYS_NICE
security_opt:
- seccomp:unconfined
- apparmor:unconfined
# NETWORK:
hostname: ${NAME}
extra_hosts:
- "${NAME}:127.0.0.1"
networks:
external-macvlan:
ipv4_address: ${CONTAINER_IP_ADDRESS}
# ENVIRONMENT:
## Read all config variables from the .env file
env_file: .env
# DEVICES:
devices:
# Use the host fuse device.
- /dev/fuse
# Add the host uinput device.
- /dev/uinput
# Add AMD/Intel HW accelerated video encoding/decoding devices (optional)
#- /dev/dri
# Ensure container access to devices 13:*
device_cgroup_rules:
- 'c 13:* rmw'
# VOLUMES:
volumes:
# The location of your home directory.
- /opt/container-data/steam-headless/home/:/home/default/:rw
# The location where all games should be installed.
# This path needs to be set as a library path in Steam after logging in.
# Otherwise, Steam will store games in the home directory above.
- /mnt/games/:/mnt/games/:rw
# The Xorg socket. This will be shared with other containers so they can access the X server.
# Select only one option or leave commented out to not share the Xorg socket with any other Docker containers.
# Option #1) Start a X server in the container to share with any other containers.
#- /opt/container-data/steam-headless/.X11-unix/:/tmp/.X11-unix/:rw
# Option #2) Use an existing X server running on the host.
#- /tmp/.X11-unix/:/tmp/.X11-unix/:rw
# Pulse audio socket. This will be shared with other containers so they can access the audio sink.
# Leave commented out to not share the pulse socket with any other Docker containers.
#- /opt/container-data/steam-headless/pulse/:/tmp/pulse/:rw
# Input devices used for mouse and joypad support inside the container.
- /dev/input/:/dev/input/:ro
# Host udev data required for input devices
- /run/udev/data/:/run/udev/data/:ro
# Store flatpak var files in a volume.
- steam-headless-var-lib-flatpak:/var/lib/flatpak/:rw
volumes:
steam-headless-var-lib-flatpak:
networks:
external-macvlan:
external: true
name: ${NETWORK_NAME}

View File

@@ -0,0 +1,79 @@
---
version: "3.8"
services:
steam-headless:
image: josh5/steam-headless:latest
restart: unless-stopped
## NOTE: This config uses privileged to access to host to be able to access the required devices
privileged: true
shm_size: ${SHM_SIZE}
ipc: host # Could also be set to 'shareable'
ulimits:
nofile:
soft: 1024
hard: 524288
# GPU PASSTHROUGH
runtime: nvidia
# NETWORK:
## NOTE: With this configuration, if we do not use the host network, then physical device input
## is not possible and your USB connected controllers will not work in steam games.
network_mode: host
hostname: ${NAME}
extra_hosts:
- "${NAME}:127.0.0.1"
# ENVIRONMENT:
## Read all config variables from the .env file
environment:
# System
- TZ=${TZ}
- USER_LOCALES=${USER_LOCALES}
- DISPLAY=${DISPLAY}
# User
- PUID=${PUID}
- PGID=${PGID}
- UMASK=${UMASK}
- USER_PASSWORD=${USER_PASSWORD}
# Mode
- MODE=${MODE}
# Web UI
- WEB_UI_MODE=${WEB_UI_MODE}
- ENABLE_VNC_AUDIO=${ENABLE_VNC_AUDIO}
- PORT_NOVNC_WEB=${PORT_NOVNC_WEB}
- NEKO_NAT1TO1=${NEKO_NAT1TO1}
# Steam
- ENABLE_STEAM=${ENABLE_STEAM}
- STEAM_ARGS=${STEAM_ARGS}
# Sunshine
- ENABLE_SUNSHINE=${ENABLE_SUNSHINE}
- SUNSHINE_USER=${SUNSHINE_USER}
- SUNSHINE_PASS=${SUNSHINE_PASS}
# Xorg
- ENABLE_EVDEV_INPUTS=${ENABLE_EVDEV_INPUTS}
- FORCE_X11_DUMMY_CONFIG=${FORCE_X11_DUMMY_CONFIG}
# Nvidia specific config
- NVIDIA_DRIVER_CAPABILITIES=${NVIDIA_DRIVER_CAPABILITIES}
- NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES}
- NVIDIA_DRIVER_VERSION=${NVIDIA_DRIVER_VERSION}
# VOLUMES:
volumes:
# The location of your home directory.
- ${HOME_DIR}/:/home/default/:rw
# The location where all games should be installed.
# This path needs to be set as a library path in Steam after logging in.
# Otherwise, Steam will store games in the home directory above.
- ${GAMES_DIR}/:/mnt/games/:rw
# The Xorg socket.
- ${SHARED_SOCKETS_DIR}/.X11-unix/:/tmp/.X11-unix/:rw
# Pulse audio socket.
- ${SHARED_SOCKETS_DIR}/pulse/:/tmp/pulse/:rw
# Input devices used for mouse and joypad support inside the container.
- /dev/input/:/dev/input/:ro

View File

@@ -0,0 +1,101 @@
---
version: "3.8"
services:
steam-headless:
image: josh5/steam-headless:latest
restart: unless-stopped
shm_size: ${SHM_SIZE}
ipc: host # Could also be set to 'shareable'
ulimits:
nofile:
soft: 1024
hard: 524288
cap_add:
- NET_ADMIN
- SYS_ADMIN
- SYS_NICE
security_opt:
- seccomp:unconfined
- apparmor:unconfined
# GPU PASSTHROUGH
runtime: nvidia
# NETWORK:
## NOTE: With this configuration, if we do not use the host network, then physical device input
## is not possible and your USB connected controllers will not work in steam games.
network_mode: host
hostname: ${NAME}
extra_hosts:
- "${NAME}:127.0.0.1"
# ENVIRONMENT:
## Read all config variables from the .env file
environment:
# System
- TZ=${TZ}
- USER_LOCALES=${USER_LOCALES}
- DISPLAY=${DISPLAY}
# User
- PUID=${PUID}
- PGID=${PGID}
- UMASK=${UMASK}
- USER_PASSWORD=${USER_PASSWORD}
# Mode
- MODE=${MODE}
# Web UI
- WEB_UI_MODE=${WEB_UI_MODE}
- ENABLE_VNC_AUDIO=${ENABLE_VNC_AUDIO}
- PORT_NOVNC_WEB=${PORT_NOVNC_WEB}
- NEKO_NAT1TO1=${NEKO_NAT1TO1}
# Steam
- ENABLE_STEAM=${ENABLE_STEAM}
- STEAM_ARGS=${STEAM_ARGS}
# Sunshine
- ENABLE_SUNSHINE=${ENABLE_SUNSHINE}
- SUNSHINE_USER=${SUNSHINE_USER}
- SUNSHINE_PASS=${SUNSHINE_PASS}
# Xorg
- ENABLE_EVDEV_INPUTS=${ENABLE_EVDEV_INPUTS}
- FORCE_X11_DUMMY_CONFIG=${FORCE_X11_DUMMY_CONFIG}
# Nvidia specific config
- NVIDIA_DRIVER_CAPABILITIES=${NVIDIA_DRIVER_CAPABILITIES}
- NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES}
- NVIDIA_DRIVER_VERSION=${NVIDIA_DRIVER_VERSION}
# DEVICES:
devices:
# Use the host fuse device [REQUIRED].
- /dev/fuse
# Add the host uinput device [REQUIRED].
- /dev/uinput
# Add NVIDIA HW accelerated devices [OPTIONAL].
# NOTE: If you use the nvidia container toolkit, this is not needed.
# Installing the nvidia container toolkit is the recommended method for running this container
#- /dev/nvidia0
#- /dev/nvidiactl
#- /dev/nvidia-modeset
#- /dev/nvidia-uvm
#- /dev/nvidia-uvm-tools
#- /dev/nvidia-caps/nvidia-cap1
#- /dev/nvidia-caps/nvidia-cap2
# Ensure container access to devices 13:*
device_cgroup_rules:
- 'c 13:* rmw'
# VOLUMES:
volumes:
# The location of your home directory.
- ${HOME_DIR}/:/home/default/:rw
# The location where all games should be installed.
# This path needs to be set as a library path in Steam after logging in.
# Otherwise, Steam will store games in the home directory above.
- ${GAMES_DIR}/:/mnt/games/:rw
# The Xorg socket.
- ${SHARED_SOCKETS_DIR}/.X11-unix/:/tmp/.X11-unix/:rw
# Pulse audio socket.
- ${SHARED_SOCKETS_DIR}/pulse/:/tmp/pulse/:rw

View File

@@ -1,56 +0,0 @@
---
services:
steam-headless:
image: josh5/steam-headless:latest
restart: unless-stopped
runtime: ${DOCKER_RUNTIME}
## NOTE: This config uses privileged to access to host to be able to access the required devices
privileged: true
shm_size: ${SHM_SIZE}
ipc: host # Could also be set to 'shareable'
ulimits:
nofile:
soft: 1024
hard: 524288
# NETWORK:
## NOTE: If we do not use the host network, then physical device input is not possible
## and your USB connected controllers will not work in steam games.
network_mode: host
hostname: ${NAME}
extra_hosts:
- "${NAME}:127.0.0.1"
# ENVIRONMENT:
## Read all config variables from the .env file
env_file: .env
# VOLUMES:
volumes:
# The location of your home directory.
- /opt/container-data/steam-headless/home/:/home/default/:rw
# The location where all games should be installed.
# This path needs to be set as a library path in Steam after logging in.
# Otherwise, Steam will store games in the home directory above.
- /mnt/games/:/mnt/games/:rw
# The Xorg socket. This will be shared with other containers so they can access the X server.
# Select only one option:
# Option #1) Start a X server in the container to share with any other containers.
#- /opt/container-data/steam-headless/.X11-unix/:/tmp/.X11-unix/:rw
# Option #2) Use an existing X server running on the host.
#- /tmp/.X11-unix/:/tmp/.X11-unix/:rw
# Pulse audio socket. This will be shared with other containers so they can access the audio sink.
# Leave commented out to not share the pulse socket with any other Docker containers.
#- /opt/container-data/steam-headless/pulse/:/tmp/pulse/:rw
# Input devices used for mouse and joypad support inside the container.
- /dev/input/:/dev/input/:ro
# Store flatpak var files in a volume.
- steam-headless-var-lib-flatpak:/var/lib/flatpak/:rw
volumes:
steam-headless-var-lib-flatpak:

View File

@@ -38,57 +38,40 @@ sudo chown -R $(id -u):$(id -g) /mnt/games
Create a Steam Headless `/opt/container-services/steam-headless/docker-compose.yml` file.
Populate this file with the contents of the default [Docker Compose File](./compose-files/docker-compose.default.yml).
Populate this file with the contents of the default Docker Compose File
### AMD/Intel:
- [AMD and Intel GPUs](./compose-files/docker-compose.amd+intel.yml).
- [Privileged AMD and Intel GPUs Docker Compose Template](./compose-files/docker-compose.amd+intel.privileged.yml) (grants full access to host devices).
## CONFIGURE HOST:
#### Multipl AMD or Intel GPUs
It is recommended that you configure this container to use a Macvlan network. If you know what you are doing, you can also use an IPvlan or Host, but I will not be covering that setup in this documentation.
To simplify the setup process and allow you to reuse the created Macvlan for other containers, we will create this Macvlan manually rather than have Docker compose handle it. If you know what you are doing with Docker compose and you would rather have the Macvlan managed there, feel free to do so. Otherwise run this command and carry on with the setup:
### 1) Discover your parent network:
To find the parent network device, run the command `ip address show`. Find the device that has the IP address of your Host server.
If you have multiple AMD or Intel GPUs and you wish to isolate them, then follow these steps to determine the card to passthrough in the docker compose file. This requires that you do not use the privileged compose template.
1) List the PCI devices and get their IDs `lspci | grep -E 'VGA|3D'`
```
root@Tower:~# ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
3: eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc fq master br0 state UP group default qlen 1000
link/ether 7c:11:a9:b1:15:b9 brd ff:ff:ff:ff:ff:ff
4: eth0.1@eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0.1 state UP group default qlen 1000
link/ether 7c:11:a9:b1:15:b9 brd ff:ff:ff:ff:ff:ff
5: eth0.3@eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0.3 state UP group default qlen 1000
link/ether 7c:11:a9:b1:15:b9 brd ff:ff:ff:ff:ff:ff
6: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 7c:11:a9:b1:15:b9 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.43/24 brd 192.168.1.255 scope global dynamic noprefixroute br0
valid_lft 440sec preferred_lft 365sec
00:02.0 VGA compatible controller: Intel Corporation TigerLake-LP GT2 [Iris Xe Graphics] (rev 01)
06:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Cezanne [Radeon Vega Series / Radeon Vega Mobile Series] (rev c6)
```
In this example output, I will select br0 as the parent network device which has the IP address of "192.168.1.43".
In this example, the Intel GPU has an ID of `00:02.0` and the AMD GPU has an ID of `06:00.0`.
### 2) Create a macvlan Docker network
2) Discover which `/dev/dri/card*` and `/dev/dri/renderD12*` references the `00:02.0` Intel GPU (or whatever your output was). To do this, run the commands `ls -la /sys/class/drm/card*` and `ls -l /sys/class/drm/renderD*`.
```
# Set the parent network device.
NETWORK_PARTENT=br0
# Name this whatever you like, but ensure you update the `.env` file below to match.
NETWORK_NAME=steam-headless-vlan
# Choose a network subnet and gateway that matches your host network
NETWORK_SUBNET=192.168.1.0/24
NETWORK_GATEWAY=192.168.1.1
# Execute the docker network create command
sudo docker network create -d macvlan \
--subnet=${NETWORK_SUBNET:?} \
--gateway=${NETWORK_GATEWAY:?} \
-o parent=${NETWORK_PARTENT:?} \
${NETWORK_NAME:?}
lrwxrwxrwx. 1 root root 0 May 8 15:44 /sys/class/drm/card1 -> ../../devices/pci0000:00/0000:00:02.0/drm/card1
lrwxrwxrwx. 1 root root 0 May 8 15:44 /sys/class/drm/card1-DP-1 -> ../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-1
lrwxrwxrwx. 1 root root 0 May 8 15:44 /sys/class/drm/card1-DP-2 -> ../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-2
lrwxrwxrwx. 1 root root 0 May 8 15:44 /sys/class/drm/card1-DP-3 -> ../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-3
lrwxrwxrwx. 1 root root 0 May 8 15:44 /sys/class/drm/card1-DP-4 -> ../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-4
```
```
lrwxrwxrwx. 1 root root 0 May 8 15:44 /sys/class/drm/renderD128 -> ../../devices/pci0000:00/0000:00:02.0/drm/renderD128
lrwxrwxrwx. 1 root root 0 May 8 15:44 /sys/class/drm/renderD129 -> ../../devices/pci0000:00/0000:06:00.0/drm/renderD129
```
From this example output we can see that the Intel GPU is `/dev/dri/card1` and `/dev/dri/renderD128`.
### NVIDIA:
- [NVIDIA GPUs Docker Compose Template](./compose-files/docker-compose.nvidia.yml).
- [Privileged NVIDIA GPUs Docker Compose Template](./compose-files/docker-compose.nvidia.yml) (grants full access to host devices).
## CONFIGURE ENV:
@@ -105,9 +88,8 @@ sudo docker-compose up -d --force-recreate
```
After container executes successfully, navigate to your docker host URL in your browser on port 8083 and click connect.
http://<host-ip>:8083/
![img.png](../images/vnc_connect.png)
`http://<host-ip>:8083/`
![img.png](./images/web_connect.png)
If using a `/mnt/games` volume mount, wait until Steam installs and executes, then restart the container. This step
is necessary to create the required steamapps folder in the /mnt/games volume after initial installation. If this
doesn't occur, you will receive a "disk write error" when trying to install to this location.
## Troubleshooting
[Troubleshooting Docs](./troubleshooting.md)

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
docs/images/web_connect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

View File

@@ -11,7 +11,7 @@ Once your Flatpak refresh is complete, everything should work correctly and your
## An error occurred while installing <game>: "disk write error"
![img.png](../images/disk_write_error.png)
![img.png](./images/disk_write_error.png)
1) Stop the container
2) Verify your mounted /mnt/games volume is owned by the executing UID/GID, and 777 permissions are set.

View File

@@ -1,22 +1,57 @@
# Ubuntu Server
# Ubuntu Server Setup
Follow these instructions to install Steam Headless on Ubuntu Server.
Use these instructions to install **Steam Headless** on an Ubuntu Server system.
> __Note__
> ⚠️ **Note**
>
> This assumes that your Ubuntu Server has not be configured to run any desktop environment!
>
> This will not work with Ubuntu Desktop.
> These steps assume you are running a minimal **Ubuntu Server** installation **without any desktop environment**.
> This setup **will not work** on Ubuntu Desktop.
---
## INSTALL NVIDIA DRIVER:
Although you're on a server system, using the `-server` variant of the NVIDIA driver can cause compatibility issues.
Instead, install the standard driver **without recommended extras**:
```bash
apt install --no-install-recommends nvidia-driver-570
```
> 🔍 Feel free to `570` with the latest available version.
To find the latest version of the standard (non-`-server`, non-`-open`) drivers, run:
```bash
apt-cache search ^nvidia-driver- | awk '{print $1}' | grep -vE '(-server|-open)' | xargs -n1 apt-cache policy | awk '/^nvidia-driver-/{driver=$1} /Candidate:/ {print driver, $2}'
```
---
## INSTALL DOCKER:
Install docker-ce to your Ubuntu server following the [official instrctions](https://docs.docker.com/engine/install/ubuntu/).
Install `docker-ce` on your Ubuntu server by following the [official Docker instructions](https://docs.docker.com/engine/install/ubuntu/).
Ensure you install the `docker-compose-plugin` mentioned within these instructions
Make sure you also install the `docker-compose-plugin` as noted in the Docker documentation.
---
## INSTALL NVIDIA CONTAINER TOOLKIT
To enable GPU support inside Docker containers, install the [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-container-toolkit?tab=readme-ov-file).
Follow the [APT-based installation steps](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html#installing-with-apt) provided in the official documentation.
Once installed, configure Docker to use the NVIDIA runtime by default:
```bash
sudo nvidia-ctk runtime configure --runtime=docker
```
> 💡 You *can* also run the container without the NVIDIA runtime by manually uncommenting the `/dev/nvidia*` device entries in the Compose file — but this approach is **not recommended**.
---
## CONFIGURE DOCKER COMPOSE:
Once you have installed docker, follow the [Compose Files](./docker-compose.md) section and select the right configuration file for your hardware.
After installing Docker, proceed to the [Compose Files](./docker-compose.md) section and select the appropriate configuration for your hardware setup.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -22,6 +22,31 @@ if [[ -f /version.txt ]]; then
cat /version.txt
fi
function print_header {
# Magenta
echo -e "\e[35m**** ${@} ****\e[0m"
}
function print_step_header {
# Cyan
echo -e "\e[36m - ${@}\e[0m"
}
function print_warning {
# Yellow
echo -e "\e[33mWARNING: ${@}\e[0m"
}
function print_error {
# Red
echo -e "\e[31mERROR: ${@}\e[0m"
}
function print_note {
# Cyan
echo -e "\e[36mNOTE: ${@}\e[0m"
}
# Execute all container init scripts
for init_script in /etc/cont-init.d/*.sh ; do
echo
@@ -59,9 +84,9 @@ touch /tmp/.first-run-user-init-scripts
# Start supervisord
echo
echo "**** Starting supervisord ****";
echo "Logging all root services to '/var/log/supervisor/'"
echo "Logging all user services to '/home/${USER:?}/.cache/log/'"
print_header "Starting supervisord";
print_step_header "Logging all root services to '/var/log/supervisor/'"
print_step_header "Logging all user services to '/home/${USER:?}/.cache/log/'"
echo
mkdir -p /var/log/supervisor
chmod a+rw /var/log/supervisor

View File

@@ -14,18 +14,18 @@ PGID=${PGID:-100}
UMASK=${UMASK:-000}
USER_PASSWORD=${USER_PASSWORD:-password}
echo "**** Configure default user ****"
print_header "Configure default user"
echo "Setting default user uid=${PUID}(${USER}) gid=${PGID}(${USER})"
print_step_header "Setting default user uid=${PUID}(${USER}) gid=${PGID}(${USER})"
usermod -o -u "${PUID}" ${USER}
groupmod -o -g "${PGID}" ${USER}
echo "Adding default user to any additional required device groups"
print_step_header "Adding default user to any additional required device groups"
additional_groups=( video audio input pulse )
for group_name in "${additional_groups[@]}"; do
if [ $(getent group ${group_name:?}) ]; then
echo "Adding user '${USER}' to group: '${group_name}'"
print_step_header "Adding user '${USER}' to group: '${group_name}'"
usermod -aG ${group_name:?} ${USER}
fi
done
@@ -54,20 +54,20 @@ for dev in "${device_nodes[@]}"; do
# Add group to user
if [[ "${added_groups}" != *"${dev_group}"* ]]; then
echo "Adding user '${USER}' to group: '${dev_group}' for device: ${dev}"
print_step_header "Adding user '${USER}' to group: '${dev_group}' for device: ${dev}"
usermod -aG ${dev_group} ${USER}
added_groups=" ${added_groups} ${dev_group} "
fi
done
echo "Setting umask to ${UMASK}";
print_step_header "Setting umask to ${UMASK}";
umask ${UMASK}
# TODO: Move this to its own 'display' init script. It does not really belong here
# Configure the 'XDG_RUNTIME_DIR' path
echo "Create the user XDG_RUNTIME_DIR path '${XDG_RUNTIME_DIR}'"
print_step_header "Create the user XDG_RUNTIME_DIR path '${XDG_RUNTIME_DIR}'"
mkdir -p ${XDG_RUNTIME_DIR}
# Ensure it is owned by the 'default' user
chown -R ${PUID}:${PGID} ${XDG_RUNTIME_DIR}
@@ -80,19 +80,19 @@ chmod a+r /etc/alternatives/desktop-background
# Setup services log path
echo "Setting ownership of all log files in '${USER_HOME}/.cache/log'"
print_step_header "Setting ownership of all log files in '${USER_HOME}/.cache/log'"
mkdir -p "${USER_HOME}/.cache/log"
chown -R ${PUID}:${PGID} "${USER_HOME}/.cache/log"
# Set the root and user password
echo "Setting root password"
print_step_header "Setting root password"
echo "root:${USER_PASSWORD}" | chpasswd
echo "Setting user password"
print_step_header "Setting user password"
echo "${USER}:${USER_PASSWORD}" | chpasswd
# Set root XDG_RUNTIME_DIR path
mkdir -p /tmp/runtime-root
chown root:root /tmp/runtime-root
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,26 +1,17 @@
#!/usr/bin/env bash
###
# File: 11-setup_sysctl_values.sh
# Project: cont-init.d
# File Created: Friday, 1st September 2023 3:56:17 pm
# Author: Josh.5 (jsunnex@gmail.com)
# -----
# Last Modified: Monday, 1st September 2023 3:56:17 pm
# Modified By: Console and webGui login account (jsunnex@gmail.com)
###
echo "**** Configure some system kernel parameters ****"
# Configure kernel parameters
print_header "Configure some system kernel parameters"
if [ "$(cat /proc/sys/vm/max_map_count)" -ge 524288 ]; then
if [ -w "/proc/sys/vm/max_map_count" ]; then
echo "Setting the maximum number of memory map areas a process can create to 524288"
print_step_header "Setting the maximum number of memory map areas a process can create to 524288"
echo 524288 > /proc/sys/vm/max_map_count
else
echo "WARNING: Unable to set max_map_count on unprivileged container"
print_warning "Unable to set vm.max_map_count on unprivileged container"
fi
else
echo "NOTE: vm.max_map_count is already greater than '524288'"
print_step_header "The vm.max_map_count is already greater than '524288'"
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,14 +1,14 @@
# Configure dbus
echo "**** Configure container dbus ****";
print_header "Configure container dbus"
if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
if [[ "${HOST_DBUS}" == "true" ]]; then
echo "Container configured to use the host dbus";
print_step_header "Container configured to use the host dbus";
# Disable supervisord script
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/dbus.ini
else
echo "Container configured to run its own dbus";
print_step_header "Container configured to run its own dbus";
# Enable supervisord script
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/dbus.ini
# Configure dbus to run as USER
@@ -25,8 +25,8 @@ if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
find /var/run/dbus -name "pid" -exec rm -f {} \;
fi
else
echo "Dbus service not available when container is run in 'secondary' mode."
print_step_header "Dbus service not available when container is run in 'secondary' mode."
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/dbus.ini
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,60 +1,51 @@
#!/usr/bin/env bash
###
# File: 30-configure_udev.sh
# Project: cont-init.d
# File Created: Friday, 12th January 2022 8:54:01 am
# Author: Josh.5 (jsunnex@gmail.com)
# -----
# Last Modified: Tuesday, 4th October 2022 11:20:48 am
# Modified By: Josh.5 (jsunnex@gmail.com)
###
# Running udev only works in privileged container
# Source: https://github.com/balena-io-playground/balena-base-images/
tmp_mount='/tmp/privileged_test'
mkdir -p "${tmp_mount}"
if mount -t devtmpfs none "${tmp_mount}" &> /dev/null; then
is_privileged=true
umount "${tmp_mount}"
else
is_privileged=false
fi
rm -rf "${tmp_mount}"
# Configure dbus
print_header "Configure udevd"
if [[ "${is_privileged}" == "true" ]]; then
# Since this container may also be run with CAP_SYS_ADMIN, ensure we can actually execute "udevadm trigger"
if [ ! -w /sys ]; then
# Disable supervisord script since we are not able to write to sysfs
echo "**** Disable udev - /sys is mounted RO ****";
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/udev.ini
elif [ ! -w /run/udev ]; then
# Disable supervisord script since we are not able to write to udev/data path
echo "**** Disable udev - /run/udev is mounted RO ****";
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/udev.ini
elif udevadm trigger &> /dev/null; then
echo "**** Configure container to run udev management ****";
# Enable supervisord script
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/udev.ini
# Configure udev permissions
if [[ -f /lib/udev/rules.d/60-steam-input.rules ]]; then
sed -i 's/MODE="0660"/MODE="0666"/' /lib/udev/rules.d/60-steam-input.rules
fi
else
# Disable supervisord script since we are not able to execute "udevadm trigger"
echo "**** Disable udev service due to privilege restrictions ****";
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/udev.ini
fi
else
# Disable supervisord script
echo "**** Disable udev service ****";
# Since this container may also be run with CAP_SYS_ADMIN, ensure we can actually execute "udevadm trigger"
run_dumb_udev="false"
if [ ! -w /sys ]; then
# Disable supervisord script since we are not able to write to sysfs
print_step_header "Disable udevd - /sys is mounted RO"
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/udev.ini
run_dumb_udev="true"
elif [ ! -d /run/udev ]; then
# Disable supervisord script since we are not able to write to udev/data path
print_step_header "Disable udevd - /run/udev does not exist"
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/udev.ini
run_dumb_udev="true"
elif [ ! -w /run/udev ]; then
# Disable supervisord script since we are not able to write to udev/data path
print_step_header "Disable udevd - /run/udev is mounted RO"
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/udev.ini
run_dumb_udev="false"
elif udevadm trigger &> /dev/null; then
print_step_header "Configure container to run udev management"
# Enable supervisord script
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/udev.ini
# Configure udev permissions
if [[ -f /lib/udev/rules.d/60-steam-input.rules ]]; then
sed -i 's/MODE="0660"/MODE="0666"/' /lib/udev/rules.d/60-steam-input.rules
fi
run_dumb_udev="false"
else
# Disable supervisord script since we are not able to execute "udevadm trigger"
print_step_header "Disable udev service due to privilege restrictions"
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/udev.ini
run_dumb_udev="true"
fi
if [ "${run_dumb_udev}" = "true" ]; then
# Enable dumb-udev instead of udevd
print_step_header "Enable dumb-udev service"
sed -i 's|^command.*=.*$|command=start-dumb-udev.sh|' /etc/supervisor.d/udev.ini
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/udev.ini
fi
if [[ -e /dev/uinput ]]; then
echo "**** Ensure the default user has permission to r/w on input devices ****";
print_step_header "Ensure the default user has permission to r/w on input devices"
chmod 0666 /dev/uinput
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,19 +1,22 @@
# Configure dbus
print_header "Configure local"
current_local=$(head -n 1 /etc/locale.gen)
user_local=$(echo ${USER_LOCALES} | cut -d ' ' -f 1)
if [ "${current_local}" != "${USER_LOCALES}" ]; then
echo "**** Configuring Locales to ${USER_LOCALES} ****";
print_step_header "Configuring Locales to ${USER_LOCALES}"
rm /etc/locale.gen
echo -e "${USER_LOCALES}\nen_US.UTF-8 UTF-8" > "/etc/locale.gen"
export LANGUAGE="${user_local}"
export LANG="${user_local}"
export LC_ALL="${user_local}" 2> /dev/null
sleep 2
sleep 0.5
locale-gen
update-locale LC_ALL="${user_local}"
else
echo "**** Locales already set correctly to ${USER_LOCALES} ****";
print_step_header "Locales already set correctly to ${USER_LOCALES}"
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,18 +1,19 @@
echo "**** Configure pulseaudio ****"
# Configure dbus
print_header "Configure pulseaudio"
# Always enable the pulseaudio service
echo "Enable pulseaudio service."
print_step_header "Enable pulseaudio service."
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/pulseaudio.ini
if [ "${MODE}" == "s" ] | [ "${MODE}" == "secondary" ]; then
echo "Configure pulseaudio as simple dummy audio"
print_step_header "Configure pulseaudio as simple dummy audio"
sed -i 's|^; autospawn.*$|autospawn = no|' /etc/pulse/client.conf
sed -i 's|^; daemon-binary.*$|daemon-binary = /bin/true|' /etc/pulse/client.conf
sed -i 's|^; flat-volumes.*$|flat-volumes = yes|' /etc/pulse/daemon.conf
else
echo "Configure pulseaudio to pipe audio to a socket"
print_step_header "Configure pulseaudio to pipe audio to a socket"
# Ensure pulseaudio directories have the correct permissions
mkdir -p \
@@ -37,4 +38,4 @@ else
fi
chown -R ${USER} /etc/pulse
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,20 +1,22 @@
# Fech NVIDIA GPU device (if one exists)
if [ "${NVIDIA_VISIBLE_DEVICES:-}" = "all" ]; then
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2> /dev/null | sed -n 2p)
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2>/dev/null | sed -n 2p)
elif [ "${NVIDIA_VISIBLE_DEVICES:-}X" = "X" ]; then
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2> /dev/null | sed -n 2p)
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2>/dev/null | sed -n 2p)
else
export gpu_select=$(nvidia-smi --format=csv --id=$(echo "$NVIDIA_VISIBLE_DEVICES" | cut -d ',' -f1) --query-gpu=uuid | sed -n 2p)
if [ "${gpu_select:-}X" = "X" ]; then
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2> /dev/null | sed -n 2p)
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2>/dev/null | sed -n 2p)
fi
fi
# NVIDIA Params
export nvidia_pci_address="$(nvidia-smi --format=csv --query-gpu=pci.bus_id --id="${gpu_select:?}" 2> /dev/null | sed -n 2p | cut -d ':' -f2,3)"
export nvidia_gpu_name=$(nvidia-smi --format=csv --query-gpu=name --id="${gpu_select:?}" 2> /dev/null | sed -n 2p)
export nvidia_host_driver_version="$(nvidia-smi 2> /dev/null | grep NVIDIA-SMI | cut -d ' ' -f3)"
if [ "X${gpu_select:-}" != "X" ]; then
export nvidia_pci_address="$(nvidia-smi --format=csv --query-gpu=pci.bus_id --id="${gpu_select:?}" 2>/dev/null | sed -n 2p | cut -d ':' -f2,3)"
export nvidia_gpu_name=$(nvidia-smi --format=csv --query-gpu=name --id="${gpu_select:?}" 2>/dev/null | sed -n 2p)
export nvidia_host_driver_version="$(nvidia-smi 2>/dev/null | grep NVIDIA-SMI | cut -d ' ' -f3)"
fi
# Intel params
# This figures out if it's an intel CPU with integrated GPU
@@ -27,38 +29,56 @@ export amd_cpu_model="$(lscpu | grep 'Model name:' | grep -i amd | cut -d':' -f2
export amd_gpu_model="$(lspci | grep -i vga | grep -i amd)"
function download_driver {
local driver_url
local stripped_version
mkdir -p "${USER_HOME:?}/Downloads"
chown -R ${USER:?} "${USER_HOME:?}/Downloads"
if [[ ! -f "${USER_HOME:?}/Downloads/NVIDIA_${nvidia_host_driver_version:?}.run" ]]; then
echo "Downloading driver v${nvidia_host_driver_version:?}"
wget -q --show-progress --progress=bar:force:noscroll \
-O /tmp/NVIDIA.run \
"http://download.nvidia.com/XFree86/Linux-x86_64/${nvidia_host_driver_version:?}/NVIDIA-Linux-x86_64-${nvidia_host_driver_version:?}.run"
[[ $? -gt 0 ]] && echo "Error downloading driver. Exit!" && return 1
print_step_header "Downloading driver v${nvidia_host_driver_version:?}"
mv /tmp/NVIDIA.run "${USER_HOME:?}/Downloads/NVIDIA_${nvidia_host_driver_version:?}.run"
# Try downloading from a list of NVIDIA driver hosting servers
stripped_version="${nvidia_host_driver_version#v}" # Strip 'v' if present
declare -a sources=(
"https://download.nvidia.com/XFree86/Linux-x86_64/${nvidia_host_driver_version}/NVIDIA-Linux-x86_64-${nvidia_host_driver_version}.run"
"https://us.download.nvidia.com/XFree86/Linux-x86_64/${nvidia_host_driver_version}/NVIDIA-Linux-x86_64-${nvidia_host_driver_version}.run"
"https://github.com/flathub/org.freedesktop.Platform.GL.nvidia/releases/download/cuda/NVIDIA-Linux-x86_64-${stripped_version}.run"
)
for driver_url in "${sources[@]}"; do
if wget -q --show-progress --progress=bar:force:noscroll \
-O /tmp/NVIDIA.run \
"${driver_url:?}"; then
mv /tmp/NVIDIA.run "${USER_HOME:?}/Downloads/NVIDIA_${nvidia_host_driver_version:?}.run"
return 0
mv /tmp/NVIDIA.run "${USER_HOME:?}/Downloads/NVIDIA_${nvidia_host_driver_version:?}.run"
return 0
else
print_warning "Download failed from: ${driver_url}"
fi
done
print_note "Visit https://download.nvidia.com/XFree86/Linux-x86_64/ in a browser and find the closest match to version '${nvidia_host_driver_version:?}', then set that version in the NVIDIA_DRIVER_VERSION environment variable."
print_error "Unable to download driver from any source. Exit!"
sleep 10
return 1
fi
}
function install_nvidia_driver {
# Check here if the currently installed version matches using nvidia-settings
nvidia_settings_version=$(nvidia-settings --version 2> /dev/null | grep version | cut -d ' ' -f 4)
nvidia_settings_version=$(nvidia-settings --version 2>/dev/null | grep version | cut -d ' ' -f 4)
if [ "${nvidia_settings_version:-}X" != "${nvidia_host_driver_version:-}X" ]; then
# Download the driver (if it does not yet exist locally)
download_driver
# if command -v pacman &> /dev/null; then
# echo "Install NVIDIA vulkan utils" \
# && pacman -Syu --noconfirm --needed \
# lib32-nvidia-utils \
# lib32-vulkan-icd-loader
# nvidia-utils \
# vulkan-icd-loader \
# && echo
# fi
if (($(echo $nvidia_host_driver_version | cut -d '.' -f 1) >= 550)); then
sed -i 's/--no-multigpu//g' /etc/cont-init.d/70-configure_xorg.sh
fi
if (($(echo $nvidia_host_driver_version | cut -d '.' -f 1) > 500)); then
echo "Installing NVIDIA driver v${nvidia_host_driver_version:?} to match what is running on the host"
print_step_header "Installing NVIDIA driver v${nvidia_host_driver_version:?} to match what is running on the host"
chmod +x "${USER_HOME:?}/Downloads/NVIDIA_${nvidia_host_driver_version:?}.run"
"${USER_HOME:?}/Downloads/NVIDIA_${nvidia_host_driver_version:?}.run" \
--silent \
@@ -77,9 +97,9 @@ function install_nvidia_driver {
--no-check-for-alternate-installs \
--no-libglx-indirect \
--no-install-libglvnd \
> "${USER_HOME:?}/Downloads/nvidia_gpu_install.log" 2>&1
else
echo "Installing Legacy NVIDIA driver v${nvidia_host_driver_version:?} to match what is running on the host"
>"${USER_HOME:?}/Downloads/nvidia_gpu_install.log" 2>&1
else
print_step_header "Installing Legacy NVIDIA driver v${nvidia_host_driver_version:?} to match what is running on the host"
chmod +x "${USER_HOME:?}/Downloads/NVIDIA_${nvidia_host_driver_version:?}.run"
"${USER_HOME:?}/Downloads/NVIDIA_${nvidia_host_driver_version:?}.run" \
--silent \
@@ -98,8 +118,10 @@ function install_nvidia_driver {
--no-check-for-alternate-installs \
--no-libglx-indirect \
--no-install-libglvnd \
> "${USER_HOME:?}/Downloads/nvidia_gpu_install.log" 2>&1
>"${USER_HOME:?}/Downloads/nvidia_gpu_install.log" 2>&1
fi
else
print_step_header "NVIDIA driver version ${nvidia_settings_version:-} is already installed"
fi
}
@@ -110,13 +132,13 @@ function patch_nvidia_driver {
(
set +e
if [ ! -f "${USER_HOME:?}/Downloads/nvidia-patch.${NVIDIA_PATCH_VERSION:?}.sh" ]; then
echo "Fetch NVIDIA NVENC patch"
print_step_header "Fetch NVIDIA NVENC patch"
wget -q --show-progress --progress=bar:force:noscroll \
-O "${USER_HOME:?}/Downloads/nvidia-patch.${NVIDIA_PATCH_VERSION:?}.sh" \
"https://raw.githubusercontent.com/keylase/nvidia-patch/${NVIDIA_PATCH_VERSION:?}/patch.sh"
fi
if [ ! -f "${USER_HOME:?}/Downloads/nvidia-patch-fbc.${NVIDIA_PATCH_VERSION:?}.sh" ]; then
echo "Fetch NVIDIA NvFBC patch"
print_step_header "Fetch NVIDIA NvFBC patch"
wget -q --show-progress --progress=bar:force:noscroll \
-O "${USER_HOME:?}/Downloads/nvidia-patch-fbc.${NVIDIA_PATCH_VERSION:?}.sh" \
"https://raw.githubusercontent.com/keylase/nvidia-patch/${NVIDIA_PATCH_VERSION:?}/patch-fbc.sh"
@@ -125,89 +147,113 @@ function patch_nvidia_driver {
"${USER_HOME:?}/Downloads/nvidia-patch.${NVIDIA_PATCH_VERSION:?}.sh" \
"${USER_HOME:?}/Downloads/nvidia-patch-fbc.${NVIDIA_PATCH_VERSION:?}.sh"
echo "Install NVIDIA driver patches"
echo "/patched-lib" > /etc/ld.so.conf.d/000-patched-lib.conf
print_step_header "Install NVIDIA driver patches"
echo "/patched-lib" >/etc/ld.so.conf.d/000-patched-lib.conf
mkdir -p "/patched-lib"
PATCH_OUTPUT_DIR="/patched-lib" "${USER_HOME:?}/Downloads/nvidia-patch.${NVIDIA_PATCH_VERSION:?}.sh"
PATCH_OUTPUT_DIR="/patched-lib" "${USER_HOME:?}/Downloads/nvidia-patch-fbc.${NVIDIA_PATCH_VERSION:?}.sh"
pushd "/patched-lib" &> /dev/null || { echo "Error: Failed to push directory to /patched-lib"; exit 1; }
for f in * ; do
pushd "/patched-lib" &>/dev/null || {
print_error "Failed to push directory to /patched-lib"
exit 1
}
for f in *; do
suffix="${f##*.so}"
name="$(basename "$f" "$suffix")"
[ -h "$name" ] || ln -sf "$f" "$name"
[ -h "$name" ] || ln -sf "$f" "$name.1"
done
ldconfig
popd &> /dev/null || { echo "Error: Failed to pop directory out of /patched-lib"; exit 1; }
popd &>/dev/null || {
print_error "Failed to pop directory out of /patched-lib"
exit 1
}
)
else
echo "Leaving NVIDIA driver stock without patching"
print_step_header "Leaving NVIDIA driver stock without patching"
fi
}
function install_deb_mesa {
if [ ! -f /tmp/init-mesa-libs-install.log ]; then
print_step_header "Enable i386 arch"
dpkg --add-architecture i386
if [ "${ENABLE_SID:-}" = "true" ]; then
print_step_header "Add Debian SID sources"
echo "deb http://deb.debian.org/debian/ sid main" >/etc/apt/sources.list
fi
apt-get update &>>/tmp/init-mesa-libs-install.log
print_step_header "Install mesa vulkan drivers"
echo "" >>/tmp/init-mesa-libs-install.log
apt-get install -y --no-install-recommends \
libvulkan1 \
libvulkan1:i386 \
mesa-vulkan-drivers \
mesa-vulkan-drivers:i386 \
mesa-utils \
mesa-utils-extra \
vulkan-tools \
&>>/tmp/init-mesa-libs-install.log
else
print_step_header "Mesa has already been installed into this container"
fi
}
function install_amd_gpu_driver {
echo "Install AMD vulkan driver"
if command -v pacman &> /dev/null; then
if command -v pacman &>/dev/null; then
print_step_header "Install AMD Mesa driver"
pacman -Syu --noconfirm --needed \
lib32-vulkan-icd-loader \
lib32-vulkan-radeon \
vulkan-icd-loader \
vulkan-radeon
# There is currently nothing to install inside the debian container. This already comes with the vulken drives that are required
# elif command -v apt-get &> /dev/null; then
# [[ "${APT_UPDATED:-false}" == 'false' ]] && apt-get update && export APT_UPDATED=true
# apt-get install -y \
# libvulkan1 \
# libvulkan1:i386 \
# mesa-vulkan-drivers \
# mesa-vulkan-drivers:i386
elif command -v apt-get &>/dev/null; then
install_deb_mesa
fi
}
function install_intel_gpu_driver {
echo "Install Intel vulkan driver"
if command -v pacman &> /dev/null; then
if command -v pacman &>/dev/null; then
print_step_header "Install Intel Mesa driver"
pacman -Syu --noconfirm --needed \
lib32-vulkan-icd-loader \
lib32-vulkan-intel \
vulkan-icd-loader \
vulkan-intel
# There is currently nothing to install inside the debian container. This already comes with the vulken drives that are required
# elif command -v apt-get &> /dev/null; then
# [[ "${APT_UPDATED:-false}" == 'false' ]] && apt-get update && export APT_UPDATED=true
# apt-get install -y \
# libvulkan1 \
# libvulkan1:i386 \
# mesa-vulkan-drivers \
# mesa-vulkan-drivers:i386
elif command -v apt-get &>/dev/null; then
install_deb_mesa
fi
}
# Intel Arc GPU or Intel CPU with possible iGPU
if [ "${intel_gpu_model:-}X" != "X" ]; then
echo "**** Found Intel device '${intel_gpu_model:?}' ****"
print_header "Found Intel device '${intel_gpu_model:?}'"
install_intel_gpu_driver
elif [ "${intel_cpu_model:-}X" != "X" ]; then
echo "**** Found Intel device '${intel_cpu_model:?}' ****"
print_header "Found Intel device '${intel_cpu_model:?}'"
install_intel_gpu_driver
else
echo "**** No Intel device found ****"
print_header "No Intel device found"
fi
# AMD GPU
if [ "${amd_gpu_model:-}X" != "X" ]; then
echo "**** Found AMD device '${amd_gpu_model:?}' ****"
print_header "Found AMD device '${amd_gpu_model:?}'"
install_amd_gpu_driver
else
echo "**** No AMD device found ****"
print_header "No AMD device found"
fi
# NVIDIA GPU
if [ "${nvidia_pci_address:-}X" != "X" ]; then
echo "**** Found NVIDIA device '${nvidia_gpu_name:?}' ****"
if [ "${NVIDIA_DRIVER_VERSION:-}X" != "X" ]; then
export nvidia_host_driver_version="${NVIDIA_DRIVER_VERSION:?}"
print_header "Forcing install of NVIDIA driver version '${nvidia_host_driver_version:?}' because the 'NVIDIA_DRIVER_VERSION' variable is set."
install_nvidia_driver
patch_nvidia_driver
elif [ "${nvidia_pci_address:-}X" != "X" ]; then
print_header "Found NVIDIA device '${nvidia_gpu_name:?}'"
install_nvidia_driver
patch_nvidia_driver
else
echo "**** No NVIDIA device found ****"
print_header "No NVIDIA device found"
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,22 +1,22 @@
echo "**** Configure Desktop ****"
print_header "Configure Desktop"
if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
echo "Enable Desktop service."
print_step_header "Enable Desktop service."
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/desktop.ini
else
echo "Desktop service not available when container is run in 'secondary' mode."
print_step_header "Desktop service not available when container is run in 'secondary' mode."
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/desktop.ini
fi
# Setup home directory
if [[ ! -f /tmp/.home-directory-template-updated ]]; then
echo "Ensure home directory template is owned by the default user."
print_step_header "Ensure home directory template is owned by the default user."
chown -R ${PUID}:${PGID} /templates/home_directory_template
echo "Installing default home directory template"
print_step_header "Installing default home directory template"
mkdir -p "${USER_HOME:?}"
rsync -aq /templates/home_directory_template/ "${USER_HOME:?}"/
touch /tmp/.home-directory-template-updated
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -30,36 +30,42 @@ fi
# Configure a NVIDIA X11 config
function configure_nvidia_x_server {
echo "Configuring X11 with GPU ID: '${gpu_select}'"
print_step_header "Configuring X11 with GPU ID: '${gpu_select}'"
nvidia_gpu_hex_id=$(nvidia-smi --format=csv --query-gpu=pci.bus_id --id="${gpu_select}" 2> /dev/null | sed -n 2p)
IFS=":." ARR_ID=(${nvidia_gpu_hex_id})
unset IFS
bus_id=PCI:$((16#${ARR_ID[1]})):$((16#${ARR_ID[2]})):$((16#${ARR_ID[3]}))
echo "Configuring X11 with PCI bus ID: '${bus_id}'"
print_step_header "Configuring X11 with PCI bus ID: '${bus_id}'"
export MODELINE=$(cvt -r "${DISPLAY_SIZEW}" "${DISPLAY_SIZEH}" "${DISPLAY_REFRESH}" | sed -n 2p)
echo "Writing X11 config with ${MODELINE}"
print_step_header "Writing X11 config with ${MODELINE}"
connected_monitor="--use-display-device=None"
if [[ "X${DISPLAY_VIDEO_PORT:-}" != "X" ]]; then
connected_monitor="--connected-monitor=${DISPLAY_VIDEO_PORT:?}"
fi
nvidia-xconfig --virtual="${DISPLAY_SIZEW:?}x${DISPLAY_SIZEH:?}" --depth="${DISPLAY_CDEPTH:?}" --mode=$(echo "${MODELINE:?}" | awk '{print $2}' | tr -d '"') --allow-empty-initial-configuration --no-probe-all-gpus --busid="${bus_id:?}" --no-multigpu --no-sli --no-base-mosaic --only-one-x-screen ${connected_monitor:?}
sed -i '/Driver\s\+"nvidia"/a\ Option "ModeValidation" "NoMaxPClkCheck, NoEdidMaxPClkCheck, NoMaxSizeCheck, NoHorizSyncCheck, NoVertRefreshCheck, NoVirtualSizeCheck, NoTotalSizeCheck, NoDualLinkDVICheck, NoDisplayPortBandwidthCheck, AllowNon3DVisionModes, AllowNonHDMI3DModes, AllowNonEdidModes, NoEdidHDMI2Check, AllowDpInterlaced"\n Option "HardDPMS" "False"' /etc/X11/xorg.conf
# Allow SteamHeadless to run with an eGPU
sed -i '/Driver\s\+"nvidia"/a\ Option "AllowExternalGpus" "True"' /etc/X11/xorg.conf
# Configure primary GPU
sed -i '/Driver\s\+"nvidia"/a\ Option "PrimaryGPU" "yes"' /etc/X11/xorg.conf
# Force X server to start even if no display devices are connected
sed -i '/Driver\s\+"nvidia"/a\ Option "AllowEmptyInitialConfiguration"' /etc/X11/xorg.conf
# Disable some mode validation checks
sed -i '/Driver\s\+"nvidia"/a\ Option "ModeValidation" "NoMaxPClkCheck, NoEdidMaxPClkCheck, NoMaxSizeCheck, NoHorizSyncCheck, NoVertRefreshCheck, NoVirtualSizeCheck, NoTotalSizeCheck, NoDualLinkDVICheck, NoDisplayPortBandwidthCheck, AllowNon3DVisionModes, AllowNonHDMI3DModes, AllowNonEdidModes, NoEdidHDMI2Check, AllowDpInterlaced"' /etc/X11/xorg.conf
# Configure the default modeline
sed -i '/Section\s\+"Monitor"/a\ '"${MODELINE}" /etc/X11/xorg.conf
# Prevent interference between GPUs
echo -e "Section \"ServerFlags\"\n Option \"AutoAddGPU\" \"false\"\nEndSection" | tee -a /etc/X11/xorg.conf > /dev/null
# Configure primary GPU
sed -i '/Driver\s\+"nvidia"/a\ Option "AllowEmptyInitialConfiguration"\n Option "PrimaryGPU" "yes"' /usr/share/X11/xorg.conf.d/nvidia-drm-outputclass.conf
}
# Allow anybody for running x server
function configure_x_server {
# Configure x to be run by anyone
if [[ ! -f /etc/X11/Xwrapper.config ]]; then
echo "Create Xwrapper.config"
print_step_header "Create Xwrapper.config"
echo 'allowed_users=anybody' > /etc/X11/Xwrapper.config
echo 'needs_root_rights=yes' >> /etc/X11/Xwrapper.config
elif grep -Fxq "allowed_users=console" /etc/X11/Xwrapper.config; then
echo "Configure Xwrapper.config"
print_step_header "Configure Xwrapper.config"
sed -i "s/allowed_users=console/allowed_users=anybody/" /etc/X11/Xwrapper.config
echo 'needs_root_rights=yes' >> /etc/X11/Xwrapper.config
fi
@@ -73,7 +79,7 @@ function configure_x_server {
# Clear out old lock files
display_file=${XORG_SOCKET_DIR}/X${DISPLAY#:}
if [ -S ${display_file} ]; then
echo "Removing ${display_file} before starting"
print_step_header "Removing ${display_file} before starting"
rm -f /tmp/.X${DISPLAY#:}-lock
rm ${display_file}
fi
@@ -84,46 +90,46 @@ function configure_x_server {
chmod 1777 /tmp/.ICE-unix/
# Check if this container is being run as a secondary instance
if [ "${MODE}" == "p" ] | [ "${MODE}" == "primary" ]; then
echo "Configure container as primary the X server"
if ([ "${MODE}" = "p" ] || [ "${MODE}" = "primary" ]); then
print_step_header "Configure container as primary the X server"
# Enable supervisord script
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/xorg.ini
elif [ "${MODE}" == "fb" ] | [ "${MODE}" == "framebuffer" ]; then
echo "Configure container to use a virtual framebuffer as the X server"
print_step_header "Configure container to use a virtual framebuffer as the X server"
# Disable xorg supervisord script
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/xorg.ini
# Enable xvfb supervisord script
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/xvfb.ini
else
echo "Configure container with no X server"
print_step_header "Configure container with no X server"
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/xorg.ini
fi
# Enable KB/Mouse input capture with Xorg if configured
if [ ${ENABLE_EVDEV_INPUTS:-} = "true" ]; then
echo "Enabling evdev input class on pointers, keyboards, touchpads, touch screens, etc."
cp -fv /usr/share/X11/xorg.conf.d/10-evdev.conf /etc/X11/xorg.conf.d/10-evdev.conf
print_step_header "Enabling evdev input class on pointers, keyboards, touchpads, touch screens, etc."
cp -f /usr/share/X11/xorg.conf.d/10-evdev.conf /etc/X11/xorg.conf.d/10-evdev.conf
else
echo "Leaving evdev inputs disabled"
print_step_header "Leaving evdev inputs disabled"
fi
# Configure dummy config if no monitor is connected (not applicable to NVIDIA)
if [[ "X${monitor_connected}" == "X" ]]; then
echo "No monitors connected. Installing dummy xorg.conf"
if ([ "X${monitor_connected}" = "X" ] || [ "${FORCE_X11_DUMMY_CONFIG}" = "true" ]); then
print_step_header "No monitors connected. Installing dummy xorg.conf"
# Use a dummy display input
cp -fv /templates/xorg/xorg.dummy.conf /etc/X11/xorg.conf
cp -f /templates/xorg/xorg.dummy.conf /etc/X11/xorg.conf
fi
}
if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
if [[ -z ${nvidia_gpu_hex_id} ]]; then
echo "**** Generate default xorg.conf ****";
print_header "Generate default xorg.conf"
configure_x_server
else
echo "**** Generate NVIDIA xorg.conf ****";
print_header "Generate NVIDIA xorg.conf"
configure_x_server
configure_nvidia_x_server
fi
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,13 +1,13 @@
echo "**** Configure Flatpak ****"
print_header "Configure Flatpak"
if [ "X${NVIDIA_VISIBLE_DEVICES:-}" != "X" ]; then
# Fix some flatpak quirks (not sure what is happening here) for NVIDIA containers
mount -t proc none /proc
flatpak list
echo "Flatpak configured for running inside a Docker container"
print_step_header "Flatpak configured for running inside a Docker container"
else
echo "Flatpak already configured for running inside a Docker container"
print_step_header "Flatpak already configured for running inside a Docker container"
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,10 +1,10 @@
echo "**** Configure Neko ****"
print_header "Configure Neko"
# REF: https://neko.m1k1o.net/#/getting-started/configuration
if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
if [ ${WEB_UI_MODE} = "neko" ]; then
echo "Enable Neko server"
print_step_header "Enable Neko server"
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/neko.ini
# Make directories for neko
@@ -15,9 +15,9 @@ if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
# Configure nat1to1 if it is not already set
if [[ -z ${NEKO_NAT1TO1} ]]; then
export NEKO_NAT1TO1=$(ip route get 1 | awk '{print $(NF-2);exit}')
echo "Setting NEKO_NAT1TO1=${NEKO_NAT1TO1}"
print_step_header "Setting NEKO_NAT1TO1=${NEKO_NAT1TO1}"
else
echo "User provided setting NEKO_NAT1TO1=${NEKO_NAT1TO1}"
print_step_header "User provided setting NEKO_NAT1TO1=${NEKO_NAT1TO1}"
fi
# Configure hardware acceleration if it is not already set
@@ -39,10 +39,10 @@ if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
export NEKO_SCREEN="${DISPLAY_SIZEW}x${DISPLAY_SIZEH}@${DISPLAY_REFRESH}"
fi
else
echo "Disable Neko server"
print_step_header "Disable Neko server"
fi
else
echo "Neko server not available when container is run in 'secondary' mode"
print_step_header "Neko server not available when container is run in 'secondary' mode"
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,7 +1,8 @@
echo "**** Configure Steam ****"
print_header "Configure Steam"
steam_autostart_desktop="$(cat <<EOF
steam_autostart_desktop="$(
cat <<EOF
[Desktop Entry]
Encoding=UTF-8
Type=Application
@@ -17,19 +18,117 @@ Hidden=false
EOF
)"
default_steam_config="$(
cat <<EOF
"InstallConfigStore"
{
"Software"
{
"Valve"
{
"Steam"
{
"CompatToolMapping"
{
"0"
{
"name" "proton_hotfix"
"config" ""
"priority" "75"
}
}
}
}
}
}
EOF
)"
default_steam_library_config="$(
cat <<EOF
"libraryfolders"
{
"0"
{
"path" "/home/default/.steam/steam"
"label" "Home"
"totalsize" "0"
"update_clean_bytes_tally" "0"
"time_last_update_verified" "0"
"apps"
{
}
}
"1"
{
"path" "/mnt/games/GameLibrary/Steam"
"label" "Games"
"contentid" "4532270033051814356"
"totalsize" "0"
"update_clean_bytes_tally" "0"
"time_last_update_verified" "0"
"apps"
{
}
}
}
EOF
)"
games_steam_library_config="$(
cat <<EOF
"libraryfolder"
{
"contentid" "4532270033051814356"
"label" "Games"
}
EOF
)"
if [ "${ENABLE_STEAM:-}" = "true" ]; then
if [ "${MODE}" == "s" ] | [ "${MODE}" == "secondary" ]; then
echo "Enable Steam supervisor.d service"
if [ "${MODE}" == "s" ] || [ "${MODE}" == "secondary" ]; then
print_step_header "Enable Steam supervisor.d service"
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/steam.ini
else
echo "Enable Steam auto-start script"
print_step_header "Enable Steam auto-start script"
mkdir -p "${USER_HOME:?}/.config/autostart"
echo "${steam_autostart_desktop:?}" > "${USER_HOME:?}/.config/autostart/Steam.desktop"
echo "${steam_autostart_desktop:?}" >"${USER_HOME:?}/.config/autostart/Steam.desktop"
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/steam.ini
fi
# Ensuring Steam Play is enabled for all titles
CONFIG_VDF="${USER_HOME:?}/.steam/steam/config/config.vdf"
if [ ! -f "${CONFIG_VDF}" ]; then
print_step_header "Initializing Steam config"
mkdir -p "$(dirname "${CONFIG_VDF}")"
echo "${default_steam_config}" >"${CONFIG_VDF}"
chown -R "${USER:?}:${USER:?}" "${USER_HOME:?}/.steam"
else
print_step_header "Steam config already exists, skipping initialization"
fi
# Ensure Steam library folder is set to /mnt/games if not already
LIBRARY_VDF="${USER_HOME:?}/.steam/steam/steamapps/libraryfolders.vdf"
if [ ! -f "${LIBRARY_VDF}" ]; then
print_step_header "Initializing Steam library"
mkdir -p "$(dirname "${LIBRARY_VDF}")"
echo "${default_steam_library_config}" >"${LIBRARY_VDF}"
chown -R "${USER:?}:${USER:?}" "${USER_HOME:?}/.steam"
# Only if we have mounted a /mnt/games path, then make the default games library for steam
if [ -d "/mnt/games" ]; then
mkdir -p "/mnt/games/GameLibrary/Steam/steamapps"
chown "${USER:?}:${USER:?}" \
"/mnt/games/GameLibrary" \
"/mnt/games/GameLibrary/Steam" \
"/mnt/games/GameLibrary/Steam/steamapps"
echo "${games_steam_library_config}" >"/mnt/games/GameLibrary/Steam/libraryfolder.vdf"
fi
else
print_step_header "Steam library config already exists, skipping initialization"
fi
else
echo "Disable Steam service"
print_step_header "Disable Steam service"
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/steam.ini
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,15 +1,15 @@
echo "**** Configure Sunshine ****"
print_header "Configure Sunshine"
if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
if [ "${ENABLE_SUNSHINE:-}" = "true" ]; then
echo "Enable Sunshine server"
print_step_header "Enable Sunshine server"
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/sunshine.ini
else
echo "Disable Sunshine server"
print_step_header "Disable Sunshine server"
fi
else
echo "Sunshine server not available when container is run in 'secondary' mode"
print_step_header "Sunshine server not available when container is run in 'secondary' mode"
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -1,5 +1,5 @@
echo "**** Configure VNC ****"
print_header "Configure VNC"
function get_next_unused_port() {
local __start_port=${1}
@@ -16,15 +16,15 @@ function get_next_unused_port() {
# REF: https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?&page=130
DYNAMIC_PORT_VNC=$(get_next_unused_port 32035)
export PORT_VNC=${PORT_VNC:-$DYNAMIC_PORT_VNC}
echo "Configure VNC service port '${PORT_VNC}'"
print_step_header "Configure VNC service port '${PORT_VNC}'"
DYNAMIC_PORT_AUDIO_STREAM=$(get_next_unused_port ${DYNAMIC_PORT_VNC})
export PORT_AUDIO_STREAM=${PORT_AUDIO_STREAM:-$DYNAMIC_PORT_AUDIO_STREAM}
echo "Configure pulseaudio encoded stream port '${PORT_AUDIO_STREAM}'"
print_step_header "Configure pulseaudio encoded stream port '${PORT_AUDIO_STREAM}'"
if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
if [ "${WEB_UI_MODE:-}" = "vnc" ]; then
echo "Enable VNC server"
print_step_header "Enable VNC server"
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/vnc.ini
# TODO: Remove this... Always enable VNC audio
@@ -32,20 +32,20 @@ if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
# Enable supervisord script
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/vnc-audio.ini
else
echo "Disable audio stream"
echo "Disable audio websock"
print_step_header "Disable audio stream"
print_step_header "Disable audio websock"
# Disable supervisord script
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/vnc-audio.ini
fi
else
echo "Disable VNC server"
print_step_header "Disable VNC server"
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/vnc.ini
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/vnc-audio.ini
fi
else
echo "VNC server not available when container is run in 'secondary' mode"
print_step_header "VNC server not available when container is run in 'secondary' mode"
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/vnc.ini
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/vnc-audio.ini
fi
echo "DONE"
echo -e "\e[34mDONE\e[0m"

View File

@@ -9,12 +9,12 @@
# Modified By: Josh.5 (jsunnex@gmail.com)
###
echo "**** Configure WoL Manager ****"
print_header "Configure WoL Manager"
if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
if [ "${ENABLE_WOL_POWER_MANAGER:-}" = "true" ]; then
if [ -f "/tmp/.wol-monitor" ]; then
echo "Container started in WoL Manager mode. Disabling all other services."
print_step_header "Container started in WoL Manager mode. Disabling all other services."
for init_config in /etc/supervisor.d/*.ini ; do
init_config_basename=$(basename "${init_config:?}")
init_name="${init_config_basename%.*}"
@@ -23,12 +23,12 @@ if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then
sed -i 's|^autostart.*=.*$|autostart=false|' "${init_config:?}"
done
fi
echo "Enable WoL Manager service."
print_step_header "Enable WoL Manager service."
sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/wol-power-manager.ini
else
echo "Disable WoL Manager service."
print_step_header "Disable WoL Manager service."
sed -i 's|^autostart.*=.*$|autostart=false|' /etc/supervisor.d/wol-power-manager.ini
fi
else
echo "WoL Manager service not available when container is run in 'secondary' mode."
print_step_header "WoL Manager service not available when container is run in 'secondary' mode."
fi

View File

@@ -1,4 +1,3 @@
"libraryfolders"
[Desktop Entry]
NoDisplay=true
Version=1.0

View File

@@ -13,12 +13,13 @@
"image-path": "steam.png",
"exclude-global-prep-cmd": "true",
"detached": [
"\/usr\/bin\/sunshine-run \/usr\/games\/steam steam:\/\/open\/bigpicture"
"\/usr\/games\/steam steam:\/\/open\/bigpicture",
"\/usr\/bin\/sunshine-run sleep infinity"
],
"prep-cmd": [
{
"do": "",
"undo": "sh -c \"sleep 7 && pkill -f -2 \/usr\/bin\/sunshine\""
"undo": "sh -c \"sleep 5 && pkill -f -2 \/usr\/bin\/sunshine\""
},
{
"do": "",
@@ -27,6 +28,10 @@
{
"do": "",
"undo": "\/usr\/bin\/xfce4-close-all-windows"
},
{
"do": "",
"undo": "\/usr\/games\/steam steam:\/\/close\/bigpicture"
}
]
}

View File

@@ -28,7 +28,7 @@ wait_for_x() {
wait_for_udev() {
MAX=10
CT=0
while [ ! -f /tmp/.started-udev ]; do
while [ ! -e /run/udev/control ]; do
sleep 1
CT=$(( CT + 1 ))
if [ "$CT" -ge "$MAX" ]; then

View File

@@ -9,7 +9,6 @@ flatpak --user install --assumeyes --or-update flathub org.mozilla.firefox
# Configure Firefox as the default browser
echo "Configure Firefox..."
custom_webbrowser="$(cat <<EOF
"libraryfolders"
[Desktop Entry]
NoDisplay=true
Version=1.0

View File

@@ -0,0 +1,35 @@
#!/bin/bash
###
# File: set-custom-res.sh
# Project: bin
# Author: LyzardByte Community Docs
###
# Get params and set any defaults
width=${1:-1920}
height=${2:-1080}
refresh_rate=${3:-60}
# You may need to adjust the scaling differently so the UI/Text isn't too small / big
scale=${4:-1}
# Get the name of the active display
display_output=$(xrandr | grep " connected" | awk '{print $1 }')
# Get the modeline info from the 2nd row in the cvt output
modeline=$(cvt ${width} ${height} ${refresh_rate} | awk 'FNR == 2')
xrandr_mode_str=${modeline//Modeline \"*\" /}
mode_alias="${width}x${height}"
echo "xrandr setting new mode ${mode_alias} ${xrandr_mode_str}"
xrandr --newmode ${mode_alias} ${xrandr_mode_str}
xrandr --addmode ${display_output} ${mode_alias}
# Reset Scaling
xrandr --output ${display_output} --scale ${scale}
# Apply new xrandr mode
xrandr --output ${display_output} --primary --mode ${mode_alias} --pos 0x0 --rotate normal --scale ${scale}
# Optionally reset your wallpaper
# xwallpaper --zoom /path/to/wallpaper.png

View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
###
# File: start-dumb-udev.sh
# Project: bin
# File Created: Tuesday, 12th January 2022 8:46:47 am
# Author: Josh.5 (jsunnex@gmail.com)
# -----
# Last Modified: Friday, 14th January 2022 9:21:00 am
# Modified By: Josh.5 (jsunnex@gmail.com)
###
set -e
# CATCH TERM SIGNAL:
_term() {
kill -TERM "$dumb_udev_pid" 2>/dev/null
}
trap _term SIGTERM SIGINT
# EXECUTE PROCESS:
# Start dumb-udev
dumb-udev &
dumb_udev_pid=$!
# WAIT FOR CHILD PROCESS:
wait "$dumb_udev_pid"

View File

@@ -19,7 +19,6 @@ trap _term SIGTERM SIGINT
# EXECUTE PROCESS:
echo "PULSEAUDIO: Starting pulseaudio service"
sleep 5
#/usr/bin/pulseaudio --disallow-module-loading --disallow-exit --exit-idle-time=-1 &
/usr/bin/pulseaudio --exit-idle-time=-1 &
pulseaudio_pid=$!

View File

@@ -5,8 +5,8 @@
# File Created: Tuesday, 4th October 2022 8:22:17 pm
# Author: Josh.5 (jsunnex@gmail.com)
# -----
# Last Modified: Tuesday, 4th October 2022 8:22:17 pm
# Modified By: Josh.5 (jsunnex@gmail.com)
# Last Modified: Wednesday, 27th November 2024 3:54:19 pm
# Modified By: Josh5 (jsunnex@gmail.com)
###
set -e
source /usr/bin/common-functions.sh
@@ -19,15 +19,15 @@ _term() {
while kill -0 "$sunshine_pid"; do
kill -TERM "$sunshine_pid" 2>/dev/null
counter=$((counter + 1))
[ "$counter" -gt 2 ] && break
sleep 2
[ "$counter" -gt 8 ] && break
sleep 0.5
done
counter=0
while kill -0 "$sunshine_pid"; do
kill -KILL "$sunshine_pid" 2>/dev/null
counter=$((counter + 1))
[ "$counter" -gt 2 ] && break
sleep 1
[ "$counter" -gt 4 ] && break
sleep 0.5
done
}
trap _term SIGTERM SIGINT
@@ -49,6 +49,10 @@ fi
if ([ "X${SUNSHINE_USER:-}" != "X" ] && [ "X${SUNSHINE_PASS:-}" != "X" ]); then
/usr/bin/sunshine "${USER_HOME:?}/.config/sunshine/sunshine.conf" --creds "${SUNSHINE_USER:?}" "${SUNSHINE_PASS:?}"
fi
# If we are running the SHUI, then force the same user upon sunshine
if ([ "X${WEBUI_USER:-}" != "X" ] && [ "X${WEBUI_PASS:-}" != "X" ]); then
/usr/bin/sunshine "${USER_HOME:?}/.config/sunshine/sunshine.conf" --creds "${WEBUI_USER:?}" "${WEBUI_PASS:?}"
fi
# Remove any auto-start scripts from user's .local dir
if [ -f "${USER_HOME:?}/.config/autostart/Sunshine.desktop" ]; then
rm -fv "${USER_HOME:?}/.config/autostart/Sunshine.desktop"

View File

@@ -16,12 +16,6 @@ _term() {
}
trap _term SIGTERM SIGINT
# CONFIGURE:
# Remove lockfile
rm -f /tmp/.started-udev
# EXECUTE PROCESS:
# Start udev
if command -v udevd &>/dev/null; then
@@ -32,11 +26,8 @@ fi
# Monitor kernel uevents
udevadm monitor &
monitor_pid=$!
# Touch lockfile
sleep 1
touch /tmp/.started-udev
# Wait for 10 seconds, then request device events from the kernel
sleep 10
# Wait for 5 seconds, then request device events from the kernel
sleep 5
udevadm trigger
# WAIT FOR CHILD PROCESS:

View File

@@ -5,8 +5,8 @@
# File Created: Tuesday, 23rd August 2023 3:28:52 pm
# Author: Josh.5 (jsunnex@gmail.com)
# -----
# Last Modified: Friday, 23rd August 2023 4:21:00 pm
# Modified By: Josh.5 (jsunnex@gmail.com)
# Last Modified: Saturday, 20th July 2024 7:07:00 pm
# Modified By: Josh5 (jsunnex@gmail.com)
###
set -e
@@ -71,71 +71,76 @@ if ([ "X${SUNSHINE_CLIENT_WIDTH:-}" != "X" ] && [ "X${SUNSHINE_CLIENT_HEIGHT:-}"
__current_refresh_rate=$(echo ${__current_current_mode:?} | awk '{sub(/\*/, "", $2); print $2}')
# Get the primary output device
__primary_output="$(echo "${__xrandr_out:?}" | grep primary | awk '{print $1}')"
# Get the modeline from cvt and extract the second line (which contains the modeline)
__client_modeline=$(cvt "${SUNSHINE_CLIENT_WIDTH:?}" "${SUNSHINE_CLIENT_HEIGHT:?}" "${SUNSHINE_CLIENT_FPS:?}" | grep Modeline | sed -e 's/Modeline //')
# Create a new mode for this. This allows us to force a set refresh rate that may not be supported by the display
__client_mode=$(echo "${__client_modeline:?}" | awk -F '"' '{print $2}')
# Check if this custom mode is already created
if ! echo "${__xrandr_out:?}" | grep -q "${__client_mode:?}"; then
# Custom mode does not yet exist. Create it
echo " - Adding new mode '${__client_mode:?}' with new modeline '${__client_modeline:?}'"
xrandr --newmode "${__client_mode:?}" ${__client_modeline##*\"}
if [ $? -gt 0 ]; then
echo " - WARNING: Failed to add new mode '${__client_mode:?}'."
else
echo " - SUCCESS"
fi
else
echo " - Custom mode '${__client_mode:?}' already exists."
__primary_output="$(echo "${__xrandr_out:?}" | grep primary | head -n1 | awk '{print $1}')"
if [ "X${__primary_output:-}" = "X" ]; then
__primary_output="$(echo "${__xrandr_out:?}" | grep -E "\sconnected" | head -n1 | awk '{print $1}')"
fi
# Check if custom mode exists
__xrandr_out="$(xrandr -q)"
if echo "${__xrandr_out:?}" | grep -q "${__client_mode:?}"; then
# Check if this mode is already added to the primary display
if ! echo "${__xrandr_out:?}" | sed -n "/${__primary_output:?}/,/^[^[:space:]]/ {/^[[:space:]]/p}" | grep -q "${__client_mode:?}"; then
# Custom mode exists, but is not yet added to the primary output device. Add it
echo " - Adding custom mode '${__client_mode:?}' to device '${__primary_output:?}'"
xrandr --addmode "${__primary_output:?}" "${__client_mode:?}"
__mode_added=$?
if [ "${__mode_added:-0}" -gt 0 ]; then
echo " - WARNING: Failed to assign custom mode to primary output device '${__primary_output:?}'."
if [ "X${__primary_output:-}" != "X" ]; then
# Get the modeline from cvt and extract the second line (which contains the modeline)
__client_modeline=$(cvt "${SUNSHINE_CLIENT_WIDTH:?}" "${SUNSHINE_CLIENT_HEIGHT:?}" "${SUNSHINE_CLIENT_FPS:?}" | grep Modeline | sed -e 's/Modeline //')
# Create a new mode for this. This allows us to force a set refresh rate that may not be supported by the display
__client_mode=$(echo "${__client_modeline:?}" | awk -F '"' '{print $2}')
# Check if this custom mode is already created
if ! echo "${__xrandr_out:?}" | grep -q "${__client_mode:?}"; then
# Custom mode does not yet exist. Create it
echo " - Adding new mode '${__client_mode:?}' with new modeline '${__client_modeline:?}'"
xrandr --newmode "${__client_mode:?}" ${__client_modeline##*\"}
if [ $? -gt 0 ]; then
echo " - WARNING: Failed to add new mode '${__client_mode:?}'."
else
echo " - SUCCESS"
fi
else
echo " - Custom mode '${__client_mode:?}' is already configured for the primary output device."
__mode_added=0
echo " - Custom mode '${__client_mode:?}' already exists."
fi
else
echo " - WARNING: Custom mode '${__client_mode:?}' does not exist."
fi
# Set the current resoultion to the new mode
if ([ "X${__mode_added:-}" = "X" ] || [ "${__mode_added:-0}" -gt 0 ]); then
echo " - Attempting to set the display mode to a supported '${SUNSHINE_CLIENT_WIDTH:?}x${SUNSHINE_CLIENT_HEIGHT:?}' mode. Note that this may not support the configured refresh rate."
xrandr --output "${__primary_output:?}" --mode ${SUNSHINE_CLIENT_WIDTH:?}x${SUNSHINE_CLIENT_HEIGHT:?} --refresh ${SUNSHINE_CLIENT_FPS:?}
if [ $? -gt 0 ]; then
echo " - WARNING: Failed to set current output to mode '${SUNSHINE_CLIENT_WIDTH:?}x${SUNSHINE_CLIENT_HEIGHT:?}' on device '${__primary_output:?}'."
# Check if custom mode exists
__xrandr_out="$(xrandr -q)"
if echo "${__xrandr_out:?}" | grep -q "${__client_mode:?}"; then
# Check if this mode is already added to the primary display
if ! echo "${__xrandr_out:?}" | sed -n "/${__primary_output:?}/,/^[^[:space:]]/ {/^[[:space:]]/p}" | grep -q "${__client_mode:?}"; then
# Custom mode exists, but is not yet added to the primary output device. Add it
echo " - Adding custom mode '${__client_mode:?}' to device '${__primary_output:?}'"
xrandr --addmode "${__primary_output:?}" "${__client_mode:?}"
__mode_added=$?
if [ "${__mode_added:-0}" -gt 0 ]; then
echo " - WARNING: Failed to assign custom mode to primary output device '${__primary_output:?}'."
else
echo " - SUCCESS"
fi
else
echo " - Custom mode '${__client_mode:?}' is already configured for the primary output device."
__mode_added=0
fi
else
echo " - SUCCESS"
echo " - WARNING: Custom mode '${__client_mode:?}' does not exist."
fi
else
echo " - Setting the display mode to '${__client_mode:?}'"
xrandr --output "${__primary_output:?}" --mode "${__client_mode:?}" --rate "${SUNSHINE_CLIENT_FPS:?}"
if [ $? -gt 0 ]; then
echo " - WARNING: Failed to set current output to custom mode '${__client_mode:?}' on device '${__primary_output:?}'."
else
echo " - SUCCESS"
fi
fi
# Save original display settings to config file. This will be read and used to restore the original display settings when the client disconnects.
echo "primary_output='${__primary_output:?}'" >> /tmp/sunshine-exec-run.conf
echo "display_mode='${__current_resolution:?}'" >> /tmp/sunshine-exec-run.conf
echo "display_rate='${__current_refresh_rate:?}'" >> /tmp/sunshine-exec-run.conf
# Set the current resoultion to the new mode
if ([ "X${__mode_added:-}" = "X" ] || [ "${__mode_added:-0}" -gt 0 ]); then
echo " - Attempting to set the display mode to a supported '${SUNSHINE_CLIENT_WIDTH:?}x${SUNSHINE_CLIENT_HEIGHT:?}' mode. Note that this may not support the configured refresh rate."
xrandr --output "${__primary_output:?}" --mode ${SUNSHINE_CLIENT_WIDTH:?}x${SUNSHINE_CLIENT_HEIGHT:?} --refresh ${SUNSHINE_CLIENT_FPS:?}
if [ $? -gt 0 ]; then
echo " - WARNING: Failed to set current output to mode '${SUNSHINE_CLIENT_WIDTH:?}x${SUNSHINE_CLIENT_HEIGHT:?}' on device '${__primary_output:?}'."
else
echo " - SUCCESS"
fi
else
echo " - Setting the display mode to '${__client_mode:?}'"
xrandr --output "${__primary_output:?}" --mode "${__client_mode:?}" --rate "${SUNSHINE_CLIENT_FPS:?}"
if [ $? -gt 0 ]; then
echo " - WARNING: Failed to set current output to custom mode '${__client_mode:?}' on device '${__primary_output:?}'."
else
echo " - SUCCESS"
fi
fi
# Save original display settings to config file. This will be read and used to restore the original display settings when the client disconnects.
echo "primary_output='${__primary_output:?}'" >> /tmp/sunshine-exec-run.conf
echo "display_mode='${__current_resolution:?}'" >> /tmp/sunshine-exec-run.conf
echo "display_rate='${__current_refresh_rate:?}'" >> /tmp/sunshine-exec-run.conf
fi
)
fi