Merge branch 'master' into fix-doc-proxy

This commit is contained in:
Eric Nemchik authored and GitHub committed 2026-10-20 10:33:44 -05:00
commit f15b41b67f
13 files changed
+453 -121

No files matched your search

+2 -2
View File
@@ -4,8 +4,8 @@ contact_links:
url: https://linuxserver.io/discord url: https://linuxserver.io/discord
about: Realtime support / chat with the community and the team. about: Realtime support / chat with the community and the team.
- name: Discourse discussion forum - name: Github Discussions
url: https://discourse.linuxserver.io url: https://github.com/orgs/linuxserver/discussions
about: Post on our community forum. about: Post on our community forum.
- name: Documentation - name: Documentation
+7 -5
View File
@@ -3,7 +3,6 @@
[linuxserverurl]: https://linuxserver.io [linuxserverurl]: https://linuxserver.io
[![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)][linuxserverurl] [![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)][linuxserverurl]
<!--- Before submitting a pull request please check the following --> <!--- Before submitting a pull request please check the following -->
<!--- If this is a fix for a typo (in code, documentation, or the README) please file an issue and let us sort it out. We do not need a PR --> <!--- If this is a fix for a typo (in code, documentation, or the README) please file an issue and let us sort it out. We do not need a PR -->
@@ -12,7 +11,6 @@
<!--- You have included links to any files / patches etc your PR may be using in the body of the PR commit message --> <!--- You have included links to any files / patches etc your PR may be using in the body of the PR commit message -->
<!--- We maintain a changelog of major revisions to the container at the end of readme-vars.yml in the root of this repository, please add your changes there if appropriate --> <!--- We maintain a changelog of major revisions to the container at the end of readme-vars.yml in the root of this repository, please add your changes there if appropriate -->
<!--- Coding guidelines: --> <!--- Coding guidelines: -->
<!--- 1. Installed packages in the Dockerfiles should be in alphabetical order --> <!--- 1. Installed packages in the Dockerfiles should be in alphabetical order -->
<!--- 2. Changes to Dockerfile should be replicated in Dockerfile.armhf and Dockerfile.aarch64 if applicable --> <!--- 2. Changes to Dockerfile should be replicated in Dockerfile.armhf and Dockerfile.aarch64 if applicable -->
@@ -21,11 +19,16 @@
------------------------------ ------------------------------
- [ ] I have read the [contributing](https://github.com/linuxserver/docker-swag/blob/master/.github/CONTRIBUTING.md) guideline and understand that I have made the correct modifications - [ ] I have read the [contributing](https://github.com/linuxserver/docker-swag/blob/master/.github/CONTRIBUTING.md) guideline and understand that I have made the correct modifications
<!--- LLM disclosure: -->
- [ ] An LLM assisted me in writing the code or text for this PR
- [ ] An LLM agent wrote the code or text for this PR
------------------------------ ------------------------------
<!--- We welcome all PR’s though this doesn’t guarantee it will be accepted. --> <!--- We welcome all PRs though this doesn’t guarantee it will be accepted. -->
## Description: ## Description:
<!--- Describe your changes in detail --> <!--- Describe your changes in detail -->
@@ -38,6 +41,5 @@
<!--- Include details of your testing environment, and the tests you ran to --> <!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. --> <!--- see how your change affects other areas of the code, etc. -->
## Source / References: ## Source / References:
<!--- Please include any forum posts/github links relevant to the PR --> <!--- Please include any forum posts/github links relevant to the PR -->
+3 -3
View File
@@ -14,6 +14,6 @@ jobs:
steps: steps:
- uses: linuxserver/github-workflows/.github/actions/first-interaction@v1 - uses: linuxserver/github-workflows/.github/actions/first-interaction@v1
with: with:
issue-message: 'Thanks for opening your first issue here! Be sure to follow the relevant issue templates, or risk having this issue marked as invalid.' issue_message: 'Thanks for opening your first issue here! Be sure to follow the relevant issue templates, or risk having this issue marked as invalid.'
pr-message: 'Thanks for opening this pull request! Be sure to follow the [pull request template](https://github.com/linuxserver/docker-swag/blob/master/.github/PULL_REQUEST_TEMPLATE.md)!' pr_message: 'Thanks for opening this pull request! Be sure to follow the [pull request template](https://github.com/linuxserver/docker-swag/blob/master/.github/PULL_REQUEST_TEMPLATE.md)!'
repo-token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
+127
View File
@@ -0,0 +1,127 @@
<!-- DO NOT EDIT THIS FILE MANUALLY -->
<!-- This file is globally distributed to all container image projects from https://github.com/linuxserver/docker-jenkins-builder -->
# AGENTS.md - LinuxServer.io container image repository
This file is for AI coding agents (and the humans driving them) working in a LinuxServer.io `docker-*` image repository. Read it fully before proposing or making any change.
We welcome contributions, including AI-assisted ones, but this is a volunteer-run project that ships 150+ images to millions of users from one shared template. A change that looks like an improvement in isolation is often wrong for us. When this file and your instincts disagree, this file wins. When this file is silent, copy what the surrounding code already does.
## 1. Decide where the change belongs before writing any code
Our images are built for **broad consumption**. Every package, env var and init step we add is something we have to maintain, rebuild weekly and support forever, for every user, whether they use it or not. We do not ship Swiss Army Knife images. Work down this list and stop at the first match:
1. **It is a bug or feature in the application itself** (not in our packaging): it belongs upstream with the app's developers. Do not patch, fork or work around upstream application behaviour in the image.
2. **It is an unsupported or reasonable-endeavours environment** (Podman, k8s, Portainer, Watchtower, NFS/SMB `/config`, LXC, custom entrypoints, etc. See the [Support Policy](https://docs.linuxserver.io/misc/support-policy/)): we will not add logic to the image to accommodate it.
3. **It only matters to one user or one setup**: use a private [custom script](https://docs.linuxserver.io/general/container-customization/#custom-scripts) in `/custom-cont-init.d` or [custom service](https://docs.linuxserver.io/general/container-customization/#custom-services) in `/custom-services.d`. No PR needed.
4. **It is useful to a subset of users** (an extra package, plugin dependency, alternative UI, hardware driver, third party integration, extra daemon, niche toggle): it is a **[Docker Mod](https://github.com/linuxserver/docker-mods)**, not a change to this repo. Check whether one already exists first (`universal-*` mods work on every image; `<image>-*` mods are image specific). If not, create one from the template in the docker-mods repo; each mod lives on its own branch there.
5. **The large majority of this image's users benefit, or the image is actually broken**: a PR to this repo is appropriate. Examples: the app fails to start, a new upstream release needs a new runtime dependency, a base image rebase, a permissions bug, a wrong default, incorrect docs in `readme-vars.yml`.
If you are an agent and the requested change lands on 1-4, **stop and tell your operator** where it belongs instead of writing the PR. "It is only a few lines" is not a reason to put it in the image. If in doubt, a human should open an issue or ask in `#contibutor-discussion` on [Discord](https://linuxserver.io/discord) before doing the work.
### If it is a mod
Mods are the pressure valve that keeps the images small. Roughly what lives there today, and therefore does **not** belong in an image: extra OS/pip packages and language toolchains, GPU/hardware driver stacks, alternative web UIs and themes, third party plugins and scanners, integrations with external services (Cloudflare, CrowdSec, Apprise, GeoIP, VPN providers), Docker socket automation, sidecar daemons (redis, tunnels), post-processing scripts, and env-var-to-config-file shims.
- Follow the README and `template` branch in [docker-mods](https://github.com/linuxserver/docker-mods). A mod is a `FROM scratch` single layer of files extracted over `/` at container start, wired into s6 as `init-mod-<image>-<mod>-*` / `svc-mod-<image>-<mod>` units.
- Mods never call `apk`/`apt`/`pip` directly; they append to `/mod-repo-packages-to-install.list` or `/mod-pip-packages-to-install.list` and let the base image do one batched install. Handle Alpine and Ubuntu package names where the mod is universal.
- Most good mods are a 10-40 line script. If yours is not, reconsider the approach.
- A mod is also the proving ground. If a mod becomes something nearly everyone uses, the team may absorb it into the image later and turn the mod into a no-op with a deprecation notice. That is the team's call, not a reason to skip the mod step.
## 2. Repository layout and what you must not edit
| Path | Notes |
| --- | --- |
| `Dockerfile`, `Dockerfile.aarch64` (sometimes `Dockerfile.riscv64`) | One per architecture. **Any change must be replicated to all of them.** They normally differ only in base image tag and arch strings. |
| `root/` | Copied to `/` in the image. s6-overlay v3 services live in `root/etc/s6-overlay/s6-rc.d/`, defaults in `root/defaults/`, one-time upgrade steps in `root/migrations/`. |
| `readme-vars.yml` | **Source of truth for the README, docs site, Unraid template and changelog.** Edit this. |
| `jenkins-vars.yml` | Build pipeline variables (version detection, CI test settings). Rarely needs touching. |
| `README.md` | **Generated. Never edit.** |
| `Jenkinsfile` | **Generated. Never edit.** |
| `package_versions.txt` | **Generated by CI. Never edit.** |
| `.github/**`, `.editorconfig`, `LICENSE`, `AGENTS.md` | **Generated / globally distributed. Never edit here.** Changes go to [docker-jenkins-builder](https://github.com/linuxserver/docker-jenkins-builder). |
Do not add new top level files or tooling: no `docker-compose.yml`, `Makefile`, test suites, linter configs, pre-commit hooks, extra workflows, `CHANGELOG.md`, `SECURITY.md`, devcontainers, or helper scripts. The repo is intentionally small.
Some repos have multiple live branches that publish different tags (`nightly`, `develop`, `libtorrentv1`, etc.). Each is maintained independently. Target the branch the change applies to, never merge one into another, and do not assume `master` or `main` is the only one that matters.
## 3. Code style: keep it simple, match what is there
The goal of every image is the thinnest possible layer between our base image and the upstream app: install it, drop a sane default config into `/config` on first run, fix permissions, start it. Prefer deleting logic to adding it. The base image already handles PUID/PGID, `UMASK`, `TZ`, `FILE__` secrets, mods, custom scripts, cron and device permissions; never reimplement those.
### Dockerfiles
- Base is always `ghcr.io/linuxserver/baseimage-*`. Do not change distro, switch to upstream/distroless images, or add multi-stage complexity unless a maintainer asked for it. Base image rebases are done by the team.
- Follow the existing shape exactly: a single `RUN` chain joined with `&& \`, each step announced with `echo "**** doing thing ****"`, two space indentation, a `**** cleanup ****` step at the end removing `/tmp/*` and package caches.
- Packages are listed **one per line in alphabetical order**. Build-only dependencies go in a `build-dependencies` virtual package (Alpine) or are purged (Ubuntu) in the same layer.
- Do not hardcode or pin the application version. Keep the `if [ -z ${APP_VERSION+x} ]; then ...` pattern; CI supplies the version as a build arg and `jenkins-vars.yml` defines how it is detected.
- Do not add `HEALTHCHECK`, `USER`, `ENTRYPOINT` or `CMD`. The base image owns init (`/init`), and the container must start as root unless the image already documents non-root support.
- Do not touch the `LABEL maintainer` or `build_version` lines.
### Init scripts and services (`root/etc/s6-overlay/s6-rc.d/`)
- Naming: `init-<app>-config` (oneshot) and `svc-<app>` (longrun). Wire them in using empty files in `dependencies.d/` and `user/contents.d/`, exactly as the existing ones do. Oneshots have `type`, `up` (the path to `run`) and `run`. No legacy `cont-init.d` / `services.d`.
- Every script starts with:
```bash
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
```
- Bash, four space indentation, `[[ ]]` tests, `"${VAR}"` quoting, short lowercase `#` comments. Scripts must be shellcheck clean.
- Use `lsiown` instead of `chown`, run the app as `abc` via `s6-setuidgid abc`, and `exec` the final process so s6 supervises it. Keep `s6-notifyoncheck` readiness checks where they exist.
- If `readme-vars.yml` has `nonroot_supported: true` or `readonly_supported: true`, every new privileged operation (chown, writing outside `/config` and `/run`, `s6-setuidgid`) must be guarded the same way the existing code does it (`if [[ -z ${LSIO_NON_ROOT_USER} ]]; then` etc.). Do not break those modes.
- User data and config live in `/config`. Copy defaults only if the file does not already exist; never overwrite user config on startup. If an existing user's config must change, add a numbered script in `root/migrations/`.
- Avoid recursive `lsiown` on large data paths (media, downloads); it makes startup take minutes for real users.
- New environment variables are a last resort. If the app can be configured through its own config file or UI, that is the answer. We do not wrap app settings in env vars.
## 4. Documentation and changelog
- All user-facing docs changes go in `readme-vars.yml` (`app_setup_block`, `param_env_vars`, `opt_param_*`, etc.). Reference: [`_container-vars-blank`](https://github.com/linuxserver/docker-jenkins-builder/blob/master/ansible/vars/_container-vars-blank).
- Any change to a Dockerfile or to anything under `root/` needs a new entry at the **top** of `changelogs:` in `readme-vars.yml`, one short factual line:
```yaml
- {date: "DD.MM.YY:", desc: "Add libfoo to fix thumbnail generation."}
```
- Optionally regenerate the templated files to check your vars render (see the [jenkins-builder README](https://github.com/linuxserver/docker-jenkins-builder#running-against-local-project)), but do not hand edit the output.
## 5. Test it for real
A change that has not been built and run is not ready. At minimum:
```bash
docker build --no-cache --pull -t lscr.io/linuxserver/<app>:test .
docker run --rm -e PUID=1000 -e PGID=1000 -e TZ=Etc/UTC -v "$(pwd)/testconfig:/config" -p <port>:<port> lscr.io/linuxserver/<app>:test
```
Confirm the init completes (`[ls.io-init] done.`), the app comes up, and it survives a restart against an **existing** `/config`, not just a fresh one. If you touched the aarch64 Dockerfile with anything arch specific, build that too (`lscr.io/linuxserver/qemu-static`). If you, the agent, cannot run Docker, say so plainly in your output; do not claim testing that did not happen.
## 6. Pull requests
- **Disclose AI use.** If any part of the PR (code, description, or the investigation behind it) was produced with an AI tool, say so in the PR description: which tool, and what it was used for. Agents: add this line yourself, do not leave it to the operator. Undisclosed AI-generated PRs will be closed. Disclosure does not count against a PR; a human who cannot explain their own PR does.
- **A human is accountable.** The person opening the PR must have read and understood every line, built and run the image, and be able to answer review questions in their own words. Do not paste maintainer questions into a chatbot and paste the answers back. Fully autonomous agents must not open PRs or issues on our repos.
- **One focused change per PR.** The smallest diff that fixes the problem. No drive-by refactors, reformatting, comment rewording, "modernisation", dependency shuffling, or fixes for things nobody reported.
- **No typo / wording-only PRs.** Open an issue instead and we will sort it out.
- **Finish before you open.** Do not open drafts and iterate in public with a stream of fixup commits.
- **Fill in the PR template honestly**, keep its structure, and tick the contributing checkbox only if it is true. Description, benefit to the wider userbase, how it was tested (real commands, real output), and links. Write it short and plain: no generated summaries, emoji headers, or bullet lists restating the diff.
- Reference the issue with `closes #<number>` when there is one. For anything non trivial, there should be an human-submitted issue or Discord discussion first.
- Commit messages are short, plain, imperative sentences (`Add libfoo for thumbnail support`). No conventional-commit prefixes, no emoji.
- A PR is a proposal; it may be declined even if it works. The most common reason is section 1 of this file.
## 7. Issues
- GitHub issues are for reproducible bugs in **our image** and for feature requests.
- Agents must not file issues on a user's behalf from a guess. An issue needs a real reproduction on the latest image, with mods and custom scripts disabled, the compose/run command and full container logs from startup, using the issue template.
- Do not submit AI-generated root cause analyses or "security audits" of the image as issues. Scanner output about CVEs in upstream or distro packages is not actionable; images are rebuilt regularly to pull in distro fixes.
- Support questions must always be submitted by a human and go to [Discord](https://linuxserver.io/discord) or the [forum](https://github.com/orgs/linuxserver/discussions); see [how to get support](https://docs.linuxserver.io/general/how-to-get-support/).
## 8. Quick self check before you finish
- [ ] This change benefits most users of this image, and is not a mod, custom script, or upstream issue.
- [ ] Only hand-maintained files were edited (`Dockerfile*`, `root/**`, `readme-vars.yml`, rarely `jenkins-vars.yml`).
- [ ] Every Dockerfile variant got the same change; packages are alphabetical.
- [ ] Style matches the neighbouring code; shebang and shellcheck directive present; non-root / read-only guards preserved.
- [ ] Changelog entry added at the top of `changelogs:` with today's date as `DD.MM.YY:`.
- [ ] Image was built and run, including against an existing `/config`.
- [ ] The diff contains nothing the task did not require.
- [ ] PR description discloses AI use and a human has reviewed everything.
Vendored
+260 -63
View File
@@ -52,6 +52,57 @@ pipeline {
''' '''
} }
} }
/* ############################
Bash Function For GHCR Retry
############################ */
// Create a reusable script for a ghcr retry bash function
stage("Create Bash Function"){
steps{
sh '''#! /bin/bash
# create our retry function
retry_ghcr() {
local max_attempts=7
local base_delay=10
local max_delay=90
local attempt=1
local errfile exit_code delay pause
errfile=$(mktemp)
while true; do
# run inside an if so a caller's set -e cannot abort before we get to retry
if "$@" 2> >(tee "${errfile}" >&2); then
exit_code=0
else
exit_code=$?
fi
# make sure tee has finished writing before we read the file
wait $! 2>/dev/null || true
if [[ "${exit_code}" == "0" ]]; then
rm -f "${errfile}"
return 0
elif ! grep -q -i -E "retry-after:|toomanyrequests|too many requests" "${errfile}"; then
rm -f "${errfile}"
return "${exit_code}"
elif (( attempt >= max_attempts )); then
rm -f "${errfile}"
echo "retry: $* failed after ${attempt} attempts (exit ${exit_code})" >&2
return "${exit_code}"
else
# exponential delay: base * 2^(attempt-1), capped at max_delay
delay=$(( base_delay * 2 ** (attempt - 1) ))
(( delay > max_delay )) && delay="${max_delay}"
# jitter between half and full delay so parallel builds spread out
pause=$(( delay / 2 + RANDOM % (delay / 2 + 1) ))
echo "retry: attempt ${attempt}/${max_attempts} failed (exit ${exit_code}); waiting ${pause}s..." >&2
sleep "${pause}"
((attempt++))
fi
done
}
declare -f retry_ghcr > ${WORKSPACE}/retry_ghcr.sh
'''
}
}
// Setup all the basic environment variables needed for the build // Setup all the basic environment variables needed for the build
stage("Set ENV Variables base"){ stage("Set ENV Variables base"){
steps{ steps{
@@ -79,7 +130,9 @@ pipeline {
env.CI_TEST_ATTEMPTED = '' env.CI_TEST_ATTEMPTED = ''
env.PUSH_ATTEMPTED = '' env.PUSH_ATTEMPTED = ''
env.LS_RELEASE = sh( env.LS_RELEASE = sh(
script: '''docker run --rm quay.io/skopeo/stable:v1 inspect docker://ghcr.io/${LS_USER}/${CONTAINER_NAME}:latest 2>/dev/null | jq -r '.Labels.build_version' | awk '{print $3}' | grep '\\-ls' || : ''', script: '''#! /bin/bash
source ${WORKSPACE}/retry_ghcr.sh
retry_ghcr docker run --rm quay.io/skopeo/stable:v1 inspect docker://ghcr.io/${LS_USER}/${CONTAINER_NAME}:latest | jq -r '.Labels.build_version' | awk '{print $3}' | grep '\\-ls' || : ''',
returnStdout: true).trim() returnStdout: true).trim()
env.LS_RELEASE_NOTES = sh( env.LS_RELEASE_NOTES = sh(
script: '''cat readme-vars.yml | awk -F \\" '/date: "[0-9][0-9].[0-9][0-9].[0-9][0-9]:/ {print $4;exit;}' | sed -E ':a;N;$!ba;s/\\r{0,1}\\n/\\\\n/g' ''', script: '''cat readme-vars.yml | awk -F \\" '/date: "[0-9][0-9].[0-9][0-9].[0-9][0-9]:/ {print $4;exit;}' | sed -E ':a;N;$!ba;s/\\r{0,1}\\n/\\\\n/g' ''',
@@ -96,12 +149,16 @@ pipeline {
env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/commit/' + env.GIT_COMMIT env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/commit/' + env.GIT_COMMIT
env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DOCKERHUB_IMAGE + '/tags/' env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DOCKERHUB_IMAGE + '/tags/'
env.PULL_REQUEST = env.CHANGE_ID 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 ./.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 ./.github/workflows/external_trigger.yml ./root/donate.txt' env.TEMPLATED_FILES = 'Jenkinsfile README.md LICENSE .editorconfig AGENTS.md ./.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 ./.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 ./.github/workflows/external_trigger.yml ./root/donate.txt'
if ( env.SYFT_IMAGE_TAG == null ) { if ( env.SYFT_IMAGE_TAG == null ) {
env.SYFT_IMAGE_TAG = 'latest' env.SYFT_IMAGE_TAG = 'latest'
} }
if ( env.GITLAB_TIMEOUT == null ) {
env.GITLAB_TIMEOUT = '600'
}
} }
echo "Using syft image tag ${SYFT_IMAGE_TAG}" echo "Using syft image tag ${SYFT_IMAGE_TAG}"
echo "Using gitlab registry timeout ${GITLAB_TIMEOUT}"
sh '''#! /bin/bash sh '''#! /bin/bash
echo "The default github branch detected as ${GH_DEFAULT_BRANCH}" ''' echo "The default github branch detected as ${GH_DEFAULT_BRANCH}" '''
script{ script{
@@ -281,6 +338,8 @@ pipeline {
} }
sh '''curl -sL https://raw.githubusercontent.com/linuxserver/docker-jenkins-builder/master/checkrun.sh | /bin/bash''' sh '''curl -sL https://raw.githubusercontent.com/linuxserver/docker-jenkins-builder/master/checkrun.sh | /bin/bash'''
sh '''#! /bin/bash sh '''#! /bin/bash
source ${WORKSPACE}/retry_ghcr.sh
retry_ghcr docker pull ghcr.io/linuxserver/baseimage-alpine:3.23
docker run --rm \ docker run --rm \
-v ${WORKSPACE}:/mnt \ -v ${WORKSPACE}:/mnt \
-e AWS_ACCESS_KEY_ID=\"${S3_KEY}\" \ -e AWS_ACCESS_KEY_ID=\"${S3_KEY}\" \
@@ -307,7 +366,8 @@ pipeline {
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
TEMPDIR=$(mktemp -d) TEMPDIR=$(mktemp -d)
docker pull ghcr.io/linuxserver/jenkins-builder:latest source ${WORKSPACE}/retry_ghcr.sh
retry_ghcr docker pull ghcr.io/linuxserver/jenkins-builder:latest
# Cloned repo paths for templating: # Cloned repo paths for templating:
# ${TEMPDIR}/docker-${CONTAINER_NAME}: Cloned branch master of ${LS_USER}/${LS_REPO} for running the jenkins builder on # ${TEMPDIR}/docker-${CONTAINER_NAME}: Cloned branch master of ${LS_USER}/${LS_REPO} for running the jenkins builder on
# ${TEMPDIR}/repo/${LS_REPO}: Cloned branch master of ${LS_USER}/${LS_REPO} for commiting various templated file changes and pushing back to Github # ${TEMPDIR}/repo/${LS_REPO}: Cloned branch master of ${LS_USER}/${LS_REPO} for commiting various templated file changes and pushing back to Github
@@ -366,6 +426,7 @@ pipeline {
sed -i 's|^changelogs:|# init diagram\\ninit_diagram:\\n\\n# changelog\\nchangelogs:|' readme-vars.yml sed -i 's|^changelogs:|# init diagram\\ninit_diagram:\\n\\n# changelog\\nchangelogs:|' readme-vars.yml
fi fi
mkdir -p ${TEMPDIR}/d2 mkdir -p ${TEMPDIR}/d2
retry_ghcr docker pull ghcr.io/linuxserver/d2-builder:latest
docker run --rm -v ${TEMPDIR}/d2:/output -e PUID=$(id -u) -e PGID=$(id -g) -e RAW="true" ghcr.io/linuxserver/d2-builder:latest ${CONTAINER_NAME}:latest docker run --rm -v ${TEMPDIR}/d2:/output -e PUID=$(id -u) -e PGID=$(id -g) -e RAW="true" ghcr.io/linuxserver/d2-builder:latest ${CONTAINER_NAME}:latest
ls -al ${TEMPDIR}/d2 ls -al ${TEMPDIR}/d2
yq -ei ".init_diagram |= load_str(\\"${TEMPDIR}/d2/${CONTAINER_NAME}-latest.d2\\")" readme-vars.yml yq -ei ".init_diagram |= load_str(\\"${TEMPDIR}/d2/${CONTAINER_NAME}-latest.d2\\")" readme-vars.yml
@@ -582,22 +643,25 @@ pipeline {
steps { steps {
echo "Running on node: ${NODE_NAME}" echo "Running on node: ${NODE_NAME}"
sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile" sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile"
sh "docker buildx build \ sh '''#! /bin/bash
--label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ source ${WORKSPACE}/retry_ghcr.sh
--label \"org.opencontainers.image.authors=linuxserver.io\" \ retry_ghcr docker buildx build \
--label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-swag/packages\" \ --label "org.opencontainers.image.created=${GITHUB_DATE}" \
--label \"org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-swag\" \ --label "org.opencontainers.image.authors=linuxserver.io" \
--label \"org.opencontainers.image.source=https://github.com/linuxserver/docker-swag\" \ --label "org.opencontainers.image.url=https://github.com/linuxserver/docker-swag/packages" \
--label \"org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}\" \ --label "org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-swag" \
--label \"org.opencontainers.image.revision=${COMMIT_SHA}\" \ --label "org.opencontainers.image.source=https://github.com/linuxserver/docker-swag" \
--label \"org.opencontainers.image.vendor=linuxserver.io\" \ --label "org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}" \
--label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ --label "org.opencontainers.image.revision=${COMMIT_SHA}" \
--label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ --label "org.opencontainers.image.vendor=linuxserver.io" \
--label \"org.opencontainers.image.title=Swag\" \ --label "org.opencontainers.image.licenses=GPL-3.0-only" \
--label \"org.opencontainers.image.description=SWAG - Secure Web Application Gateway (formerly known as letsencrypt, no relation to Let's Encrypt™) sets up an Nginx webserver and reverse proxy with php support and a built-in certbot client that automates free SSL server certificate generation and renewal processes (Let's Encrypt and ZeroSSL). It also contains fail2ban for intrusion prevention.\" \ --label "org.opencontainers.image.ref.name=${COMMIT_SHA}" \
--label "org.opencontainers.image.title=Swag" \
--label "org.opencontainers.image.description=SWAG - Secure Web Application Gateway (formerly known as letsencrypt, no relation to Let's Encrypt™) sets up an Nginx webserver and reverse proxy with php support and a built-in certbot client that automates free SSL server certificate generation and renewal processes (Let's Encrypt and ZeroSSL). It also contains fail2ban for intrusion prevention." \
--no-cache --pull -t ${IMAGE}:${META_TAG} --platform=linux/amd64 \ --no-cache --pull -t ${IMAGE}:${META_TAG} --platform=linux/amd64 \
--provenance=true --sbom=true --builder=container --load \ --provenance=true --sbom=true --builder=container --load \
--build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION="${VERSION_TAG}" --build-arg BUILD_DATE=${GITHUB_DATE} .
'''
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
IFS=',' read -ra CACHE <<< "$BUILDCACHE" IFS=',' read -ra CACHE <<< "$BUILDCACHE"
@@ -616,6 +680,17 @@ pipeline {
retry_backoff(5,5) { retry_backoff(5,5) {
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
# run a registry.gitlab.com command under what is left of the gitlab time budget
gitlab_timeout() {
local remaining=$(( GITLAB_DEADLINE - SECONDS ))
if (( remaining <= 0 )); then
echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2
return 124
fi
timeout "${remaining}" "$@"
}
GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT ))
echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin
echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin
echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin
@@ -625,11 +700,16 @@ pipeline {
declare -A pids declare -A pids
IFS=',' read -ra CACHE <<< "$BUILDCACHE" IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do for i in "${CACHE[@]}"; do
docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & if [[ "${i}" == *"registry.gitlab.com"* ]]; then
TIMEOUT_CMD="gitlab_timeout"
else
TIMEOUT_CMD=""
fi
${TIMEOUT_CMD} docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} &
pids[$!]="$i" pids[$!]="$i"
done done
for p in "${!pids[@]}"; do for p in "${!pids[@]}"; do
wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* && "${pids[$p]}" != *"registry.gitlab.com"* ]] && exit 1; } wait "$p" || { if [[ "${pids[$p]}" != *"quay.io"* && "${pids[$p]}" != *"registry.gitlab.com"* ]]; then exit 1; fi; }
done done
fi fi
''' '''
@@ -651,22 +731,25 @@ pipeline {
steps { steps {
echo "Running on node: ${NODE_NAME}" echo "Running on node: ${NODE_NAME}"
sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile" sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile"
sh "docker buildx build \ sh '''#! /bin/bash
--label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ source ${WORKSPACE}/retry_ghcr.sh
--label \"org.opencontainers.image.authors=linuxserver.io\" \ retry_ghcr docker buildx build \
--label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-swag/packages\" \ --label "org.opencontainers.image.created=${GITHUB_DATE}" \
--label \"org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-swag\" \ --label "org.opencontainers.image.authors=linuxserver.io" \
--label \"org.opencontainers.image.source=https://github.com/linuxserver/docker-swag\" \ --label "org.opencontainers.image.url=https://github.com/linuxserver/docker-swag/packages" \
--label \"org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}\" \ --label "org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-swag" \
--label \"org.opencontainers.image.revision=${COMMIT_SHA}\" \ --label "org.opencontainers.image.source=https://github.com/linuxserver/docker-swag" \
--label \"org.opencontainers.image.vendor=linuxserver.io\" \ --label "org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}" \
--label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ --label "org.opencontainers.image.revision=${COMMIT_SHA}" \
--label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ --label "org.opencontainers.image.vendor=linuxserver.io" \
--label \"org.opencontainers.image.title=Swag\" \ --label "org.opencontainers.image.licenses=GPL-3.0-only" \
--label \"org.opencontainers.image.description=SWAG - Secure Web Application Gateway (formerly known as letsencrypt, no relation to Let's Encrypt™) sets up an Nginx webserver and reverse proxy with php support and a built-in certbot client that automates free SSL server certificate generation and renewal processes (Let's Encrypt and ZeroSSL). It also contains fail2ban for intrusion prevention.\" \ --label "org.opencontainers.image.ref.name=${COMMIT_SHA}" \
--label "org.opencontainers.image.title=Swag" \
--label "org.opencontainers.image.description=SWAG - Secure Web Application Gateway (formerly known as letsencrypt, no relation to Let's Encrypt™) sets up an Nginx webserver and reverse proxy with php support and a built-in certbot client that automates free SSL server certificate generation and renewal processes (Let's Encrypt and ZeroSSL). It also contains fail2ban for intrusion prevention." \
--no-cache --pull -t ${IMAGE}:amd64-${META_TAG} --platform=linux/amd64 \ --no-cache --pull -t ${IMAGE}:amd64-${META_TAG} --platform=linux/amd64 \
--provenance=true --sbom=true --builder=container --load \ --provenance=true --sbom=true --builder=container --load \
--build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION="${VERSION_TAG}" --build-arg BUILD_DATE=${GITHUB_DATE} .
'''
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
IFS=',' read -ra CACHE <<< "$BUILDCACHE" IFS=',' read -ra CACHE <<< "$BUILDCACHE"
@@ -685,6 +768,17 @@ pipeline {
retry_backoff(5,5) { retry_backoff(5,5) {
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
# run a registry.gitlab.com command under what is left of the gitlab time budget
gitlab_timeout() {
local remaining=$(( GITLAB_DEADLINE - SECONDS ))
if (( remaining <= 0 )); then
echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2
return 124
fi
timeout "${remaining}" "$@"
}
GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT ))
echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin
echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin
echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin
@@ -694,11 +788,16 @@ pipeline {
declare -A pids declare -A pids
IFS=',' read -ra CACHE <<< "$BUILDCACHE" IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do for i in "${CACHE[@]}"; do
docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & if [[ "${i}" == *"registry.gitlab.com"* ]]; then
TIMEOUT_CMD="gitlab_timeout"
else
TIMEOUT_CMD=""
fi
${TIMEOUT_CMD} docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} &
pids[$!]="$i" pids[$!]="$i"
done done
for p in "${!pids[@]}"; do for p in "${!pids[@]}"; do
wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* && "${pids[$p]}" != *"registry.gitlab.com"* ]] && exit 1; } wait "$p" || { if [[ "${pids[$p]}" != *"quay.io"* && "${pids[$p]}" != *"registry.gitlab.com"* ]]; then exit 1; fi; }
done done
fi fi
''' '''
@@ -713,22 +812,64 @@ pipeline {
steps { steps {
echo "Running on node: ${NODE_NAME}" echo "Running on node: ${NODE_NAME}"
sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile.aarch64" sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile.aarch64"
sh "docker buildx build \ sh '''#! /bin/bash
--label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ # create our retry function
--label \"org.opencontainers.image.authors=linuxserver.io\" \ retry_ghcr() {
--label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-swag/packages\" \ local max_attempts=7
--label \"org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-swag\" \ local base_delay=10
--label \"org.opencontainers.image.source=https://github.com/linuxserver/docker-swag\" \ local max_delay=90
--label \"org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}\" \ local attempt=1
--label \"org.opencontainers.image.revision=${COMMIT_SHA}\" \ local errfile exit_code delay pause
--label \"org.opencontainers.image.vendor=linuxserver.io\" \ errfile=$(mktemp)
--label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ while true; do
--label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ # run inside an if so a caller's set -e cannot abort before we get to retry
--label \"org.opencontainers.image.title=Swag\" \ if "$@" 2> >(tee "${errfile}" >&2); then
--label \"org.opencontainers.image.description=SWAG - Secure Web Application Gateway (formerly known as letsencrypt, no relation to Let's Encrypt™) sets up an Nginx webserver and reverse proxy with php support and a built-in certbot client that automates free SSL server certificate generation and renewal processes (Let's Encrypt and ZeroSSL). It also contains fail2ban for intrusion prevention.\" \ exit_code=0
else
exit_code=$?
fi
# make sure tee has finished writing before we read the file
wait $! 2>/dev/null || true
if [[ "${exit_code}" == "0" ]]; then
rm -f "${errfile}"
return 0
elif ! grep -q -i -E "retry-after:|toomanyrequests|too many requests" "${errfile}"; then
rm -f "${errfile}"
return "${exit_code}"
elif (( attempt >= max_attempts )); then
rm -f "${errfile}"
echo "retry: $* failed after ${attempt} attempts (exit ${exit_code})" >&2
return "${exit_code}"
else
# exponential delay: base * 2^(attempt-1), capped at max_delay
delay=$(( base_delay * 2 ** (attempt - 1) ))
(( delay > max_delay )) && delay="${max_delay}"
# jitter between half and full delay so parallel builds spread out
pause=$(( delay / 2 + RANDOM % (delay / 2 + 1) ))
echo "retry: attempt ${attempt}/${max_attempts} failed (exit ${exit_code}); waiting ${pause}s..." >&2
sleep "${pause}"
((attempt++))
fi
done
}
retry_ghcr docker buildx build \
--label "org.opencontainers.image.created=${GITHUB_DATE}" \
--label "org.opencontainers.image.authors=linuxserver.io" \
--label "org.opencontainers.image.url=https://github.com/linuxserver/docker-swag/packages" \
--label "org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-swag" \
--label "org.opencontainers.image.source=https://github.com/linuxserver/docker-swag" \
--label "org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}" \
--label "org.opencontainers.image.revision=${COMMIT_SHA}" \
--label "org.opencontainers.image.vendor=linuxserver.io" \
--label "org.opencontainers.image.licenses=GPL-3.0-only" \
--label "org.opencontainers.image.ref.name=${COMMIT_SHA}" \
--label "org.opencontainers.image.title=Swag" \
--label "org.opencontainers.image.description=SWAG - Secure Web Application Gateway (formerly known as letsencrypt, no relation to Let's Encrypt™) sets up an Nginx webserver and reverse proxy with php support and a built-in certbot client that automates free SSL server certificate generation and renewal processes (Let's Encrypt and ZeroSSL). It also contains fail2ban for intrusion prevention." \
--no-cache --pull -f Dockerfile.aarch64 -t ${IMAGE}:arm64v8-${META_TAG} --platform=linux/arm64 \ --no-cache --pull -f Dockerfile.aarch64 -t ${IMAGE}:arm64v8-${META_TAG} --platform=linux/arm64 \
--provenance=true --sbom=true --builder=container --load \ --provenance=true --sbom=true --builder=container --load \
--build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION="${VERSION_TAG}" --build-arg BUILD_DATE=${GITHUB_DATE} .
'''
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
IFS=',' read -ra CACHE <<< "$BUILDCACHE" IFS=',' read -ra CACHE <<< "$BUILDCACHE"
@@ -747,6 +888,17 @@ pipeline {
retry_backoff(5,5) { retry_backoff(5,5) {
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
# run a registry.gitlab.com command under what is left of the gitlab time budget
gitlab_timeout() {
local remaining=$(( GITLAB_DEADLINE - SECONDS ))
if (( remaining <= 0 )); then
echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2
return 124
fi
timeout "${remaining}" "$@"
}
GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT ))
echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin
echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin
echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin
@@ -755,11 +907,16 @@ pipeline {
declare -A pids declare -A pids
IFS=',' read -ra CACHE <<< "$BUILDCACHE" IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do for i in "${CACHE[@]}"; do
docker push ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} & if [[ "${i}" == *"registry.gitlab.com"* ]]; then
TIMEOUT_CMD="gitlab_timeout"
else
TIMEOUT_CMD=""
fi
${TIMEOUT_CMD} docker push ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} &
pids[$!]="$i" pids[$!]="$i"
done done
for p in "${!pids[@]}"; do for p in "${!pids[@]}"; do
wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* && "${pids[$p]}" != *"registry.gitlab.com"* ]] && exit 1; } wait "$p" || { if [[ "${pids[$p]}" != *"quay.io"* && "${pids[$p]}" != *"registry.gitlab.com"* ]]; then exit 1; fi; }
done done
fi fi
''' '''
@@ -794,6 +951,8 @@ pipeline {
LOCAL_CONTAINER=${IMAGE}:${META_TAG} LOCAL_CONTAINER=${IMAGE}:${META_TAG}
fi fi
touch ${TEMPDIR}/package_versions.txt touch ${TEMPDIR}/package_versions.txt
source ${WORKSPACE}/retry_ghcr.sh
retry_ghcr docker pull ghcr.io/anchore/syft:${SYFT_IMAGE_TAG}
docker run --rm \ docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock:ro \ -v /var/run/docker.sock:/var/run/docker.sock:ro \
-v ${TEMPDIR}:/tmp \ -v ${TEMPDIR}:/tmp \
@@ -885,9 +1044,10 @@ pipeline {
CI_DOCKERENV="LSIO_FIRST_PARTY=true" CI_DOCKERENV="LSIO_FIRST_PARTY=true"
fi fi
fi fi
docker pull ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} source ${WORKSPACE}/retry_ghcr.sh
retry_ghcr docker pull ghcr.io/linuxserver/ci:${CITEST_IMAGETAG}
if [ "${MULTIARCH}" == "true" ]; then if [ "${MULTIARCH}" == "true" ]; then
docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} --platform=arm64 retry_ghcr docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} --platform=arm64
docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG}
fi fi
docker run --rm \ docker run --rm \
@@ -932,7 +1092,23 @@ pipeline {
retry_backoff(5,5) { retry_backoff(5,5) {
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
# run a registry.gitlab.com command under what is left of the gitlab time budget
gitlab_timeout() {
local remaining=$(( GITLAB_DEADLINE - SECONDS ))
if (( remaining <= 0 )); then
echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2
return 124
fi
timeout "${remaining}" "$@"
}
GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT ))
for PUSHIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do for PUSHIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do
if [[ "${PUSHIMAGE}" == "${GITLABIMAGE}" ]]; then
TIMEOUT_CMD="gitlab_timeout"
else
TIMEOUT_CMD=""
fi
[[ ${PUSHIMAGE%%/*} =~ \\. ]] && PUSHIMAGEPLUS="${PUSHIMAGE}" || PUSHIMAGEPLUS="docker.io/${PUSHIMAGE}" [[ ${PUSHIMAGE%%/*} =~ \\. ]] && PUSHIMAGEPLUS="${PUSHIMAGE}" || PUSHIMAGEPLUS="docker.io/${PUSHIMAGE}"
IFS=',' read -ra CACHE <<< "$BUILDCACHE" IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do for i in "${CACHE[@]}"; do
@@ -940,10 +1116,10 @@ pipeline {
CACHEIMAGE=${i} CACHEIMAGE=${i}
fi fi
done done
docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${META_TAG} -t ${PUSHIMAGE}:latest -t ${PUSHIMAGE}:${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${META_TAG} -t ${PUSHIMAGE}:latest -t ${PUSHIMAGE}:${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \
{ if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" && "${PUSHIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" && "${PUSHIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
if [ -n "${SEMVER}" ]; then if [ -n "${SEMVER}" ]; then
docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \
{ if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" && "${PUSHIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" && "${PUSHIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
fi fi
done done
@@ -964,7 +1140,23 @@ pipeline {
retry_backoff(5,5) { retry_backoff(5,5) {
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
# run a registry.gitlab.com command under what is left of the gitlab time budget
gitlab_timeout() {
local remaining=$(( GITLAB_DEADLINE - SECONDS ))
if (( remaining <= 0 )); then
echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2
return 124
fi
timeout "${remaining}" "$@"
}
GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT ))
for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do
if [[ "${MANIFESTIMAGE}" == "${GITLABIMAGE}" ]]; then
TIMEOUT_CMD="gitlab_timeout"
else
TIMEOUT_CMD=""
fi
if [[ "${MANIFESTIMAGE%%/*}" =~ \\. ]]; then if [[ "${MANIFESTIMAGE%%/*}" =~ \\. ]]; then
MANIFESTIMAGEPLUS="${MANIFESTIMAGE}" MANIFESTIMAGEPLUS="${MANIFESTIMAGE}"
else else
@@ -976,26 +1168,31 @@ pipeline {
CACHEIMAGE=${i} CACHEIMAGE=${i}
fi fi
done done
docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${META_TAG} -t ${MANIFESTIMAGE}:amd64-latest -t ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${META_TAG} -t ${MANIFESTIMAGE}:amd64-latest -t ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${META_TAG} -t ${MANIFESTIMAGE}:arm64v8-latest -t ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${META_TAG} -t ${MANIFESTIMAGE}:arm64v8-latest -t ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
if [ -n "${SEMVER}" ]; then if [ -n "${SEMVER}" ]; then
docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${SEMVER} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${SEMVER} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
fi fi
done done
for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do
docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest || \ if [[ "${MANIFESTIMAGE}" == "${GITLABIMAGE}" ]]; then
TIMEOUT_CMD="gitlab_timeout"
else
TIMEOUT_CMD=""
fi
${TIMEOUT_CMD} docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest || \
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} || \ ${TIMEOUT_CMD} docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} || \
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} || \ ${TIMEOUT_CMD} docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} || \
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
if [ -n "${SEMVER}" ]; then if [ -n "${SEMVER}" ]; then
docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} || \ ${TIMEOUT_CMD} docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} || \
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; }
fi fi
done done
+3 -2
View File
@@ -4,7 +4,7 @@
[![Blog](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=Blog)](https://blog.linuxserver.io "all the things you can do with our containers including How-To guides, opinions and much more!") [![Blog](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=Blog)](https://blog.linuxserver.io "all the things you can do with our containers including How-To guides, opinions and much more!")
[![Discord](https://img.shields.io/discord/354974912613449730.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Discord&logo=discord)](https://linuxserver.io/discord "realtime support / chat with the community and the team.") [![Discord](https://img.shields.io/discord/354974912613449730.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Discord&logo=discord)](https://linuxserver.io/discord "realtime support / chat with the community and the team.")
[![Discourse](https://img.shields.io/discourse/https/discourse.linuxserver.io/topics.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&logo=discourse)](https://discourse.linuxserver.io "post on our community forum.") [![Discussions](https://img.shields.io/badge/Github-Discussions-94398d?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&logo=github)](https://github.com/orgs/linuxserver/discussions "post on our community forum.")
[![GitHub](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=GitHub&logo=github)](https://github.com/linuxserver "view the source for all of our repositories.") [![GitHub](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=GitHub&logo=github)](https://github.com/linuxserver "view the source for all of our repositories.")
[![Open Collective](https://img.shields.io/opencollective/all/linuxserver.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Supporters&logo=open%20collective)](https://opencollective.com/linuxserver "please consider helping us by either donating or contributing to our budget") [![Open Collective](https://img.shields.io/opencollective/all/linuxserver.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Supporters&logo=open%20collective)](https://opencollective.com/linuxserver "please consider helping us by either donating or contributing to our budget")
@@ -20,7 +20,7 @@ Find us at:
* [Blog](https://blog.linuxserver.io) - all the things you can do with our containers including How-To guides, opinions and much more! * [Blog](https://blog.linuxserver.io) - all the things you can do with our containers including How-To guides, opinions and much more!
* [Discord](https://linuxserver.io/discord) - realtime support / chat with the community and the team. * [Discord](https://linuxserver.io/discord) - realtime support / chat with the community and the team.
* [Discourse](https://discourse.linuxserver.io) - post on our community forum. * [Discussions](https://github.com/orgs/linuxserver/discussions) - post on our community forum.
* [GitHub](https://github.com/linuxserver) - view the source for all of our repositories. * [GitHub](https://github.com/linuxserver) - view the source for all of our repositories.
* [Open Collective](https://opencollective.com/linuxserver) - please consider helping us by either donating or contributing to our budget * [Open Collective](https://opencollective.com/linuxserver) - please consider helping us by either donating or contributing to our budget
@@ -436,6 +436,7 @@ Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64
## Versions ## Versions
* **20.10.26:** - [Existing users should update:](https://github.com/linuxserver/docker-swag/blob/master/README.md#updating-configs) proxy.conf, authelia-server.conf, authentik-server.conf, tinyauth-server.conf - Update Nginx configuration to replace $http_host with $host$is_request_port$request_port for better compatibility.
* **09.09.26:** - Use new X-Tinyauth-Location header in Tinyauth locations and remove duplicate auth module headers. * **09.09.26:** - Use new X-Tinyauth-Location header in Tinyauth locations and remove duplicate auth module headers.
* **19.07.26:** - Rebase to Alpine 3.24 with PHP 8.5. * **19.07.26:** - Rebase to Alpine 3.24 with PHP 8.5.
* **10.07.26:** - Add support for Let's Encrypt cert profiles. Run certbot twice daily with a random delay. * **10.07.26:** - Add support for Let's Encrypt cert profiles. Run certbot twice daily with a random delay.
+31 -32
View File
@@ -9,7 +9,7 @@ alpine-release 3.24.2-r0 apk
annotated-types 0.8.0 python annotated-types 0.8.0 python
anyio 4.15.1 python anyio 4.15.1 python
aom-libs 3.14.1-r0 apk aom-libs 3.14.1-r0 apk
apache2-utils 2.4.68-r0 apk apache2-utils 2.4.69-r0 apk
apk-tools 3.0.8-r0 apk apk-tools 3.0.8-r0 apk
apr 1.7.6-r0 apk apr 1.7.6-r0 apk
apr-util 1.6.4-r0 apk apr-util 1.6.4-r0 apk
@@ -23,8 +23,8 @@ azure-mgmt-dns 9.0.0 python
backports-tarfile 1.2.0 python backports-tarfile 1.2.0 python
bash 5.3.9-r1 apk bash 5.3.9-r1 apk
beautifulsoup4 4.15.0 python beautifulsoup4 4.15.0 python
boto3 1.43.108 python boto3 1.43.115 python
botocore 1.43.108 python botocore 1.43.115 python
brotli-libs 1.2.0-r1 apk brotli-libs 1.2.0-r1 apk
bs4 0.0.2 python bs4 0.0.2 python
busybox 1.37.0-r31 apk busybox 1.37.0-r31 apk
@@ -58,7 +58,7 @@ certbot-dns-godaddy 2.8.0 python
certbot-dns-google 5.8.0 python certbot-dns-google 5.8.0 python
certbot-dns-he 1.0.0 python certbot-dns-he 1.0.0 python
certbot-dns-hetzner 4.0.0 python certbot-dns-hetzner 4.0.0 python
certbot-dns-hetzner-cloud 1.0.5 python certbot-dns-hetzner-cloud 1.1.0 python
certbot-dns-infomaniak 0.3.3 python certbot-dns-infomaniak 0.3.3 python
certbot-dns-inwx 3.0.3 python certbot-dns-inwx 3.0.3 python
certbot-dns-ionos 2024.11.9 python certbot-dns-ionos 2024.11.9 python
@@ -67,7 +67,7 @@ certbot-dns-loopia 1.0.1 python
certbot-dns-luadns 5.8.0 python certbot-dns-luadns 5.8.0 python
certbot-dns-mijn-host 0.0.10 python certbot-dns-mijn-host 0.0.10 python
certbot-dns-namecheap 1.0.0 python certbot-dns-namecheap 1.0.0 python
certbot-dns-netcup 2.0.3 python certbot-dns-netcup 2.1.0 python
certbot-dns-njalla 2.0.2 python certbot-dns-njalla 2.0.2 python
certbot-dns-nsone 5.8.0 python certbot-dns-nsone 5.8.0 python
certbot-dns-ovh 5.8.0 python certbot-dns-ovh 5.8.0 python
@@ -79,7 +79,7 @@ certbot-dns-standalone 1.2.1 python
certbot-dns-transip 0.5.2 python certbot-dns-transip 0.5.2 python
certbot-dns-vultr 1.1.0 python certbot-dns-vultr 1.1.0 python
certbot-plugin-gandi 1.5.0 python certbot-plugin-gandi 1.5.0 python
certifi 2026.7.22 python certifi 2026.10.19 python
cffi 2.1.1 python cffi 2.1.1 python
charset-normalizer 3.5.2 python charset-normalizer 3.5.2 python
cli UNKNOWN binary cli UNKNOWN binary
@@ -99,12 +99,12 @@ curl 8.22.0-r0 apk
distro 1.9.0 python distro 1.9.0 python
dns-lexicon 3.25.2 python dns-lexicon 3.25.2 python
dnslib 0.9.26 python dnslib 0.9.26 python
dnspython 2.8.0 python dnspython 2.9.0 python
domeneshop 0.4.4 python domeneshop 0.4.4 python
fail2ban 1.1.0 python fail2ban 1.1.0 python
fail2ban 1.1.0-r3 apk fail2ban 1.1.0-r3 apk
fail2ban-pyc 1.1.0-r3 apk fail2ban-pyc 1.1.0-r3 apk
filelock 4.0.9 python filelock 4.2.4 python
findutils 4.10.0-r1 apk findutils 4.10.0-r1 apk
fontconfig 2.17.1-r1 apk fontconfig 2.17.1-r1 apk
freetype 2.14.3-r0 apk freetype 2.14.3-r0 apk
@@ -121,9 +121,9 @@ gnupg-keyboxd 2.4.9-r1 apk
gnupg-utils 2.4.9-r1 apk gnupg-utils 2.4.9-r1 apk
gnupg-wks-client 2.4.9-r1 apk gnupg-wks-client 2.4.9-r1 apk
gnutls 3.8.13-r0 apk gnutls 3.8.13-r0 apk
google-api-core 2.40.0 python google-api-core 2.42.0 python
google-api-python-client 2.201.0 python google-api-python-client 2.201.0 python
google-auth 2.59.1 python google-auth 2.62.0 python
google-auth-httplib2 0.4.4 python google-auth-httplib2 0.4.4 python
googleapis-common-protos 1.75.5 python googleapis-common-protos 1.75.5 python
gpg 2.4.9-r1 apk gpg 2.4.9-r1 apk
@@ -136,7 +136,7 @@ gui-32 UNKNOWN binary
gui-64 UNKNOWN binary gui-64 UNKNOWN binary
gui-arm64 UNKNOWN binary gui-arm64 UNKNOWN binary
h11 0.16.0 python h11 0.16.0 python
hcloud 2.26.0 python hcloud 2.27.0 python
httpcore 1.0.9 python httpcore 1.0.9 python
httplib2 0.32.0 python httplib2 0.32.0 python
httpx 0.28.1 python httpx 0.28.1 python
@@ -157,7 +157,7 @@ jinja2 3.1.6 python
jmespath 1.1.0 python jmespath 1.1.0 python
josepy 2.2.0 python josepy 2.2.0 python
jq 1.8.2-r0 apk jq 1.8.2-r0 apk
jsonpickle 4.1.3 python jsonpickle 4.1.4 python
libapk 3.0.8-r0 apk libapk 3.0.8-r0 apk
libassuan 3.0.2-r0 apk libassuan 3.0.2-r0 apk
libattr 2.5.2-r2 apk libattr 2.5.2-r2 apk
@@ -195,7 +195,7 @@ libpq 18.6-r0 apk
libproc2 4.0.6-r0 apk libproc2 4.0.6-r0 apk
libpsl 0.21.5-r3 apk libpsl 0.21.5-r3 apk
libsasl 2.1.28-r9 apk libsasl 2.1.28-r9 apk
libseccomp 2.6.0-r2 apk libseccomp 2.6.1-r0 apk
libsharpyuv 1.6.0-r0 apk libsharpyuv 1.6.0-r0 apk
libsm 1.2.6-r0 apk libsm 1.2.6-r0 apk
libsodium 1.0.22-r0 apk libsodium 1.0.22-r0 apk
@@ -205,13 +205,13 @@ libtasn1 4.21.0-r0 apk
libunistring 1.4.2-r0 apk libunistring 1.4.2-r0 apk
libuuid 2.42.3-r1 apk libuuid 2.42.3-r1 apk
libwebp 1.6.0-r0 apk libwebp 1.6.0-r0 apk
libx11 1.8.13-r0 apk libx11 1.8.14-r0 apk
libxau 1.0.12-r0 apk libxau 1.0.12-r0 apk
libxcb 1.17.0-r2 apk libxcb 1.17.0-r2 apk
libxdmcp 1.1.5-r1 apk libxdmcp 1.1.5-r1 apk
libxext 1.3.7-r0 apk libxext 1.3.7-r0 apk
libxml2 2.13.9-r2 apk libxml2 2.13.9-r2 apk
libxpm 3.5.19-r0 apk libxpm 3.5.20-r0 apk
libxslt 1.1.43-r3 apk libxslt 1.1.43-r3 apk
libxt 1.3.1-r0 apk libxt 1.3.1-r0 apk
libxtables 1.8.13-r0 apk libxtables 1.8.13-r0 apk
@@ -235,7 +235,7 @@ nano 9.2-r0 apk
ncurses-terminfo-base 6.6_p20260516-r0 apk ncurses-terminfo-base 6.6_p20260516-r0 apk
netcat-openbsd 1.234.1-r0 apk netcat-openbsd 1.234.1-r0 apk
nettle 3.10.2-r0 apk nettle 3.10.2-r0 apk
nghttp2-libs 1.69.0-r0 apk nghttp2-libs 1.70.0-r0 apk
nginx 1.30.4-r1 apk nginx 1.30.4-r1 apk
nginx-mod-devel-kit 1.30.4-r1 apk nginx-mod-devel-kit 1.30.4-r1 apk
nginx-mod-http-brotli 1.30.4-r1 apk nginx-mod-http-brotli 1.30.4-r1 apk
@@ -258,12 +258,11 @@ nginx-vim 1.30.4-r1 apk
npth 1.8-r0 apk npth 1.8-r0 apk
oniguruma 6.9.10-r0 apk oniguruma 6.9.10-r0 apk
openssl 3.5.9-r0 apk openssl 3.5.9-r0 apk
opentelemetry-api 1.45.0 python opentelemetry-api 1.45.1 python
p11-kit 0.26.2-r0 apk p11-kit 0.26.2-r0 apk
packaging 26.0 python packaging 26.3 python (+1 duplicate)
packaging 26.3 python
parsedatetime 2.6 python parsedatetime 2.6 python
pcre2 10.48-r0 apk pcre2 10.49-r0 apk
perl 5.42.2-r1 apk perl 5.42.2-r1 apk
perl-error 0.17030-r0 apk perl-error 0.17030-r0 apk
perl-git 2.54.0-r0 apk perl-git 2.54.0-r0 apk
@@ -325,15 +324,15 @@ pyacmedns 0.4 python
pyasn1 0.6.4 python pyasn1 0.6.4 python
pyasn1-modules 0.4.2 python pyasn1-modules 0.4.2 python
pyc 3.14.8-r0 apk pyc 3.14.8-r0 apk
pycparser 3.0 python pycparser 3.11 python
pydantic 2.13.5 python pydantic 2.14.1 python
pydantic-core 2.46.5 python pydantic-core 2.50.1 python
pyjwt 2.15.1 python pyjwt 2.15.1 python
pynamecheap 0.0.3 python pynamecheap 0.0.3 python
pyopenssl 26.4.0 python pyopenssl 26.4.0 python
pyotp 2.10.0 python pyotp 2.10.0 python
pyparsing 3.3.3 python pyparsing 3.3.3 python
pyrfc3339 2.1.0 python pyrfc3339 2.1.1 python
python-dateutil 2.9.0.post0 python python-dateutil 2.9.0.post0 python
python-digitalocean 1.17.0 python python-digitalocean 1.17.0 python
python-transip 0.6.0 python python-transip 0.6.0 python
@@ -346,22 +345,22 @@ requests 2.34.2 python
requests-file 3.0.1 python requests-file 3.0.1 python
requests-mock 1.12.1 python requests-mock 1.12.1 python
requests-unixsocket 0.4.1 python requests-unixsocket 0.4.1 python
s3transfer 0.19.2 python s3transfer 0.19.3 python
scanelf 1.3.9-r1 apk scanelf 1.3.9-r1 apk
setuptools 84.0.0 python setuptools 84.2.0 python
shadow 4.18.0-r1 apk shadow 4.18.0-r1 apk
six 1.17.0 python six 1.17.0 python
skalibs-libs 2.15.0.0-r0 apk skalibs-libs 2.15.0.0-r0 apk
sniffio 1.3.1 python sniffio 1.3.1 python
soupsieve 2.10 python soupsieve 3.0.3 python
sqlite-libs 3.53.4-r0 apk sqlite-libs 3.53.4-r0 apk
ssl_client 1.37.0-r31 apk ssl_client 1.37.0-r31 apk
tiff 4.7.1-r0 apk tiff 4.7.2-r0 apk
tldextract 5.3.2 python tldextract 5.4.0 python
tomli 2.4.0 python tomli 2.4.0 python
typing-extensions 4.16.0 python typing-extensions 4.16.0 python
typing-inspection 0.4.4 python typing-inspection 0.4.4 python
tzdata 2026d-r0 apk tzdata 2026e-r0 apk
unixodbc 2.3.14-r1 apk unixodbc 2.3.14-r1 apk
uritemplate 4.2.0 python uritemplate 4.2.0 python
urllib3 2.8.0 python urllib3 2.8.0 python
@@ -371,6 +370,6 @@ wheel 0.48.0 python
whois 5.6.6-r0 apk whois 5.6.6-r0 apk
xz-libs 5.8.4-r0 apk xz-libs 5.8.4-r0 apk
zipp 3.23.0 python zipp 3.23.0 python
zlib 1.3.2-r0 apk zlib 1.3.2-r1 apk
zope-interface 8.6 python zope-interface 8.7 python
zstd-libs 1.5.7-r2 apk zstd-libs 1.5.7-r2 apk
+1
View File
@@ -220,6 +220,7 @@ init_diagram: |
"swag:latest" <- Base Images "swag:latest" <- Base Images
# changelog # changelog
changelogs: changelogs:
- {date: "20.10.26:", desc: "[Existing users should update:](https://github.com/linuxserver/docker-swag/blob/master/README.md#updating-configs) proxy.conf, authelia-server.conf, authentik-server.conf, tinyauth-server.conf - Update Nginx configuration to replace $http_host with $host$is_request_port$request_port for better compatibility."}
- {date: "09.09.26:", desc: "Use new X-Tinyauth-Location header in Tinyauth locations and remove duplicate auth module headers."} - {date: "09.09.26:", desc: "Use new X-Tinyauth-Location header in Tinyauth locations and remove duplicate auth module headers."}
- {date: "19.07.26:", desc: "Rebase to Alpine 3.24 with PHP 8.5."} - {date: "19.07.26:", desc: "Rebase to Alpine 3.24 with PHP 8.5."}
- {date: "10.07.26:", desc: "Add support for Let's Encrypt cert profiles. Run certbot twice daily with a random delay."} - {date: "10.07.26:", desc: "Add support for Let's Encrypt cert profiles. Run certbot twice daily with a random delay."}
@@ -1,4 +1,4 @@
## Version 2025/03/25 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/authelia-server.conf.sample ## Version 2026/10/20 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/authelia-server.conf.sample
# Make sure that your authelia container is in the same user defined bridge network and is named authelia # Make sure that your authelia container is in the same user defined bridge network and is named authelia
# Rename /config/nginx/proxy-confs/authelia.subdomain.conf.sample to /config/nginx/proxy-confs/authelia.subdomain.conf # Rename /config/nginx/proxy-confs/authelia.subdomain.conf.sample to /config/nginx/proxy-confs/authelia.subdomain.conf
@@ -28,7 +28,7 @@ location @authelia_proxy_signin {
add_header Set-Cookie $set_cookie; add_header Set-Cookie $set_cookie;
## Set the $target_url variable based on the original request ## Set the $target_url variable based on the original request
set_escape_uri $target_url $scheme://$http_host$request_uri; set_escape_uri $target_url $scheme://$host$is_request_port$request_port$request_uri;
## Translate the Location response header from the auth subrequest into a variable ## Translate the Location response header from the auth subrequest into a variable
auth_request_set $signin_url $upstream_http_location; auth_request_set $signin_url $upstream_http_location;
@@ -1,4 +1,4 @@
## Version 2025/03/25 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/authentik-server.conf.sample ## Version 2026/10/20 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/authentik-server.conf.sample
# Make sure that your authentik container is in the same user defined bridge network and is named authentik-server # Make sure that your authentik container is in the same user defined bridge network and is named authentik-server
# Rename /config/nginx/proxy-confs/authentik.subdomain.conf.sample to /config/nginx/proxy-confs/authentik.subdomain.conf # Rename /config/nginx/proxy-confs/authentik.subdomain.conf.sample to /config/nginx/proxy-confs/authentik.subdomain.conf
@@ -38,10 +38,10 @@ location @goauthentik_proxy_signin {
add_header Set-Cookie $set_cookie; add_header Set-Cookie $set_cookie;
## Set the $target_url variable based on the original request ## Set the $target_url variable based on the original request
set_escape_uri $target_url $scheme://$http_host$request_uri; set_escape_uri $target_url $scheme://$host$is_request_port$request_port$request_uri;
## Set the $signin_url variable ## Set the $signin_url variable
set $signin_url https://$http_host/outpost.goauthentik.io/start?rd=$target_url; set $signin_url https://$host$is_request_port$request_port/outpost.goauthentik.io/start?rd=$target_url;
## Redirect to login ## Redirect to login
return 302 $signin_url; return 302 $signin_url;
+6 -6
View File
@@ -1,4 +1,4 @@
## Version 2023/02/09 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/proxy.conf.sample ## Version 2026/10/20 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/proxy.conf.sample
# Timeout if the real server is dead # Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
@@ -21,17 +21,17 @@ proxy_no_cache $cookie_session;
# Proxy Header Settings # Proxy Header Settings
proxy_set_header Connection $connection_upgrade; proxy_set_header Connection $connection_upgrade;
proxy_set_header Early-Data $ssl_early_data; proxy_set_header Early-Data $ssl_early_data;
proxy_set_header Host $host; proxy_set_header Host $host; # NOTE: only use $host here, port is handled separately
proxy_set_header Proxy ""; proxy_set_header Proxy "";
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Host $host; # NOTE: only use $host here, port is handled separately
proxy_set_header X-Forwarded-Method $request_method; proxy_set_header X-Forwarded-Method $request_method;
proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Port $request_port;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-Server $host; # NOTE: only use $host here, port is handled separately
proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-Uri $request_uri; proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Original-Method $request_method; proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri; proxy_set_header X-Original-URL $scheme://$host$is_request_port$request_port$request_uri;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
@@ -1,4 +1,4 @@
## Version 2026/03/07 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/site-confs/default.conf.sample ## Version 2026/10/20 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/site-confs/default.conf.sample
# redirect all traffic to https # redirect all traffic to https
server { server {
@@ -7,6 +7,11 @@ server {
location / { location / {
return 301 https://$host$request_uri; return 301 https://$host$request_uri;
# NOTE FOR USERS: If your external HTTP and HTTPS ports are asymmetrical
# (e.g., External 8443 maps to Nginx 443),
# replace the return above this one and hardcode your external HTTPS port:
# return 301 https://$host:8443$request_uri;
} }
} }
@@ -1,4 +1,4 @@
## Version 2026/09/08 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/tinyauth-server.conf.sample ## Version 2026/10/20 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/tinyauth-server.conf.sample
# Make sure that your tinyauth container is in the same user defined bridge network and is named tinyauth # Make sure that your tinyauth container is in the same user defined bridge network and is named tinyauth
# Rename /config/nginx/proxy-confs/tinyauth.subdomain.conf.sample to /config/nginx/proxy-confs/tinyauth.subdomain.conf # Rename /config/nginx/proxy-confs/tinyauth.subdomain.conf.sample to /config/nginx/proxy-confs/tinyauth.subdomain.conf
@@ -15,7 +15,7 @@ location /tinyauth {
proxy_set_header Content-Length ""; proxy_set_header Content-Length "";
# Headers needed for authentication # Headers needed for authentication
proxy_set_header X-Original-URL $scheme://$http_host$request_uri; proxy_set_header X-Original-URL $scheme://$host$is_request_port$request_port$request_uri;
proxy_set_header X-Original-Method $request_method; proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;