* Update permissions on workflow templates

* Remove armhf from arch table

* keep sanitized and raw external versions separate in external trigger

* Clarify logs

* Remove fleet

* Retrieve syft image tag from jenkins env vars, default to latest

* use CI_SYFT_IMAGE_TAG for the ci test, with fall back to SYFT_IMAGE_TAG

* add selkies blurb for readmes (#341)

* add selkies blurb for readmes

* typo

* append more options to selkies blurb

* add working path for watermark

* general blurb cleanup emphasize https and nvidia encoding support

* Add selkies note to requires

---------

Co-authored-by: thespad <spad@linuxserver.io>
Co-authored-by: quietsy <github@qtsy.cc>
Co-authored-by: j0nnymoe <j0nnymoe@users.noreply.github.com>
Co-authored-by: Ryan Kuba <ryankuba@gmail.com>
Co-authored-by: Roxedus <me@roxedus.dev>
This commit is contained in:
aptalca 2025-07-02 15:22:38 -04:00 committed by GitHub
parent 1c0338ab6c
commit 0dfd197c4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 169 additions and 18 deletions

View File

@ -1,6 +1,5 @@
[![Blog]({{ lsio_shieldsio_static_blog }})]({{ lsio_blog_url }} "{{ lsio_blog_desc }}")
[![Discord]({{ lsio_shieldsio_discord }})]({{ lsio_discord_url }} "{{ lsio_discord_desc }}")
[![Discourse]({{ lsio_shieldsio_discourse_topics }})]({{ lsio_discourse_url }} "{{ lsio_discourse_desc }}")
[![Fleet]({{ lsio_shieldsio_static_fleet }})]({{ lsio_fleet_url }} "{{ lsio_fleet_desc }}")
[![GitHub]({{ lsio_shieldsio_static_github }})]({{ lsio_github_url }} "{{ lsio_github_desc }}")
[![Open Collective]({{ lsio_shieldsio_opencollective_all }})]({{ lsio_opencollective_url }} "{{ lsio_opencollective_desc }}")

View File

@ -15,6 +15,5 @@ Find us at:
* [Blog]({{ lsio_blog_url }}) - {{ lsio_blog_desc }}
* [Discord]({{ lsio_discord_url }}) - {{ lsio_discord_desc }}
* [Discourse]({{ lsio_discourse_url }}) - {{ lsio_discourse_desc }}
* [Fleet]({{ lsio_fleet_url }}) - {{ lsio_fleet_desc }}
* [GitHub]({{ lsio_github_url }}) - {{ lsio_github_desc }}
* [Open Collective]({{ lsio_opencollective_url }}) - {{ lsio_opencollective_desc }}

View File

@ -0,0 +1,117 @@
**Modern GUI desktop apps may have compatibility issues with the latest Docker syscall restrictions. You can use Docker with the `--security-opt seccomp=unconfined` setting to allow these syscalls on hosts with older Kernels or libseccomp versions.**
### Security
{{ "This container provides privileged access to the host system. Do not expose it to the Internet unless you have secured it properly." | admonition(flavour=markdown, severity="warning") }}
**HTTPS is required for full functionality.** Modern browser features such as WebCodecs, used for video and audio, will not function over an insecure HTTP connection.
By default, this container has no authentication. The optional `CUSTOM_USER` and `PASSWORD` environment variables enable basic HTTP auth, which is suitable only for securing the container on a trusted local network. For internet exposure, we strongly recommend placing the container behind a reverse proxy, such as [SWAG](https://github.com/linuxserver/docker-swag), with a robust authentication mechanism.
The web interface includes a terminal with passwordless `sudo` access. Any user with access to the GUI can gain root control within the container, install arbitrary software, and probe your local network.
### Options in all Selkies-based GUI containers
This container is based on [Docker Baseimage Selkies](https://github.com/linuxserver/docker-baseimage-selkies), which provides the following environment variables and run configurations to customize its functionality.
#### Optional Environment Variables
| Variable | Description |
| :----: | --- |
| `CUSTOM_PORT` | Internal HTTP port. Defaults to `{% if external_http_port is defined %}{{ external_http_port }}{% else %}3000{% endif %}`. |
| `CUSTOM_HTTPS_PORT` | Internal HTTPS port. Defaults to `{% if external_https_port is defined %}{{ external_https_port }}{% else %}3001{% endif %}`. |
| `CUSTOM_USER` | Username for HTTP Basic Auth. Defaults to `abc`. |
| `PASSWORD` | Password for HTTP Basic Auth. If unset, authentication is disabled. |
| `SUBFOLDER` | Application subfolder for reverse proxy configurations. Must include leading and trailing slashes, e.g., `/subfolder/`. |
| `TITLE` | Page title displayed in the web browser. Defaults to "Selkies". |
| `START_DOCKER` | If set to `false`, the privileged Docker-in-Docker setup will not start automatically. |
| `DISABLE_IPV6` | Set to `true` to disable IPv6 support in the container. |
| `LC_ALL` | Sets the container's locale, e.g., `fr_FR.UTF-8`. |
| `NO_DECOR` | If set, applications will run without window borders, suitable for PWA usage. |
| `NO_FULL` | If set, applications will not be automatically fullscreened. |
| `DISABLE_ZINK` | If set, Zink-related environment variables will not be configured when a video card is detected. |
| `WATERMARK_PNG` | Full path to a watermark PNG file inside the container, e.g., `/usr/share/selkies/www/icon.png`. |
| `WATERMARK_LOCATION` | Integer specifying the watermark location: `1` (Top Left), `2` (Top Right), `3` (Bottom Left), `4` (Bottom Right), `5` (Centered), `6` (Animated). |
#### Optional Run Configurations
| Argument | Description |
| :----: | --- |
| `--privileged` | Starts a Docker-in-Docker (DinD) environment. For better performance, mount the Docker data directory from the host, e.g., `-v /path/to/docker-data:/var/lib/docker`. |
| `-v /var/run/docker.sock:/var/run/docker.sock` | Mounts the host's Docker socket to manage host containers from within this container. |
### Language Support - Internationalization
To launch the desktop session in a different language, set the `LC_ALL` environment variable. For example:
* `-e LC_ALL=zh_CN.UTF-8` - Chinese
* `-e LC_ALL=ja_JP.UTF-8` - Japanese
* `-e LC_ALL=ko_KR.UTF-8` - Korean
* `-e LC_ALL=ar_AE.UTF-8` - Arabic
* `-e LC_ALL=ru_RU.UTF-8` - Russian
* `-e LC_ALL=es_MX.UTF-8` - Spanish (Latin America)
* `-e LC_ALL=de_DE.UTF-8` - German
* `-e LC_ALL=fr_FR.UTF-8` - French
* `-e LC_ALL=nl_NL.UTF-8` - Netherlands
* `-e LC_ALL=it_IT.UTF-8` - Italian
{% if show_nvidia is defined %}### Nvidia GPU Support
**Note: Nvidia support is not available for Alpine-based images.**
Nvidia GPU support is available by leveraging Zink for OpenGL. When a compatible Nvidia GPU is passed through, it will also be **automatically utilized for hardware-accelerated video stream encoding** (using the `x264enc` full-frame profile), significantly reducing CPU load.
Enable Nvidia support with the following runtime flags:
| Flag | Description |
| :----: | --- |
| `--gpus all` | Passes all available host GPUs to the container. This can be filtered to specific GPUs. |
| `--runtime nvidia` | Specifies the Nvidia runtime, which provides the necessary drivers and tools from the host. |
For Docker Compose, you must first configure the Nvidia runtime as the default on the host:
```
sudo nvidia-ctk runtime configure --runtime=docker --set-as-default
sudo systemctl restart docker
```
Then, assign the GPU to the service in your `compose.yaml`:
```
services:
{{ project_name }}:
image: lscr.io/{{ lsio_project_name_short }}/{{ project_name }}:{{ release_tag }}
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [compute,video,graphics,utility]
```
{% endif %}### Application Management
There are two methods for installing applications inside the container: PRoot Apps (recommended for persistence) and Native Apps.
#### PRoot Apps (Persistent)
Natively installed packages (e.g., via `apt-get install`) will not persist if the container is recreated. To retain applications and their settings across container updates, we recommend using [proot-apps](https://github.com/linuxserver/proot-apps). These are portable applications installed to the user's persistent `$HOME` directory.
To install an application, use the command line inside the container:
```
proot-apps install filezilla
```
A list of supported applications is available [here](https://github.com/linuxserver/proot-apps?tab=readme-ov-file#supported-apps).
#### Native Apps (Non-Persistent)
You can install packages from the system's native repository using the [universal-package-install](https://github.com/linuxserver/docker-mods/tree/universal-package-install) mod. This method will increase the container's start time and is not persistent. Add the following to your `compose.yaml`:
```yaml
environment:
- DOCKER_MODS=linuxserver/mods:universal-package-install
- INSTALL_PACKAGES=libfuse2|git|gdb
```

View File

@ -13,4 +13,3 @@ The architectures supported by this image are:
| riscv64 | {{ '✅ | riscv64-\<version tag\>' }} |
{% endif %}
| arm64 | {{ '✅ | arm64v8-\<version tag\>' if 'arm64' in (available_architectures | map(attribute="arch") ) else '❌ |' }} |
| armhf | {{ '✅ | arm32v7-\<version tag\>' if 'armhf' in (available_architectures | map(attribute="arch") ) else '❌ |' }} |

View File

@ -64,6 +64,10 @@ description: "{{ noter(project_blurb) | trim }}"
{% if kasm_blurb is defined %}
{% include "README_SNIPPETS/KASM.j2" | trim %}
{% endif %}
{% if selkies_blurb is defined %}
{% include "README_SNIPPETS/SELKIES.j2" | trim %}
{% endif %}
{% if readonly_supported is defined and readonly_supported %}
{% include "README_SNIPPETS/READONLY.j2" | trim %}

View File

@ -55,6 +55,10 @@
{% if kasm_blurb is defined %}
{% include "README_SNIPPETS/KASM.j2" | trim %}
{% endif %}
{% if selkies_blurb is defined %}
{% include "README_SNIPPETS/SELKIES.j2" | trim %}
{% endif %}
{% if readonly_supported is defined and readonly_supported %}
{% include "README_SNIPPETS/READONLY.j2" | trim %}

View File

@ -91,13 +91,19 @@
{# Set the WebUI link based on the link the CI runs against #}
<TemplateURL>{{ "false" if unraid_template_sync is sameas false else "https://raw.githubusercontent.com/linuxserver/templates/main/unraid/" + project_name | lower + ".xml" }}</TemplateURL>
<Icon>https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver-ls-logo.png</Icon>
{% if (unraid_requirement is defined and unraid_requirement != "") or (external_application_snippet_enabled) %}
{% if (unraid_requirement is defined and unraid_requirement != "") or (external_application_snippet_enabled) or (selkies_blurb is defined) %}
<Requires>
{{ unraid_requirement }}
{% if external_application_snippet_enabled %}
{% if unraid_requirement is defined %}
{{ unraid_requirement | indent(4) | trim }}
{% endif %}
{% if external_application_snippet_enabled %}
This container requires an external application to be run separately.
{{ external_application_unraid_block }}
{% endif %}
{{ external_application_unraid_block | indent(4) | trim }}
{% endif %}
{% if selkies_blurb is defined %}
This image is unprotected by default __**do not**__ expose it to the internet.
Please read {{ project_github_repo_url }}#security for more information.
{% endif %}
</Requires>
{% endif %}
{# Create changelog #}

View File

@ -8,6 +8,9 @@ on:
pull_request_review:
types: [submitted,edited,dismissed]
permissions:
contents: read
jobs:
manage-project:
permissions:

View File

@ -4,6 +4,9 @@ on:
- cron: '{{ 60 | random(seed=('docker-' + project_name + '-minute')) }} {{ 24 | random(seed=('docker-' + project_name + '-hour')) }} * * *'
workflow_dispatch:
permissions:
contents: read
jobs:
stale:
permissions:

View File

@ -10,6 +10,9 @@ name: External Trigger Main
on:
workflow_dispatch:
permissions:
contents: read
jobs:
external-trigger-{{ ls_branch|regex_replace('[^a-zA-Z0-9-]','-') }}:
runs-on: ubuntu-latest
@ -107,8 +110,8 @@ jobs:
"username": "Github Actions"}' ${{ '{{' }} secrets.DISCORD_WEBHOOK {{ '}}' }}
exit 1
fi
EXT_RELEASE=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g')
echo "External version: \`${EXT_RELEASE}\`" >> $GITHUB_STEP_SUMMARY
EXT_RELEASE_SANITIZED=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g')
echo "Sanitized external version: \`${EXT_RELEASE_SANITIZED}\`" >> $GITHUB_STEP_SUMMARY
echo "Retrieving last pushed version" >> $GITHUB_STEP_SUMMARY
image="{{ better_vars.LS_USER }}/{{ project_name }}"
tag="{{ release_tag }}"
@ -164,8 +167,8 @@ jobs:
exit 1
fi
echo "Last pushed version: \`${IMAGE_VERSION}\`" >> $GITHUB_STEP_SUMMARY
if [ "${EXT_RELEASE}" == "${IMAGE_VERSION}" ]; then
echo "Version \`${EXT_RELEASE}\` already pushed, exiting" >> $GITHUB_STEP_SUMMARY
if [ "${EXT_RELEASE_SANITIZED}" == "${IMAGE_VERSION}" ]; then
echo "Sanitized version \`${EXT_RELEASE_SANITIZED}\` already pushed, exiting" >> $GITHUB_STEP_SUMMARY
exit 0
{% if external_type == "alpine_repo" and better_vars.MULTIARCH == 'true' %}
elif [[ $(curl -sL "{{ better_vars.DIST_REPO }}aarch64/APKINDEX.tar.gz" | tar -xz -C /tmp && awk '/^P:'"{{ better_vars.DIST_REPO_PACKAGES }}"'$/,/V:/' /tmp/APKINDEX | sed -n 2p | sed 's/^V://') != "${EXT_RELEASE}" ]]{% if build_armhf %} || [[ $(curl -sL "{{ better_vars.DIST_REPO }}armv7/APKINDEX.tar.gz" | tar -xz -C /tmp && awk '/^P:'"{{ better_vars.DIST_REPO_PACKAGES }}"'$/,/V:/' /tmp/APKINDEX | sed -n 2p | sed 's/^V://') != "${EXT_RELEASE}" ]]{% endif %}; then
@ -197,7 +200,7 @@ jobs:
"username": "Github Actions"}' ${{ '{{' }} secrets.DISCORD_WEBHOOK {{ '}}' }}
else
printf "\n## Trigger new build\n\n" >> $GITHUB_STEP_SUMMARY
echo "New version \`${EXT_RELEASE}\` found; old version was \`${IMAGE_VERSION}\`. Triggering new build" >> $GITHUB_STEP_SUMMARY
echo "New sanitized version \`${EXT_RELEASE_SANITIZED}\` found; old version was \`${IMAGE_VERSION}\`. Triggering new build" >> $GITHUB_STEP_SUMMARY
if [[ "${artifacts_found}" == "true" ]]; then
echo "All artifacts seem to be uploaded." >> $GITHUB_STEP_SUMMARY
fi
@ -217,7 +220,7 @@ jobs:
--data-urlencode "description=GHA external trigger https://github.com/${{ '{{' }} github.repository {{ '}}' }}/actions/runs/${{ '{{' }} github.run_id {{ '}}' }}" \
--data-urlencode "Submit=Submit"
echo "**** Notifying Discord ****"
TRIGGER_REASON="A version change was detected for {{ project_name }} tag {{ release_tag }}. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE}"
TRIGGER_REASON="A version change was detected for {{ project_name }} tag {{ release_tag }}. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE_SANITIZED}"
curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903,
"description": "**Build Triggered** \n**Reason:** '"${TRIGGER_REASON}"' \n**Build URL:** '"${buildurl}display/redirect"' \n"}],
"username": "Github Actions"}' ${{ '{{' }} secrets.DISCORD_WEBHOOK {{ '}}' }}

View File

@ -5,6 +5,9 @@ on:
- cron: '{{ 60 | random(seed=(project_name + '-external-minute')) }} * * * *'
workflow_dispatch:
permissions:
contents: read
jobs:
external-trigger-scheduler:
runs-on: ubuntu-latest

View File

@ -2,8 +2,14 @@ name: Greetings
on: [pull_request_target, issues]
permissions:
contents: read
jobs:
greeting:
permissions:
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1

View File

@ -5,6 +5,9 @@ on:
- cron: '{{ 60 | random(seed=(project_name + '-minute')) }} {{ 24 | random(seed=(project_name + '-hour')) }} * * {{ 7 | random(seed=(project_name + '-day')) }}'
workflow_dispatch:
permissions:
contents: read
jobs:
package-trigger-scheduler:
runs-on: ubuntu-latest

View File

@ -80,7 +80,11 @@ pipeline {
env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DOCKERHUB_IMAGE + '/tags/'
env.PULL_REQUEST = env.CHANGE_ID
env.TEMPLATED_FILES = 'Jenkinsfile README.md LICENSE .editorconfig ./.github/CONTRIBUTING.md ./.github/FUNDING.yml ./.github/ISSUE_TEMPLATE/config.yml ./.github/ISSUE_TEMPLATE/issue.bug.yml ./.github/ISSUE_TEMPLATE/issue.feature.yml ./.github/PULL_REQUEST_TEMPLATE.md{% if project_deprecation_status != true %} ./.github/workflows/external_trigger_scheduler.yml ./.github/workflows/greetings.yml ./.github/workflows/package_trigger_scheduler.yml ./.github/workflows/call_issue_pr_tracker.yml ./.github/workflows/call_issues_cron.yml ./.github/workflows/permissions.yml{% if custom_external_trigger != true %} ./.github/workflows/external_trigger.yml{% endif %}{% endif %}{% if sponsor_links is defined %} ./root/donate.txt{% endif %}{% if project_deprecation_status %} ./root/etc/s6-overlay/s6-rc.d/init-deprecate/run ./root/etc/s6-overlay/s6-rc.d/init-deprecate/up ./root/etc/s6-overlay/s6-rc.d/init-deprecate/type ./root/etc/s6-overlay/s6-rc.d/init-deprecate/dependencies.d/init-config-end ./root/etc/s6-overlay/s6-rc.d/init-services/dependencies.d/init-deprecate ./root/etc/s6-overlay/s6-rc.d/user/contents.d/init-deprecate{% endif %}'
if ( env.SYFT_IMAGE_TAG == null ) {
env.SYFT_IMAGE_TAG = 'latest'
}
}
echo "Using syft image tag ${SYFT_IMAGE_TAG}"
sh '''#! /bin/bash
echo "The default github branch detected as ${GH_DEFAULT_BRANCH}" '''
script{
@ -1082,7 +1086,7 @@ pipeline {
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v ${TEMPDIR}:/tmp \
ghcr.io/anchore/syft:v1.26.1 \
ghcr.io/anchore/syft:${SYFT_IMAGE_TAG} \
${LOCAL_CONTAINER} -o table=/tmp/package_versions.txt
NEW_PACKAGE_TAG=$(md5sum ${TEMPDIR}/package_versions.txt | cut -c1-8 )
echo "Package tag sha from current packages in buit container is ${NEW_PACKAGE_TAG} comparing to old ${PACKAGE_TAG} from github"
@ -1210,6 +1214,7 @@ pipeline {
-e WEB_AUTH=\"${CI_AUTH}\" \
-e WEB_PATH=\"${CI_WEBPATH}\" \
-e NODE_NAME=\"${NODE_NAME}\" \
-e SYFT_IMAGE_TAG=\"${CI_SYFT_IMAGE_TAG:${SYFT_IMAGE_TAG}}\" \
-t ghcr.io/linuxserver/ci:latest \
python3 test_build.py'''
}

View File

@ -14,7 +14,6 @@ lsio_discord_url: "https://linuxserver.io/discord"
lsio_discourse_url: "https://discourse.{{ lsio_short_url }}"
lsio_docker_hub_url: "https://hub.docker.com/r/{{ lsio_project_name_short }}"
lsio_docs_url: "https://docs.{{ lsio_short_url }}"
lsio_fleet_url: "https://fleet.{{ lsio_short_url }}"
lsio_github_url: "https://github.com/{{ lsio_project_name_short }}"
lsio_gitlab_url: "https://gitlab.com/{{ lsio_project_name }}"
lsio_mods_url: "https://mods.{{ lsio_short_url }}/?mod={{ project_name }}"
@ -38,7 +37,6 @@ arch_armhf: "armhf"
lsio_blog_desc: "all the things you can do with our containers including How-To guides, opinions and much more!"
lsio_discord_desc: "realtime support / chat with the community and the team."
lsio_discourse_desc: "post on our community forum."
lsio_fleet_desc: "an online web interface which displays all of our maintained images."
lsio_github_desc: "view the source for all of our repositories."
lsio_mods_desc: "view available mods for this container."
lsio_universal_mods_desc: "view available universal mods."
@ -72,7 +70,6 @@ lsio_shieldsio_jenkins_build: "https://img.shields.io/jenkins/build?{{ lsio_badg
lsio_shieldsio_microbadger_layers: "https://img.shields.io/microbadger/layers/{{ lsio_project_name_short }}/{{ project_name }}.svg?{{ lsio_badge_url_parameters }}"
lsio_shieldsio_opencollective_all: "https://img.shields.io/opencollective/all/{{ lsio_project_name_short }}.svg?{{ lsio_badge_url_parameters }}&label=Supporters&logo=open%20collective"
lsio_shieldsio_static_blog: "https://img.shields.io/static/v1.svg?{{ lsio_badge_url_parameters }}&label={{ lsio_project_name }}&message=Blog"
lsio_shieldsio_static_fleet: "https://img.shields.io/static/v1.svg?{{ lsio_badge_url_parameters }}&label={{ lsio_project_name }}&message=Fleet"
lsio_shieldsio_static_github_package: "https://img.shields.io/static/v1.svg?{{ lsio_badge_url_parameters }}&label={{ lsio_project_name }}&message=GitHub%20Package&logo=github"
lsio_shieldsio_static_github: "https://img.shields.io/static/v1.svg?{{ lsio_badge_url_parameters }}&label={{ lsio_project_name }}&message=GitHub&logo=github"
lsio_shieldsio_static_gitlab_registry: "https://img.shields.io/static/v1.svg?{{ lsio_badge_url_parameters }}&label={{ lsio_project_name }}&message=GitLab%20Registry&logo=gitlab"