Compare commits

..

2 Commits

Author SHA1 Message Date
aptalca
732b6d1bf1 pin cryptography 2024-09-10 13:06:02 -04:00
aptalca
0c3bc63349 overwrite renewal hook, add notice about it, increase verbosity 2024-09-10 12:25:06 -04:00
72 changed files with 929 additions and 1405 deletions

0
.editorconfig Normal file → Executable file
View File

View File

@@ -6,7 +6,7 @@
* Read, and fill the Pull Request template * Read, and fill the Pull Request template
* 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
* If the PR is addressing an existing issue include, closes #\<issue number>, in the body of the PR commit message * If the PR is addressing an existing issue include, closes #\<issue number>, in the body of the PR commit message
* If you want to discuss changes, you can also bring it up in [#dev-talk](https://discordapp.com/channels/354974912613449730/757585807061155840) in our [Discord server](https://linuxserver.io/discord) * If you want to discuss changes, you can also bring it up in [#dev-talk](https://discordapp.com/channels/354974912613449730/757585807061155840) in our [Discord server](https://discord.gg/YWrKVTn)
## Common files ## Common files
@@ -105,10 +105,10 @@ docker build \
-t linuxserver/swag:latest . -t linuxserver/swag:latest .
``` ```
The ARM variants can be built on x86_64 hardware and vice versa using `lscr.io/linuxserver/qemu-static` The ARM variants can be built on x86_64 hardware using `multiarch/qemu-user-static`
```bash ```bash
docker run --rm --privileged lscr.io/linuxserver/qemu-static --reset docker run --rm --privileged multiarch/qemu-user-static:register --reset
``` ```
Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64`. Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64`.

0
.github/FUNDING.yml vendored Normal file → Executable file
View File

2
.github/ISSUE_TEMPLATE/config.yml vendored Normal file → Executable file
View File

@@ -1,7 +1,7 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: Discord chat support - name: Discord chat support
url: https://linuxserver.io/discord url: https://discord.gg/YWrKVTn
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: Discourse discussion forum

0
.github/ISSUE_TEMPLATE/issue.bug.yml vendored Normal file → Executable file
View File

0
.github/ISSUE_TEMPLATE/issue.feature.yml vendored Normal file → Executable file
View File

3
.github/workflows/call_issue_pr_tracker.yml vendored Normal file → Executable file
View File

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

3
.github/workflows/call_issues_cron.yml vendored Normal file → Executable file
View File

@@ -4,9 +4,6 @@ on:
- cron: '35 15 * * *' - cron: '35 15 * * *'
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
stale: stale:
permissions: permissions:

View File

@@ -3,9 +3,6 @@ name: External Trigger Main
on: on:
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
external-trigger-master: external-trigger-master:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -14,28 +11,18 @@ jobs:
- name: External Trigger - name: External Trigger
if: github.ref == 'refs/heads/master' if: github.ref == 'refs/heads/master'
env:
SKIP_EXTERNAL_TRIGGER: ${{ vars.SKIP_EXTERNAL_TRIGGER }}
run: | run: |
printf "# External trigger for docker-swag\n\n" >> $GITHUB_STEP_SUMMARY printf "# External trigger for docker-swag\n\n" >> $GITHUB_STEP_SUMMARY
if grep -q "^swag_master_" <<< "${SKIP_EXTERNAL_TRIGGER}"; then if [ -n "${{ secrets.PAUSE_EXTERNAL_TRIGGER_SWAG_MASTER }}" ]; then
echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY
echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` contains \`swag_master_\`; will skip trigger if version matches." >> $GITHUB_STEP_SUMMARY
elif grep -q "^swag_master" <<< "${SKIP_EXTERNAL_TRIGGER}"; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` contains \`swag_master\`; skipping trigger." >> $GITHUB_STEP_SUMMARY echo "> Github secret \`PAUSE_EXTERNAL_TRIGGER_SWAG_MASTER\` is set; skipping trigger." >> $GITHUB_STEP_SUMMARY
exit 0 exit 0
fi fi
echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY
echo "> External trigger running off of master branch. To disable this trigger, add \`swag_master\` into the Github organizational variable \`SKIP_EXTERNAL_TRIGGER\`." >> $GITHUB_STEP_SUMMARY echo "> External trigger running off of master branch. To disable this trigger, set a Github secret named \`PAUSE_EXTERNAL_TRIGGER_SWAG_MASTER\`" >> $GITHUB_STEP_SUMMARY
printf "\n## Retrieving external version\n\n" >> $GITHUB_STEP_SUMMARY printf "\n## Retrieving external version\n\n" >> $GITHUB_STEP_SUMMARY
EXT_RELEASE=$(curl -sL "https://pypi.python.org/pypi/certbot/json" |jq -r '. | .info.version') EXT_RELEASE=$(curl -sL "https://pypi.python.org/pypi/certbot/json" |jq -r '. | .info.version')
echo "Type is \`pip_version\`" >> $GITHUB_STEP_SUMMARY echo "Type is \`pip_version\`" >> $GITHUB_STEP_SUMMARY
if grep -q "^swag_master_${EXT_RELEASE}" <<< "${SKIP_EXTERNAL_TRIGGER}"; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` matches current external release; skipping trigger." >> $GITHUB_STEP_SUMMARY
exit 0
fi
if [ -z "${EXT_RELEASE}" ] || [ "${EXT_RELEASE}" == "null" ]; then if [ -z "${EXT_RELEASE}" ] || [ "${EXT_RELEASE}" == "null" ]; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> Can't retrieve external version, exiting" >> $GITHUB_STEP_SUMMARY echo "> Can't retrieve external version, exiting" >> $GITHUB_STEP_SUMMARY
@@ -46,8 +33,8 @@ jobs:
"username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }}
exit 1 exit 1
fi fi
EXT_RELEASE_SANITIZED=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g') EXT_RELEASE=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g')
echo "Sanitized external version: \`${EXT_RELEASE_SANITIZED}\`" >> $GITHUB_STEP_SUMMARY echo "External version: \`${EXT_RELEASE}\`" >> $GITHUB_STEP_SUMMARY
echo "Retrieving last pushed version" >> $GITHUB_STEP_SUMMARY echo "Retrieving last pushed version" >> $GITHUB_STEP_SUMMARY
image="linuxserver/swag" image="linuxserver/swag"
tag="latest" tag="latest"
@@ -56,33 +43,14 @@ jobs:
| jq -r '.token') | jq -r '.token')
multidigest=$(curl -s \ multidigest=$(curl -s \
--header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
--header "Accept: application/vnd.oci.image.index.v1+json" \
--header "Authorization: Bearer ${token}" \ --header "Authorization: Bearer ${token}" \
"https://ghcr.io/v2/${image}/manifests/${tag}") "https://ghcr.io/v2/${image}/manifests/${tag}" \
if jq -e '.layers // empty' <<< "${multidigest}" >/dev/null 2>&1; then | jq -r 'first(.manifests[].digest)')
# If there's a layer element it's a single-arch manifest so just get that digest digest=$(curl -s \
digest=$(jq -r '.config.digest' <<< "${multidigest}")
else
# Otherwise it's multi-arch or has manifest annotations
if jq -e '.manifests[]?.annotations // empty' <<< "${multidigest}" >/dev/null 2>&1; then
# Check for manifest annotations and delete if found
multidigest=$(jq 'del(.manifests[] | select(.annotations))' <<< "${multidigest}")
fi
if [[ $(jq '.manifests | length' <<< "${multidigest}") -gt 1 ]]; then
# If there's still more than one digest, it's multi-arch
multidigest=$(jq -r ".manifests[] | select(.platform.architecture == \"amd64\").digest?" <<< "${multidigest}")
else
# Otherwise it's single arch
multidigest=$(jq -r ".manifests[].digest?" <<< "${multidigest}")
fi
if digest=$(curl -s \
--header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
--header "Accept: application/vnd.oci.image.manifest.v1+json" \
--header "Authorization: Bearer ${token}" \ --header "Authorization: Bearer ${token}" \
"https://ghcr.io/v2/${image}/manifests/${multidigest}"); then "https://ghcr.io/v2/${image}/manifests/${multidigest}" \
digest=$(jq -r '.config.digest' <<< "${digest}"); | jq -r '.config.digest')
fi
fi
image_info=$(curl -sL \ image_info=$(curl -sL \
--header "Authorization: Bearer ${token}" \ --header "Authorization: Bearer ${token}" \
"https://ghcr.io/v2/${image}/blobs/${digest}") "https://ghcr.io/v2/${image}/blobs/${digest}")
@@ -103,26 +71,15 @@ jobs:
exit 1 exit 1
fi fi
echo "Last pushed version: \`${IMAGE_VERSION}\`" >> $GITHUB_STEP_SUMMARY echo "Last pushed version: \`${IMAGE_VERSION}\`" >> $GITHUB_STEP_SUMMARY
if [ "${EXT_RELEASE_SANITIZED}" == "${IMAGE_VERSION}" ]; then if [ "${EXT_RELEASE}" == "${IMAGE_VERSION}" ]; then
echo "Sanitized version \`${EXT_RELEASE_SANITIZED}\` already pushed, exiting" >> $GITHUB_STEP_SUMMARY echo "Version \`${EXT_RELEASE}\` already pushed, exiting" >> $GITHUB_STEP_SUMMARY
exit 0 exit 0
elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/master/lastBuild/api/json | jq -r '.building') == "true" ]; then elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/master/lastBuild/api/json | jq -r '.building') == "true" ]; then
echo "New version \`${EXT_RELEASE}\` found; but there already seems to be an active build on Jenkins; exiting" >> $GITHUB_STEP_SUMMARY echo "New version \`${EXT_RELEASE}\` found; but there already seems to be an active build on Jenkins; exiting" >> $GITHUB_STEP_SUMMARY
exit 0 exit 0
else
if [[ "${artifacts_found}" == "false" ]]; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> New version detected, but not all artifacts are published yet; skipping trigger" >> $GITHUB_STEP_SUMMARY
FAILURE_REASON="New version ${EXT_RELEASE} for swag tag latest is detected, however not all artifacts are uploaded to upstream release yet. Will try again later."
curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903,
"description": "**Trigger Failed** \n**Reason:** '"${FAILURE_REASON}"' \n"}],
"username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }}
else else
printf "\n## Trigger new build\n\n" >> $GITHUB_STEP_SUMMARY printf "\n## Trigger new build\n\n" >> $GITHUB_STEP_SUMMARY
echo "New sanitized version \`${EXT_RELEASE_SANITIZED}\` found; old version was \`${IMAGE_VERSION}\`. Triggering new build" >> $GITHUB_STEP_SUMMARY echo "New version \`${EXT_RELEASE}\` 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
response=$(curl -iX POST \ response=$(curl -iX POST \
https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/master/buildWithParameters?PACKAGE_CHECK=false \ https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/master/buildWithParameters?PACKAGE_CHECK=false \
--user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|")
@@ -139,9 +96,8 @@ jobs:
--data-urlencode "description=GHA external trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ --data-urlencode "description=GHA external trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
--data-urlencode "Submit=Submit" --data-urlencode "Submit=Submit"
echo "**** Notifying Discord ****" echo "**** Notifying Discord ****"
TRIGGER_REASON="A version change was detected for swag tag latest. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE_SANITIZED}" TRIGGER_REASON="A version change was detected for swag tag latest. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE}"
curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, 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"}], "description": "**Build Triggered** \n**Reason:** '"${TRIGGER_REASON}"' \n**Build URL:** '"${buildurl}display/redirect"' \n"}],
"username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }}
fi fi
fi

View File

@@ -5,9 +5,6 @@ on:
- cron: '2 * * * *' - cron: '2 * * * *'
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
external-trigger-scheduler: external-trigger-scheduler:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

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

42
.github/workflows/package_trigger.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Package Trigger Main
on:
workflow_dispatch:
jobs:
package-trigger-master:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.1.1
- name: Package Trigger
if: github.ref == 'refs/heads/master'
run: |
printf "# Package trigger for docker-swag\n\n" >> $GITHUB_STEP_SUMMARY
if [ -n "${{ secrets.PAUSE_PACKAGE_TRIGGER_SWAG_MASTER }}" ]; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> Github secret \`PAUSE_PACKAGE_TRIGGER_SWAG_MASTER\` is set; skipping trigger." >> $GITHUB_STEP_SUMMARY
exit 0
fi
if [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/master/lastBuild/api/json | jq -r '.building') == "true" ]; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> There already seems to be an active build on Jenkins; skipping package trigger" >> $GITHUB_STEP_SUMMARY
exit 0
fi
echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY
echo "> Package trigger running off of master branch. To disable, set a Github secret named \`PAUSE_PACKAGE_TRIGGER_SWAG_MASTER\`" >> $GITHUB_STEP_SUMMARY
response=$(curl -iX POST \
https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/master/buildWithParameters?PACKAGE_CHECK=true \
--user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|")
echo "Jenkins [job queue url](${response%$'\r'})" >> $GITHUB_STEP_SUMMARY
echo "Sleeping 10 seconds until job starts" >> $GITHUB_STEP_SUMMARY
sleep 10
buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url')
buildurl="${buildurl%$'\r'}"
echo "Jenkins job [build url](${buildurl})" >> $GITHUB_STEP_SUMMARY
echo "Attempting to change the Jenkins job description" >> $GITHUB_STEP_SUMMARY
curl -iX POST \
"${buildurl}submitDescription" \
--user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \
--data-urlencode "description=GHA package trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
--data-urlencode "Submit=Submit"

View File

@@ -5,9 +5,6 @@ on:
- cron: '1 3 * * 6' - cron: '1 3 * * 6'
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
package-trigger-scheduler: package-trigger-scheduler:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -17,8 +14,6 @@ jobs:
fetch-depth: '0' fetch-depth: '0'
- name: Package Trigger Scheduler - name: Package Trigger Scheduler
env:
SKIP_PACKAGE_TRIGGER: ${{ vars.SKIP_PACKAGE_TRIGGER }}
run: | run: |
printf "# Package trigger scheduler for docker-swag\n\n" >> $GITHUB_STEP_SUMMARY printf "# Package trigger scheduler for docker-swag\n\n" >> $GITHUB_STEP_SUMMARY
printf "Found the branches:\n\n%s\n" "$(git for-each-ref --format='- %(refname:lstrip=3)' refs/remotes)" >> $GITHUB_STEP_SUMMARY printf "Found the branches:\n\n%s\n" "$(git for-each-ref --format='- %(refname:lstrip=3)' refs/remotes)" >> $GITHUB_STEP_SUMMARY
@@ -29,75 +24,27 @@ jobs:
continue continue
fi fi
printf "\n## Evaluating \`%s\`\n\n" ${br} >> $GITHUB_STEP_SUMMARY printf "\n## Evaluating \`%s\`\n\n" ${br} >> $GITHUB_STEP_SUMMARY
JENKINS_VARS=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-swag/${br}/jenkins-vars.yml) ls_branch=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-swag/${br}/jenkins-vars.yml | yq -r '.ls_branch')
if ! curl -sfX GET https://raw.githubusercontent.com/linuxserver/docker-swag/${br}/Jenkinsfile >/dev/null 2>&1; then if [ "${br}" == "${ls_branch}" ]; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> No Jenkinsfile found. Branch is either deprecated or is an early dev branch." >> $GITHUB_STEP_SUMMARY
skipped_branches="${skipped_branches}${br} "
elif [[ "${br}" == $(yq -r '.ls_branch' <<< "${JENKINS_VARS}") ]]; then
echo "Branch appears to be live; checking workflow." >> $GITHUB_STEP_SUMMARY echo "Branch appears to be live; checking workflow." >> $GITHUB_STEP_SUMMARY
README_VARS=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-swag/${br}/readme-vars.yml) if curl -sfX GET https://raw.githubusercontent.com/linuxserver/docker-swag/${br}/.github/workflows/package_trigger.yml > /dev/null 2>&1; then
if [[ $(yq -r '.project_deprecation_status' <<< "${README_VARS}") == "true" ]]; then echo "Triggering package trigger workflow for branch ${br}" >> $GITHUB_STEP_SUMMARY
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> Branch appears to be deprecated; skipping trigger." >> $GITHUB_STEP_SUMMARY
skipped_branches="${skipped_branches}${br} "
elif [[ $(yq -r '.skip_package_check' <<< "${JENKINS_VARS}") == "true" ]]; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> Skipping branch ${br} due to \`skip_package_check\` being set in \`jenkins-vars.yml\`." >> $GITHUB_STEP_SUMMARY
skipped_branches="${skipped_branches}${br} "
elif grep -q "^swag_${br}" <<< "${SKIP_PACKAGE_TRIGGER}"; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> Github organizational variable \`SKIP_PACKAGE_TRIGGER\` contains \`swag_${br}\`; skipping trigger." >> $GITHUB_STEP_SUMMARY
skipped_branches="${skipped_branches}${br} "
elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/${br}/lastBuild/api/json | jq -r '.building' 2>/dev/null) == "true" ]; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> There already seems to be an active build on Jenkins; skipping package trigger for ${br}" >> $GITHUB_STEP_SUMMARY
skipped_branches="${skipped_branches}${br} "
else
echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY
echo "> Triggering package trigger for branch ${br}" >> $GITHUB_STEP_SUMMARY
printf "> To disable, add \`swag_%s\` into the Github organizational variable \`SKIP_PACKAGE_TRIGGER\`.\n\n" "${br}" >> $GITHUB_STEP_SUMMARY
triggered_branches="${triggered_branches}${br} " triggered_branches="${triggered_branches}${br} "
response=$(curl -iX POST \ curl -iX POST \
https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/${br}/buildWithParameters?PACKAGE_CHECK=true \ -H "Authorization: token ${{ secrets.CR_PAT }}" \
--user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") -H "Accept: application/vnd.github.v3+json" \
if [[ -z "${response}" ]]; then -d "{\"ref\":\"refs/heads/${br}\"}" \
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY https://api.github.com/repos/linuxserver/docker-swag/actions/workflows/package_trigger.yml/dispatches
echo "> Jenkins build could not be triggered. Skipping branch." sleep 30
continue else
fi echo "Skipping branch ${br} due to no package trigger workflow present." >> $GITHUB_STEP_SUMMARY
echo "Jenkins [job queue url](${response%$'\r'})" >> $GITHUB_STEP_SUMMARY
echo "Sleeping 10 seconds until job starts" >> $GITHUB_STEP_SUMMARY
sleep 10
buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url')
buildurl="${buildurl%$'\r'}"
echo "Jenkins job [build url](${buildurl})" >> $GITHUB_STEP_SUMMARY
echo "Attempting to change the Jenkins job description" >> $GITHUB_STEP_SUMMARY
if ! curl -ifX POST \
"${buildurl}submitDescription" \
--user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \
--data-urlencode "description=GHA package trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
--data-urlencode "Submit=Submit"; then
echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY
echo "> Unable to change the Jenkins job description."
fi
sleep 20
fi fi
else else
echo "Skipping branch ${br} due to being detected as dev branch." >> $GITHUB_STEP_SUMMARY echo "Skipping branch ${br} due to being detected as dev branch." >> $GITHUB_STEP_SUMMARY
fi fi
done done
if [[ -n "${triggered_branches}" ]] || [[ -n "${skipped_branches}" ]]; then
if [[ -n "${triggered_branches}" ]]; then
NOTIFY_BRANCHES="**Triggered:** ${triggered_branches} \n"
NOTIFY_BUILD_URL="**Build URL:** https://ci.linuxserver.io/blue/organizations/jenkins/Docker-Pipeline-Builders%2Fdocker-swag/activity/ \n"
echo "**** Package check build(s) triggered for branch(es): ${triggered_branches} ****" echo "**** Package check build(s) triggered for branch(es): ${triggered_branches} ****"
fi
if [[ -n "${skipped_branches}" ]]; then
NOTIFY_BRANCHES="${NOTIFY_BRANCHES}**Skipped:** ${skipped_branches} \n"
fi
echo "**** Notifying Discord ****" echo "**** Notifying Discord ****"
curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903,
"description": "**Package Check Build(s) for swag** \n'"${NOTIFY_BRANCHES}"''"${NOTIFY_BUILD_URL}"'"}], "description": "**Package Check Build(s) Triggered for swag** \n**Branch(es):** '"${triggered_branches}"' \n**Build URL:** '"https://ci.linuxserver.io/blue/organizations/jenkins/Docker-Pipeline-Builders%2Fdocker-swag/activity/"' \n"}],
"username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }}
fi

0
.github/workflows/permissions.yml vendored Normal file → Executable file
View File

1
.gitignore vendored
View File

@@ -1,2 +1 @@
.idea
.jenkins-external .jenkins-external

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM ghcr.io/linuxserver/baseimage-alpine-nginx:3.22 FROM ghcr.io/linuxserver/baseimage-alpine-nginx:3.20
# set version label # set version label
ARG BUILD_DATE ARG BUILD_DATE
@@ -10,10 +10,8 @@ LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DA
LABEL maintainer="nemchik" LABEL maintainer="nemchik"
# environment settings # environment settings
ENV DHLEVEL=2048 \ ENV DHLEVEL=2048 ONLY_SUBDOMAINS=false AWS_CONFIG_FILE=/config/dns-conf/route53.ini
ONLY_SUBDOMAINS=false \ ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2
AWS_CONFIG_FILE=/config/dns-conf/route53.ini \
S6_BEHAVIOUR_IF_STAGE2_FAILS=2
RUN \ RUN \
echo "**** install build packages ****" && \ echo "**** install build packages ****" && \
@@ -29,7 +27,6 @@ RUN \
apk add --no-cache \ apk add --no-cache \
fail2ban \ fail2ban \
gnupg \ gnupg \
inotify-tools \
iptables-legacy \ iptables-legacy \
memcached \ memcached \
nginx-mod-http-brotli \ nginx-mod-http-brotli \
@@ -49,36 +46,37 @@ RUN \
nginx-mod-stream \ nginx-mod-stream \
nginx-mod-stream-geoip2 \ nginx-mod-stream-geoip2 \
nginx-vim \ nginx-vim \
php84-bcmath \ php83-bcmath \
php84-bz2 \ php83-bz2 \
php84-dom \ php83-dom \
php84-exif \ php83-exif \
php84-ftp \ php83-ftp \
php84-gd \ php83-gd \
php84-gmp \ php83-gmp \
php84-imap \ php83-imap \
php84-intl \ php83-intl \
php84-ldap \ php83-ldap \
php84-mysqli \ php83-mysqli \
php84-mysqlnd \ php83-mysqlnd \
php84-opcache \ php83-opcache \
php84-pdo_mysql \ php83-pdo_mysql \
php84-pdo_odbc \ php83-pdo_odbc \
php84-pdo_pgsql \ php83-pdo_pgsql \
php84-pdo_sqlite \ php83-pdo_sqlite \
php84-pear \ php83-pear \
php84-pecl-apcu \ php83-pecl-apcu \
php84-pecl-memcached \ php83-pecl-mcrypt \
php84-pecl-redis \ php83-pecl-memcached \
php84-pgsql \ php83-pecl-redis \
php84-posix \ php83-pgsql \
php84-soap \ php83-posix \
php84-sockets \ php83-soap \
php84-sodium \ php83-sockets \
php84-sqlite3 \ php83-sodium \
php84-tokenizer \ php83-sqlite3 \
php84-xmlreader \ php83-tokenizer \
php84-xsl \ php83-xmlreader \
php83-xsl \
whois && \ whois && \
echo "**** install certbot plugins ****" && \ echo "**** install certbot plugins ****" && \
if [ -z ${CERTBOT_VERSION+x} ]; then \ if [ -z ${CERTBOT_VERSION+x} ]; then \
@@ -88,7 +86,7 @@ RUN \
pip install -U --no-cache-dir \ pip install -U --no-cache-dir \
pip \ pip \
wheel && \ wheel && \
pip install -U --no-cache-dir --find-links https://wheel-index.linuxserver.io/alpine-3.22/ \ pip install -U --no-cache-dir --find-links https://wheel-index.linuxserver.io/alpine-3.20/ \
certbot==${CERTBOT_VERSION} \ certbot==${CERTBOT_VERSION} \
certbot-dns-acmedns \ certbot-dns-acmedns \
certbot-dns-aliyun \ certbot-dns-aliyun \
@@ -114,7 +112,6 @@ RUN \
certbot-dns-google \ certbot-dns-google \
certbot-dns-he \ certbot-dns-he \
certbot-dns-hetzner \ certbot-dns-hetzner \
certbot-dns-hetzner-cloud \
certbot-dns-infomaniak \ certbot-dns-infomaniak \
certbot-dns-inwx \ certbot-dns-inwx \
certbot-dns-ionos \ certbot-dns-ionos \
@@ -134,7 +131,7 @@ RUN \
certbot-dns-transip \ certbot-dns-transip \
certbot-dns-vultr \ certbot-dns-vultr \
certbot-plugin-gandi \ certbot-plugin-gandi \
cryptography \ cryptography==42.0.7 \
future \ future \
requests && \ requests && \
echo "**** enable OCSP stapling from base ****" && \ echo "**** enable OCSP stapling from base ****" && \
@@ -151,9 +148,9 @@ RUN \
rm -f /etc/nginx/conf.d/stream.conf && \ rm -f /etc/nginx/conf.d/stream.conf && \
echo "**** correct ip6tables legacy issue ****" && \ echo "**** correct ip6tables legacy issue ****" && \
rm \ rm \
/usr/sbin/ip6tables && \ /sbin/ip6tables && \
ln -s \ ln -s \
/usr/sbin/ip6tables-nft /usr/sbin/ip6tables && \ /sbin/ip6tables-nft /sbin/ip6tables && \
echo "**** remove unnecessary fail2ban filters ****" && \ echo "**** remove unnecessary fail2ban filters ****" && \
rm \ rm \
/etc/fail2ban/jail.d/alpine-ssh.conf && \ /etc/fail2ban/jail.d/alpine-ssh.conf && \

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM ghcr.io/linuxserver/baseimage-alpine-nginx:arm64v8-3.22 FROM ghcr.io/linuxserver/baseimage-alpine-nginx:arm64v8-3.20
# set version label # set version label
ARG BUILD_DATE ARG BUILD_DATE
@@ -10,10 +10,8 @@ LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DA
LABEL maintainer="nemchik" LABEL maintainer="nemchik"
# environment settings # environment settings
ENV DHLEVEL=2048 \ ENV DHLEVEL=2048 ONLY_SUBDOMAINS=false AWS_CONFIG_FILE=/config/dns-conf/route53.ini
ONLY_SUBDOMAINS=false \ ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2
AWS_CONFIG_FILE=/config/dns-conf/route53.ini \
S6_BEHAVIOUR_IF_STAGE2_FAILS=2
RUN \ RUN \
echo "**** install build packages ****" && \ echo "**** install build packages ****" && \
@@ -29,7 +27,6 @@ RUN \
apk add --no-cache \ apk add --no-cache \
fail2ban \ fail2ban \
gnupg \ gnupg \
inotify-tools \
iptables-legacy \ iptables-legacy \
memcached \ memcached \
nginx-mod-http-brotli \ nginx-mod-http-brotli \
@@ -49,36 +46,37 @@ RUN \
nginx-mod-stream \ nginx-mod-stream \
nginx-mod-stream-geoip2 \ nginx-mod-stream-geoip2 \
nginx-vim \ nginx-vim \
php84-bcmath \ php83-bcmath \
php84-bz2 \ php83-bz2 \
php84-dom \ php83-dom \
php84-exif \ php83-exif \
php84-ftp \ php83-ftp \
php84-gd \ php83-gd \
php84-gmp \ php83-gmp \
php84-imap \ php83-imap \
php84-intl \ php83-intl \
php84-ldap \ php83-ldap \
php84-mysqli \ php83-mysqli \
php84-mysqlnd \ php83-mysqlnd \
php84-opcache \ php83-opcache \
php84-pdo_mysql \ php83-pdo_mysql \
php84-pdo_odbc \ php83-pdo_odbc \
php84-pdo_pgsql \ php83-pdo_pgsql \
php84-pdo_sqlite \ php83-pdo_sqlite \
php84-pear \ php83-pear \
php84-pecl-apcu \ php83-pecl-apcu \
php84-pecl-memcached \ php83-pecl-mcrypt \
php84-pecl-redis \ php83-pecl-memcached \
php84-pgsql \ php83-pecl-redis \
php84-posix \ php83-pgsql \
php84-soap \ php83-posix \
php84-sockets \ php83-soap \
php84-sodium \ php83-sockets \
php84-sqlite3 \ php83-sodium \
php84-tokenizer \ php83-sqlite3 \
php84-xmlreader \ php83-tokenizer \
php84-xsl \ php83-xmlreader \
php83-xsl \
whois && \ whois && \
echo "**** install certbot plugins ****" && \ echo "**** install certbot plugins ****" && \
if [ -z ${CERTBOT_VERSION+x} ]; then \ if [ -z ${CERTBOT_VERSION+x} ]; then \
@@ -88,7 +86,7 @@ RUN \
pip install -U --no-cache-dir \ pip install -U --no-cache-dir \
pip \ pip \
wheel && \ wheel && \
pip install -U --no-cache-dir --find-links https://wheel-index.linuxserver.io/alpine-3.22/ \ pip install -U --no-cache-dir --find-links https://wheel-index.linuxserver.io/alpine-3.20/ \
certbot==${CERTBOT_VERSION} \ certbot==${CERTBOT_VERSION} \
certbot-dns-acmedns \ certbot-dns-acmedns \
certbot-dns-aliyun \ certbot-dns-aliyun \
@@ -114,7 +112,6 @@ RUN \
certbot-dns-google \ certbot-dns-google \
certbot-dns-he \ certbot-dns-he \
certbot-dns-hetzner \ certbot-dns-hetzner \
certbot-dns-hetzner-cloud \
certbot-dns-infomaniak \ certbot-dns-infomaniak \
certbot-dns-inwx \ certbot-dns-inwx \
certbot-dns-ionos \ certbot-dns-ionos \
@@ -134,7 +131,7 @@ RUN \
certbot-dns-transip \ certbot-dns-transip \
certbot-dns-vultr \ certbot-dns-vultr \
certbot-plugin-gandi \ certbot-plugin-gandi \
cryptography \ cryptography==42.0.7 \
future \ future \
requests && \ requests && \
echo "**** enable OCSP stapling from base ****" && \ echo "**** enable OCSP stapling from base ****" && \
@@ -151,9 +148,9 @@ RUN \
rm -f /etc/nginx/conf.d/stream.conf && \ rm -f /etc/nginx/conf.d/stream.conf && \
echo "**** correct ip6tables legacy issue ****" && \ echo "**** correct ip6tables legacy issue ****" && \
rm \ rm \
/usr/sbin/ip6tables && \ /sbin/ip6tables && \
ln -s \ ln -s \
/usr/sbin/ip6tables-nft /usr/sbin/ip6tables && \ /sbin/ip6tables-nft /sbin/ip6tables && \
echo "**** remove unnecessary fail2ban filters ****" && \ echo "**** remove unnecessary fail2ban filters ****" && \
rm \ rm \
/etc/fail2ban/jail.d/alpine-ssh.conf && \ /etc/fail2ban/jail.d/alpine-ssh.conf && \

406
Jenkinsfile vendored
View File

@@ -29,12 +29,12 @@ pipeline {
PR_DOCKERHUB_IMAGE = 'lspipepr/swag' PR_DOCKERHUB_IMAGE = 'lspipepr/swag'
DIST_IMAGE = 'alpine' DIST_IMAGE = 'alpine'
MULTIARCH='true' MULTIARCH='true'
CI='false' CI='true'
CI_WEB='false' CI_WEB='false'
CI_PORT='80' CI_PORT='80'
CI_SSL='false' CI_SSL='false'
CI_DELAY='30' CI_DELAY='30'
CI_DOCKERENV='' CI_DOCKERENV='TEST_RUN=1'
CI_AUTH='' CI_AUTH=''
CI_WEBPATH='' CI_WEBPATH=''
} }
@@ -57,23 +57,11 @@ pipeline {
steps{ steps{
echo "Running on node: ${NODE_NAME}" echo "Running on node: ${NODE_NAME}"
sh '''#! /bin/bash sh '''#! /bin/bash
echo "Pruning builder" containers=$(docker ps -aq)
docker builder prune -f --builder container || :
containers=$(docker ps -q)
if [[ -n "${containers}" ]]; then if [[ -n "${containers}" ]]; then
BUILDX_CONTAINER_ID=$(docker ps -qf 'name=buildx_buildkit') docker stop ${containers}
for container in ${containers}; do
if [[ "${container}" == "${BUILDX_CONTAINER_ID}" ]]; then
echo "skipping buildx container in docker stop"
else
echo "Stopping container ${container}"
docker stop ${container}
fi fi
done docker system prune -af --volumes || : '''
fi
docker system prune -f --volumes || :
docker image prune -af || :
'''
script{ script{
env.EXIT_STATUS = '' env.EXIT_STATUS = ''
env.LS_RELEASE = sh( env.LS_RELEASE = sh(
@@ -94,12 +82,8 @@ 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 ./.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 ./.github/workflows/package_trigger.yml ./root/donate.txt'
if ( env.SYFT_IMAGE_TAG == null ) {
env.SYFT_IMAGE_TAG = 'latest'
} }
}
echo "Using syft image tag ${SYFT_IMAGE_TAG}"
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{
@@ -207,8 +191,6 @@ pipeline {
env.VERSION_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER env.VERSION_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER
env.META_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER env.META_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER
env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN
env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache'
env.CITEST_IMAGETAG = 'latest'
} }
} }
} }
@@ -233,8 +215,6 @@ pipeline {
env.META_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA env.META_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA
env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN
env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DEV_DOCKERHUB_IMAGE + '/tags/' env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DEV_DOCKERHUB_IMAGE + '/tags/'
env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache'
env.CITEST_IMAGETAG = 'develop'
} }
} }
} }
@@ -259,8 +239,6 @@ pipeline {
env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN
env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/pull/' + env.PULL_REQUEST env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/pull/' + env.PULL_REQUEST
env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.PR_DOCKERHUB_IMAGE + '/tags/' env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.PR_DOCKERHUB_IMAGE + '/tags/'
env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache'
env.CITEST_IMAGETAG = 'develop'
} }
} }
} }
@@ -283,7 +261,7 @@ pipeline {
-v ${WORKSPACE}:/mnt \ -v ${WORKSPACE}:/mnt \
-e AWS_ACCESS_KEY_ID=\"${S3_KEY}\" \ -e AWS_ACCESS_KEY_ID=\"${S3_KEY}\" \
-e AWS_SECRET_ACCESS_KEY=\"${S3_SECRET}\" \ -e AWS_SECRET_ACCESS_KEY=\"${S3_SECRET}\" \
ghcr.io/linuxserver/baseimage-alpine:3.23 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ ghcr.io/linuxserver/baseimage-alpine:3.20 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\
apk add --no-cache python3 && \ apk add --no-cache python3 && \
python3 -m venv /lsiopy && \ python3 -m venv /lsiopy && \
pip install --no-cache-dir -U pip && \ pip install --no-cache-dir -U pip && \
@@ -333,7 +311,7 @@ pipeline {
echo "Jenkinsfile is up to date." echo "Jenkinsfile is up to date."
fi fi
echo "Starting Stage 2 - Delete old templates" echo "Starting Stage 2 - Delete old templates"
OLD_TEMPLATES=".github/ISSUE_TEMPLATE.md .github/ISSUE_TEMPLATE/issue.bug.md .github/ISSUE_TEMPLATE/issue.feature.md .github/workflows/call_invalid_helper.yml .github/workflows/stale.yml .github/workflows/package_trigger.yml" OLD_TEMPLATES=".github/ISSUE_TEMPLATE.md .github/ISSUE_TEMPLATE/issue.bug.md .github/ISSUE_TEMPLATE/issue.feature.md .github/workflows/call_invalid_helper.yml .github/workflows/stale.yml"
for i in ${OLD_TEMPLATES}; do for i in ${OLD_TEMPLATES}; do
if [[ -f "${i}" ]]; then if [[ -f "${i}" ]]; then
TEMPLATES_TO_DELETE="${i} ${TEMPLATES_TO_DELETE}" TEMPLATES_TO_DELETE="${i} ${TEMPLATES_TO_DELETE}"
@@ -357,35 +335,6 @@ pipeline {
else else
echo "No templates to delete" echo "No templates to delete"
fi fi
echo "Starting Stage 2.5 - Update init diagram"
if ! grep -q 'init_diagram:' readme-vars.yml; then
echo "Adding the key 'init_diagram' to readme-vars.yml"
sed -i '\\|^#.*changelog.*$|d' readme-vars.yml
sed -i 's|^changelogs:|# init diagram\\ninit_diagram:\\n\\n# changelog\\nchangelogs:|' readme-vars.yml
fi
mkdir -p ${TEMPDIR}/d2
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
yq -ei ".init_diagram |= load_str(\\"${TEMPDIR}/d2/${CONTAINER_NAME}-latest.d2\\")" readme-vars.yml
if [[ $(md5sum readme-vars.yml | cut -c1-8) != $(md5sum ${TEMPDIR}/docker-${CONTAINER_NAME}/readme-vars.yml | cut -c1-8) ]]; then
echo "'init_diagram' has been updated. Updating repo and exiting build, new one will trigger based on commit."
mkdir -p ${TEMPDIR}/repo
git clone https://github.com/${LS_USER}/${LS_REPO}.git ${TEMPDIR}/repo/${LS_REPO}
cd ${TEMPDIR}/repo/${LS_REPO}
git checkout -f master
cp ${WORKSPACE}/readme-vars.yml ${TEMPDIR}/repo/${LS_REPO}/readme-vars.yml
git add readme-vars.yml
git commit -m 'Bot Updating Templated Files'
git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master
git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master
echo "true" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER}
echo "Updating templates and exiting build, new one will trigger based on commit"
rm -Rf ${TEMPDIR}
exit 0
else
echo "false" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER}
echo "Init diagram is unchanged"
fi
echo "Starting Stage 3 - Update templates" echo "Starting Stage 3 - Update templates"
CURRENTHASH=$(grep -hs ^ ${TEMPLATED_FILES} | md5sum | cut -c1-8) CURRENTHASH=$(grep -hs ^ ${TEMPLATED_FILES} | md5sum | cut -c1-8)
cd ${TEMPDIR}/docker-${CONTAINER_NAME} cd ${TEMPDIR}/docker-${CONTAINER_NAME}
@@ -594,45 +543,8 @@ pipeline {
--label \"org.opencontainers.image.title=Swag\" \ --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.\" \ --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=false --sbom=false \
--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
set -e
IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do
docker tag ${IMAGE}:${META_TAG} ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER}
done
'''
withCredentials([
[
$class: 'UsernamePasswordMultiBinding',
credentialsId: 'Quay.io-Robot',
usernameVariable: 'QUAYUSER',
passwordVariable: 'QUAYPASS'
]
]) {
retry_backoff(5,5) {
sh '''#! /bin/bash
set -e
echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --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 $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin
if [[ "${PACKAGE_CHECK}" != "true" ]]; then
declare -A pids
IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do
docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} &
pids[$!]="$i"
done
for p in "${!pids[@]}"; do
wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; }
done
fi
'''
}
}
} }
} }
// Build MultiArch Docker containers for push to LS Repo // Build MultiArch Docker containers for push to LS Repo
@@ -663,45 +575,8 @@ pipeline {
--label \"org.opencontainers.image.title=Swag\" \ --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.\" \ --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=false --sbom=false \
--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
set -e
IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do
docker tag ${IMAGE}:amd64-${META_TAG} ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER}
done
'''
withCredentials([
[
$class: 'UsernamePasswordMultiBinding',
credentialsId: 'Quay.io-Robot',
usernameVariable: 'QUAYUSER',
passwordVariable: 'QUAYPASS'
]
]) {
retry_backoff(5,5) {
sh '''#! /bin/bash
set -e
echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --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 $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin
if [[ "${PACKAGE_CHECK}" != "true" ]]; then
declare -A pids
IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do
docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} &
pids[$!]="$i"
done
for p in "${!pids[@]}"; do
wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; }
done
fi
'''
}
}
} }
} }
stage('Build ARM64') { stage('Build ARM64') {
@@ -710,6 +585,10 @@ pipeline {
} }
steps { steps {
echo "Running on node: ${NODE_NAME}" echo "Running on node: ${NODE_NAME}"
echo 'Logging into Github'
sh '''#! /bin/bash
echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin
'''
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 "docker buildx build \
--label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ --label \"org.opencontainers.image.created=${GITHUB_DATE}\" \
@@ -725,52 +604,18 @@ pipeline {
--label \"org.opencontainers.image.title=Swag\" \ --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.\" \ --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=false --sbom=false \
--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 "docker tag ${IMAGE}:arm64v8-${META_TAG} ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}"
set -e
IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do
docker tag ${IMAGE}:arm64v8-${META_TAG} ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}
done
'''
withCredentials([
[
$class: 'UsernamePasswordMultiBinding',
credentialsId: 'Quay.io-Robot',
usernameVariable: 'QUAYUSER',
passwordVariable: 'QUAYPASS'
]
]) {
retry_backoff(5,5) { retry_backoff(5,5) {
sh '''#! /bin/bash sh "docker push ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}"
set -e
echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --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 $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin
if [[ "${PACKAGE_CHECK}" != "true" ]]; then
declare -A pids
IFS=',' read -ra CACHE <<< "$BUILDCACHE"
for i in "${CACHE[@]}"; do
docker push ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} &
pids[$!]="$i"
done
for p in "${!pids[@]}"; do
wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; }
done
fi
'''
}
} }
sh '''#! /bin/bash sh '''#! /bin/bash
containers=$(docker ps -aq) containers=$(docker ps -aq)
if [[ -n "${containers}" ]]; then if [[ -n "${containers}" ]]; then
docker stop ${containers} docker stop ${containers}
fi fi
docker system prune -f --volumes || : docker system prune -af --volumes || : '''
docker image prune -af || :
'''
} }
} }
} }
@@ -795,7 +640,7 @@ pipeline {
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 \
ghcr.io/anchore/syft:${SYFT_IMAGE_TAG} \ ghcr.io/anchore/syft:latest \
${LOCAL_CONTAINER} -o table=/tmp/package_versions.txt ${LOCAL_CONTAINER} -o table=/tmp/package_versions.txt
NEW_PACKAGE_TAG=$(md5sum ${TEMPDIR}/package_versions.txt | cut -c1-8 ) 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" echo "Package tag sha from current packages in buit container is ${NEW_PACKAGE_TAG} comparing to old ${PACKAGE_TAG} from github"
@@ -874,15 +719,7 @@ pipeline {
} }
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
if grep -q 'docker-baseimage' <<< "${LS_REPO}"; then docker pull ghcr.io/linuxserver/ci:latest
echo "Detected baseimage, setting LSIO_FIRST_PARTY=true"
if [ -n "${CI_DOCKERENV}" ]; then
CI_DOCKERENV="LSIO_FIRST_PARTY=true|${CI_DOCKERENV}"
else
CI_DOCKERENV="LSIO_FIRST_PARTY=true"
fi
fi
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 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}
@@ -894,7 +731,6 @@ pipeline {
-e DOCKER_LOGS_TIMEOUT=\"${CI_DELAY}\" \ -e DOCKER_LOGS_TIMEOUT=\"${CI_DELAY}\" \
-e TAGS=\"${CI_TAGS}\" \ -e TAGS=\"${CI_TAGS}\" \
-e META_TAG=\"${META_TAG}\" \ -e META_TAG=\"${META_TAG}\" \
-e RELEASE_TAG=\"latest\" \
-e PORT=\"${CI_PORT}\" \ -e PORT=\"${CI_PORT}\" \
-e SSL=\"${CI_SSL}\" \ -e SSL=\"${CI_SSL}\" \
-e BASE=\"${DIST_IMAGE}\" \ -e BASE=\"${DIST_IMAGE}\" \
@@ -904,11 +740,7 @@ pipeline {
-e WEB_SCREENSHOT=\"${CI_WEB}\" \ -e WEB_SCREENSHOT=\"${CI_WEB}\" \
-e WEB_AUTH=\"${CI_AUTH}\" \ -e WEB_AUTH=\"${CI_AUTH}\" \
-e WEB_PATH=\"${CI_WEBPATH}\" \ -e WEB_PATH=\"${CI_WEBPATH}\" \
-e NODE_NAME=\"${NODE_NAME}\" \ -t ghcr.io/linuxserver/ci:latest \
-e SYFT_IMAGE_TAG=\"${CI_SYFT_IMAGE_TAG:-${SYFT_IMAGE_TAG}}\" \
-e COMMIT_SHA=\"${COMMIT_SHA}\" \
-e BUILD_NUMBER=\"${BUILD_NUMBER}\" \
-t ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} \
python3 test_build.py''' python3 test_build.py'''
} }
} }
@@ -923,28 +755,40 @@ pipeline {
environment name: 'EXIT_STATUS', value: '' environment name: 'EXIT_STATUS', value: ''
} }
steps { steps {
withCredentials([
[
$class: 'UsernamePasswordMultiBinding',
credentialsId: 'Quay.io-Robot',
usernameVariable: 'QUAYUSER',
passwordVariable: 'QUAYPASS'
]
]) {
retry_backoff(5,5) { retry_backoff(5,5) {
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
for PUSHIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin
[[ ${PUSHIMAGE%%/*} =~ \\. ]] && PUSHIMAGEPLUS="${PUSHIMAGE}" || PUSHIMAGEPLUS="docker.io/${PUSHIMAGE}" echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin
IFS=',' read -ra CACHE <<< "$BUILDCACHE" echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin
for i in "${CACHE[@]}"; do echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin
if [[ "${PUSHIMAGEPLUS}" == "$(cut -d "/" -f1 <<< ${i})"* ]]; then for PUSHIMAGE in "${GITHUBIMAGE}" "${GITLABIMAGE}" "${QUAYIMAGE}" "${IMAGE}"; do
CACHEIMAGE=${i} docker tag ${IMAGE}:${META_TAG} ${PUSHIMAGE}:${META_TAG}
fi docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:latest
done docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:${EXT_RELEASE_TAG}
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}" ]]; 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} || \ docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:${SEMVER}
{ if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } fi
docker push ${PUSHIMAGE}:latest
docker push ${PUSHIMAGE}:${META_TAG}
docker push ${PUSHIMAGE}:${EXT_RELEASE_TAG}
if [ -n "${SEMVER}" ]; then
docker push ${PUSHIMAGE}:${SEMVER}
fi fi
done done
''' '''
} }
} }
} }
}
// If this is a multi arch release push all images and define the manifest // If this is a multi arch release push all images and define the manifest
stage('Docker-Push-Multi') { stage('Docker-Push-Multi') {
when { when {
@@ -952,44 +796,60 @@ pipeline {
environment name: 'EXIT_STATUS', value: '' environment name: 'EXIT_STATUS', value: ''
} }
steps { steps {
withCredentials([
[
$class: 'UsernamePasswordMultiBinding',
credentialsId: 'Quay.io-Robot',
usernameVariable: 'QUAYUSER',
passwordVariable: 'QUAYPASS'
]
]) {
retry_backoff(5,5) { retry_backoff(5,5) {
sh '''#! /bin/bash sh '''#! /bin/bash
set -e set -e
for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin
[[ ${MANIFESTIMAGE%%/*} =~ \\. ]] && MANIFESTIMAGEPLUS="${MANIFESTIMAGE}" || MANIFESTIMAGEPLUS="docker.io/${MANIFESTIMAGE}" echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin
IFS=',' read -ra CACHE <<< "$BUILDCACHE" echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin
for i in "${CACHE[@]}"; do echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin
if [[ "${MANIFESTIMAGEPLUS}" == "$(cut -d "/" -f1 <<< ${i})"* ]]; then if [ "${CI}" == "false" ]; then
CACHEIMAGE=${i} 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}
fi fi
done for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do
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} || \ docker tag ${IMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG}
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-latest
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} || \ docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG}
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } docker tag ${IMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG}
docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-latest
docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG}
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} || \ docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${SEMVER}
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${SEMVER}
docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${SEMVER} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ fi
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } docker push ${MANIFESTIMAGE}:amd64-${META_TAG}
docker push ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG}
docker push ${MANIFESTIMAGE}:amd64-latest
docker push ${MANIFESTIMAGE}:arm64v8-${META_TAG}
docker push ${MANIFESTIMAGE}:arm64v8-latest
docker push ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG}
if [ -n "${SEMVER}" ]; then
docker push ${MANIFESTIMAGE}:amd64-${SEMVER}
docker push ${MANIFESTIMAGE}:arm64v8-${SEMVER}
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 || \ docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG}
docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} || \ docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG}
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; }
docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} || \
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; 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} || \ docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER}
{ if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; }
fi fi
done done
''' '''
} }
} }
} }
}
// If this is a public release tag it in the LS Github // If this is a public release tag it in the LS Github
stage('Github-Tag-Push-Release') { stage('Github-Tag-Push-Release') {
when { when {
@@ -1001,41 +861,23 @@ pipeline {
environment name: 'EXIT_STATUS', value: '' environment name: 'EXIT_STATUS', value: ''
} }
steps { steps {
sh '''#! /bin/bash
echo "Auto-generating release notes"
if [ "$(git tag --points-at HEAD)" != "" ]; then
echo "Existing tag points to current commit, suggesting no new LS changes"
AUTO_RELEASE_NOTES="No changes"
else
AUTO_RELEASE_NOTES=$(curl -fsL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github+json" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases/generate-notes \
-d '{"tag_name":"'${META_TAG}'",\
"target_commitish": "master"}' \
| jq -r '.body' | sed 's|## What.s Changed||')
fi
echo "Pushing New tag for current commit ${META_TAG}" echo "Pushing New tag for current commit ${META_TAG}"
curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \ sh '''curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \
-d '{"tag":"'${META_TAG}'",\ -d '{"tag":"'${META_TAG}'",\
"object": "'${COMMIT_SHA}'",\ "object": "'${COMMIT_SHA}'",\
"message": "Tagging Release '${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}' to master",\ "message": "Tagging Release '${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}' to master",\
"type": "commit",\ "type": "commit",\
"tagger": {"name": "LinuxServer-CI","email": "ci@linuxserver.io","date": "'${GITHUB_DATE}'"}}' "tagger": {"name": "LinuxServer-CI","email": "ci@linuxserver.io","date": "'${GITHUB_DATE}'"}}' '''
echo "Pushing New release for Tag" echo "Pushing New release for Tag"
sh '''#! /bin/bash
echo "Updating PIP version of ${EXT_PIP} to ${EXT_RELEASE_CLEAN}" > releasebody.json echo "Updating PIP version of ${EXT_PIP} to ${EXT_RELEASE_CLEAN}" > releasebody.json
jq -n \ echo '{"tag_name":"'${META_TAG}'",\
--arg tag_name "$META_TAG" \ "target_commitish": "master",\
--arg target_commitish "master" \ "name": "'${META_TAG}'",\
--arg ci_url "${CI_URL:-N/A}" \ "body": "**LinuxServer Changes:**\\n\\n'${LS_RELEASE_NOTES}'\\n\\n**PIP Changes:**\\n\\n' > start
--arg ls_notes "$AUTO_RELEASE_NOTES" \ printf '","draft": false,"prerelease": false}' >> releasebody.json
--arg remote_notes "$(cat releasebody.json)" \ paste -d'\\0' start releasebody.json > releasebody.json.done
'{ curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done'''
"tag_name": $tag_name,
"target_commitish": $target_commitish,
"name": $tag_name,
"body": ("**CI Report:**\\n\\n" + $ci_url + "\\n\\n**LinuxServer Changes:**\\n\\n" + $ls_notes + "\\n\\n**Remote Changes:**\\n\\n" + $remote_notes),
"draft": false,
"prerelease": false }' > releasebody.json.done
curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done
'''
} }
} }
// Add protection to the release branch // Add protection to the release branch
@@ -1165,67 +1007,29 @@ EOF
git config --global --unset commit.gpgsign git config --global --unset commit.gpgsign
''' '''
script{ script{
env.JOB_DATE = sh(
script: '''date '+%Y-%m-%dT%H:%M:%S%:z' ''',
returnStdout: true).trim()
if (env.EXIT_STATUS == "ABORTED"){ if (env.EXIT_STATUS == "ABORTED"){
sh 'echo "build aborted"' sh 'echo "build aborted"'
}else{
if (currentBuild.currentResult == "SUCCESS"){
if (env.GITHUBIMAGE =~ /lspipepr/){
env.JOB_WEBHOOK_STATUS='Success'
env.JOB_WEBHOOK_COLOUR=3957028
env.JOB_WEBHOOK_FOOTER='PR Build'
}else if (env.GITHUBIMAGE =~ /lsiodev/){
env.JOB_WEBHOOK_STATUS='Success'
env.JOB_WEBHOOK_COLOUR=3957028
env.JOB_WEBHOOK_FOOTER='Dev Build'
}else{
env.JOB_WEBHOOK_STATUS='Success'
env.JOB_WEBHOOK_COLOUR=1681177
env.JOB_WEBHOOK_FOOTER='Live Build'
} }
}else{ else if (currentBuild.currentResult == "SUCCESS"){
if (env.GITHUBIMAGE =~ /lspipepr/){ sh ''' curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/jenkins-avatar.png","embeds": [{"color": 1681177,\
env.JOB_WEBHOOK_STATUS='Failure' "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** Success\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\
env.JOB_WEBHOOK_COLOUR=12669523 "username": "Jenkins"}' ${BUILDS_DISCORD} '''
env.JOB_WEBHOOK_FOOTER='PR Build'
}else if (env.GITHUBIMAGE =~ /lsiodev/){
env.JOB_WEBHOOK_STATUS='Failure'
env.JOB_WEBHOOK_COLOUR=12669523
env.JOB_WEBHOOK_FOOTER='Dev Build'
}else{
env.JOB_WEBHOOK_STATUS='Failure'
env.JOB_WEBHOOK_COLOUR=16711680
env.JOB_WEBHOOK_FOOTER='Live Build'
} }
} else {
sh ''' curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/jenkins-avatar.png","embeds": [{"'color'": '${JOB_WEBHOOK_COLOUR}',\ sh ''' curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/jenkins-avatar.png","embeds": [{"color": 16711680,\
"footer": {"text" : "'"${JOB_WEBHOOK_FOOTER}"'"},\ "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** failure\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\
"timestamp": "'${JOB_DATE}'",\
"description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** '${JOB_WEBHOOK_STATUS}'\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\
"username": "Jenkins"}' ${BUILDS_DISCORD} ''' "username": "Jenkins"}' ${BUILDS_DISCORD} '''
} }
} }
} }
cleanup { cleanup {
sh '''#! /bin/bash sh '''#! /bin/bash
echo "Pruning builder!!" echo "Performing docker system prune!!"
docker builder prune -f --builder container || : containers=$(docker ps -aq)
containers=$(docker ps -q)
if [[ -n "${containers}" ]]; then if [[ -n "${containers}" ]]; then
BUILDX_CONTAINER_ID=$(docker ps -qf 'name=buildx_buildkit') docker stop ${containers}
for container in ${containers}; do
if [[ "${container}" == "${BUILDX_CONTAINER_ID}" ]]; then
echo "skipping buildx container in docker stop"
else
echo "Stopping container ${container}"
docker stop ${container}
fi fi
done docker system prune -af --volumes || :
fi
docker system prune -f --volumes || :
docker image prune -af || :
''' '''
cleanWs() cleanWs()
} }

0
LICENSE Normal file → Executable file
View File

View File

@@ -3,8 +3,9 @@
[![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)](https://linuxserver.io) [![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)](https://linuxserver.io)
[![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://discord.gg/YWrKVTn "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.") [![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.")
[![Fleet](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=Fleet)](https://fleet.linuxserver.io "an online web interface which displays all of our maintained images.")
[![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")
@@ -19,8 +20,9 @@ The [LinuxServer.io](https://linuxserver.io) team brings you another container r
Find us at: 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://discord.gg/YWrKVTn) - realtime support / chat with the community and the team.
* [Discourse](https://discourse.linuxserver.io) - post on our community forum. * [Discourse](https://discourse.linuxserver.io) - post on our community forum.
* [Fleet](https://fleet.linuxserver.io) - an online web interface which displays all of our maintained images.
* [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
@@ -35,6 +37,7 @@ Find us at:
[![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/swag.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=pulls&logo=docker)](https://hub.docker.com/r/linuxserver/swag) [![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/swag.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=pulls&logo=docker)](https://hub.docker.com/r/linuxserver/swag)
[![Docker Stars](https://img.shields.io/docker/stars/linuxserver/swag.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=stars&logo=docker)](https://hub.docker.com/r/linuxserver/swag) [![Docker Stars](https://img.shields.io/docker/stars/linuxserver/swag.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=stars&logo=docker)](https://hub.docker.com/r/linuxserver/swag)
[![Jenkins Build](https://img.shields.io/jenkins/build?labelColor=555555&logoColor=ffffff&style=for-the-badge&jobUrl=https%3A%2F%2Fci.linuxserver.io%2Fjob%2FDocker-Pipeline-Builders%2Fjob%2Fdocker-swag%2Fjob%2Fmaster%2F&logo=jenkins)](https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/master/) [![Jenkins Build](https://img.shields.io/jenkins/build?labelColor=555555&logoColor=ffffff&style=for-the-badge&jobUrl=https%3A%2F%2Fci.linuxserver.io%2Fjob%2FDocker-Pipeline-Builders%2Fjob%2Fdocker-swag%2Fjob%2Fmaster%2F&logo=jenkins)](https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-swag/job/master/)
[![LSIO CI](https://img.shields.io/badge/dynamic/yaml?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=CI&query=CI&url=https%3A%2F%2Fci-tests.linuxserver.io%2Flinuxserver%2Fswag%2Flatest%2Fci-status.yml)](https://ci-tests.linuxserver.io/linuxserver/swag/latest/index.html)
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. 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.
@@ -52,6 +55,7 @@ The architectures supported by this image are:
| :----: | :----: | ---- | | :----: | :----: | ---- |
| x86-64 | ✅ | amd64-\<version tag\> | | x86-64 | ✅ | amd64-\<version tag\> |
| arm64 | ✅ | arm64v8-\<version tag\> | | arm64 | ✅ | arm64v8-\<version tag\> |
| armhf | ❌ | |
## Application Setup ## Application Setup
@@ -67,7 +71,7 @@ The architectures supported by this image are:
1. Certs that only cover your main subdomain (ie. `yoursubdomain.duckdns.org`, leave the `SUBDOMAINS` variable empty) 1. Certs that only cover your main subdomain (ie. `yoursubdomain.duckdns.org`, leave the `SUBDOMAINS` variable empty)
2. Certs that cover sub-subdomains of your main subdomain (ie. `*.yoursubdomain.duckdns.org`, set the `SUBDOMAINS` variable to `wildcard`) 2. Certs that cover sub-subdomains of your main subdomain (ie. `*.yoursubdomain.duckdns.org`, set the `SUBDOMAINS` variable to `wildcard`)
* `--cap-add=NET_ADMIN` is required for fail2ban to modify iptables * `--cap-add=NET_ADMIN` is required for fail2ban to modify iptables
* After setup, navigate to `https://example.com` to access the default homepage (http access through port 80 is disabled by default, you can enable it by editing the default site config at `/config/nginx/site-confs/default.conf`). * After setup, navigate to `https://yourdomain.url` to access the default homepage (http access through port 80 is disabled by default, you can enable it by editing the default site config at `/config/nginx/site-confs/default.conf`).
* Certs are checked nightly and if expiration is within 30 days, renewal is attempted. If your cert is about to expire in less than 30 days, check the logs under `/config/log/letsencrypt` to see why the renewals have been failing. It is recommended to input your e-mail in docker parameters so you receive expiration notices from Let's Encrypt in those circumstances. * Certs are checked nightly and if expiration is within 30 days, renewal is attempted. If your cert is about to expire in less than 30 days, check the logs under `/config/log/letsencrypt` to see why the renewals have been failing. It is recommended to input your e-mail in docker parameters so you receive expiration notices from Let's Encrypt in those circumstances.
### Certbot Plugins ### Certbot Plugins
@@ -126,7 +130,7 @@ This will *ask* Google et al not to index and list your site. Be careful with th
* You can check which jails are active via `docker exec -it swag fail2ban-client status` * You can check which jails are active via `docker exec -it swag fail2ban-client status`
* You can check the status of a specific jail via `docker exec -it swag fail2ban-client status <jail name>` * You can check the status of a specific jail via `docker exec -it swag fail2ban-client status <jail name>`
* You can unban an IP via `docker exec -it swag fail2ban-client set <jail name> unbanip <IP>` * You can unban an IP via `docker exec -it swag fail2ban-client set <jail name> unbanip <IP>`
* A list of commands for fail2ban-client can be found [here](https://manpages.ubuntu.com/manpages/noble/man1/fail2ban-client.1.html) * A list of commands can be found here: <https://www.fail2ban.org/wiki/index.php/Commands>
### Updating configs ### Updating configs
@@ -142,36 +146,14 @@ This will *ask* Google et al not to index and list your site. Be careful with th
* Proxy sample files WILL be updated, however your renamed (enabled) proxy files will not. * Proxy sample files WILL be updated, however your renamed (enabled) proxy files will not.
* You can check the new sample and adjust your active config as needed. * You can check the new sample and adjust your active config as needed.
### QUIC support
This image supports QUIC (also known as HTTP/3) but it must be explicitly enabled in each proxy conf, and the default conf, because if the listener is enabled and you don't expose 443/UDP, it can break connections with some browsers.
To enable QUIC, expose 443/UDP to your clients, then uncomment both QUIC listeners in all of your active proxy confs, as well as the default conf, and restart the container.
You should also uncomment the `Alt-Svc` header in your `ssl.conf` so that browsers are aware that you offer QUIC connectivity.
It is [recommended](https://quic-go.net/docs/quic/optimizations/#udp-buffer-sizes) to increase the UDP send/recieve buffer **on the host** by setting the `net.core.rmem_max` and `net.core.wmem_max` sysctls. Suggested values are 4-16Mb (4194304-16777216 bytes). For persistence between reboots use `/etc/sysctl.d/`.
### Migration from the old `linuxserver/letsencrypt` image ### Migration from the old `linuxserver/letsencrypt` image
Please follow the instructions [on this blog post](https://www.linuxserver.io/blog/2020-08-21-introducing-swag#migrate). Please follow the instructions [on this blog post](https://www.linuxserver.io/blog/2020-08-21-introducing-swag#migrate).
## Read-Only Operation
This image can be run with a read-only container filesystem. For details please [read the docs](https://docs.linuxserver.io/misc/read-only/).
### Caveats
* `/tmp` must be mounted to tmpfs
* fail2ban will not be available
## Usage ## Usage
To help you get started creating a container from this image you can either use docker-compose or the docker cli. To help you get started creating a container from this image you can either use docker-compose or the docker cli.
>[!NOTE]
>Unless a parameter is flagged as 'optional', it is *mandatory* and a value must be provided.
### docker-compose (recommended, [click here for more info](https://docs.linuxserver.io/general/docker-compose)) ### docker-compose (recommended, [click here for more info](https://docs.linuxserver.io/general/docker-compose))
```yaml ```yaml
@@ -186,7 +168,7 @@ services:
- PUID=1000 - PUID=1000
- PGID=1000 - PGID=1000
- TZ=Etc/UTC - TZ=Etc/UTC
- URL=example.com - URL=yourdomain.url
- VALIDATION=http - VALIDATION=http
- SUBDOMAINS=www, #optional - SUBDOMAINS=www, #optional
- CERTPROVIDER= #optional - CERTPROVIDER= #optional
@@ -196,15 +178,11 @@ services:
- ONLY_SUBDOMAINS=false #optional - ONLY_SUBDOMAINS=false #optional
- EXTRA_DOMAINS= #optional - EXTRA_DOMAINS= #optional
- STAGING=false #optional - STAGING=false #optional
- DISABLE_F2B= #optional
- SWAG_AUTORELOAD= #optional
- SWAG_AUTORELOAD_WATCHLIST= #optional
volumes: volumes:
- /path/to/swag/config:/config - /path/to/swag/config:/config
ports: ports:
- 443:443 - 443:443
- 80:80 #optional - 80:80 #optional
- 443:443/udp #optional
restart: unless-stopped restart: unless-stopped
``` ```
@@ -217,7 +195,7 @@ docker run -d \
-e PUID=1000 \ -e PUID=1000 \
-e PGID=1000 \ -e PGID=1000 \
-e TZ=Etc/UTC \ -e TZ=Etc/UTC \
-e URL=example.com \ -e URL=yourdomain.url \
-e VALIDATION=http \ -e VALIDATION=http \
-e SUBDOMAINS=www, `#optional` \ -e SUBDOMAINS=www, `#optional` \
-e CERTPROVIDER= `#optional` \ -e CERTPROVIDER= `#optional` \
@@ -227,12 +205,8 @@ docker run -d \
-e ONLY_SUBDOMAINS=false `#optional` \ -e ONLY_SUBDOMAINS=false `#optional` \
-e EXTRA_DOMAINS= `#optional` \ -e EXTRA_DOMAINS= `#optional` \
-e STAGING=false `#optional` \ -e STAGING=false `#optional` \
-e DISABLE_F2B= `#optional` \
-e SWAG_AUTORELOAD= `#optional` \
-e SWAG_AUTORELOAD_WATCHLIST= `#optional` \
-p 443:443 \ -p 443:443 \
-p 80:80 `#optional` \ -p 80:80 `#optional` \
-p 443:443/udp `#optional` \
-v /path/to/swag/config:/config \ -v /path/to/swag/config:/config \
--restart unless-stopped \ --restart unless-stopped \
lscr.io/linuxserver/swag:latest lscr.io/linuxserver/swag:latest
@@ -244,28 +218,22 @@ Containers are configured using parameters passed at runtime (such as those abov
| Parameter | Function | | Parameter | Function |
| :----: | --- | | :----: | --- |
| `-p 443:443` | HTTPS port | | `-p 443` | Https port |
| `-p 80` | HTTP port (required for HTTP validation and HTTP -> HTTPS redirect) | | `-p 80` | Http port (required for http validation and http -> https redirect) |
| `-p 443/udp` | QUIC (HTTP/3) port. Must be enabled in the default and proxy confs. |
| `-e PUID=1000` | for UserID - see below for explanation | | `-e PUID=1000` | for UserID - see below for explanation |
| `-e PGID=1000` | for GroupID - see below for explanation | | `-e PGID=1000` | for GroupID - see below for explanation |
| `-e TZ=Etc/UTC` | specify a timezone to use, see this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List). | | `-e TZ=Etc/UTC` | specify a timezone to use, see this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List). |
| `-e URL=example.com` | Top url you have control over (e.g. `example.com` if you own it, or `customsubdomain.example.com` if dynamic dns). | | `-e URL=yourdomain.url` | Top url you have control over (`customdomain.com` if you own it, or `customsubdomain.ddnsprovider.com` if dynamic dns). |
| `-e VALIDATION=http` | Certbot validation method to use, options are `http` or `dns` (`dns` method also requires `DNSPLUGIN` variable set). | | `-e VALIDATION=http` | Certbot validation method to use, options are `http` or `dns` (`dns` method also requires `DNSPLUGIN` variable set). |
| `-e SUBDOMAINS=www,` | Subdomains you'd like the cert to cover (comma separated, no spaces) ie. `www,ftp,cloud`. For a wildcard cert, set this *exactly* to `wildcard` (wildcard cert is available via `dns` validation only) | | `-e SUBDOMAINS=www,` | Subdomains you'd like the cert to cover (comma separated, no spaces) ie. `www,ftp,cloud`. For a wildcard cert, set this *exactly* to `wildcard` (wildcard cert is available via `dns` validation only) |
| `-e CERTPROVIDER=` | Optionally define the cert provider. Set to `zerossl` for ZeroSSL certs (requires existing [ZeroSSL account](https://app.zerossl.com/signup) and the e-mail address entered in `EMAIL` env var). Otherwise defaults to Let's Encrypt. | | `-e CERTPROVIDER=` | Optionally define the cert provider. Set to `zerossl` for ZeroSSL certs (requires existing [ZeroSSL account](https://app.zerossl.com/signup) and the e-mail address entered in `EMAIL` env var). Otherwise defaults to Let's Encrypt. |
| `-e DNSPLUGIN=cloudflare` | Required if `VALIDATION` is set to `dns`. Options are `acmedns`, `aliyun`, `azure`, `bunny`, `cloudflare`, `cpanel`, `desec`, `digitalocean`, `directadmin`, `dnsimple`, `dnsmadeeasy`, `dnspod`, `do`, `domeneshop`, `dreamhost`, `duckdns`, `dynu`, `freedns`, `gandi`, `gehirn`, `glesys`, `godaddy`, `google`, `he`, `hetzner`, `hetzner-cloud`, `infomaniak`, `inwx`, `ionos`, `linode`, `loopia`, `luadns`, `namecheap`, `netcup`, `njalla`, `nsone`, `ovh`, `porkbun`, `rfc2136`, `route53`, `sakuracloud`, `standalone`, `transip`, and `vultr`. Also need to enter the credentials into the corresponding ini (or json for some plugins) file under `/config/dns-conf`. | | `-e DNSPLUGIN=cloudflare` | Required if `VALIDATION` is set to `dns`. Options are `acmedns`, `aliyun`, `azure`, `bunny`, `cloudflare`, `cpanel`, `desec`, `digitalocean`, `directadmin`, `dnsimple`, `dnsmadeeasy`, `dnspod`, `do`, `domeneshop`, `dreamhost`, `duckdns`, `dynudns`, `freedns`, `gandi`, `gehirn`, `glesys`, `godaddy`, `google`, `he`, `hetzner`, `infomaniak`, `inwx`, `ionos`, `linode`, `loopia`, `luadns`, `namecheap`, `netcup`, `njalla`, `nsone`, `ovh`, `porkbun`, `rfc2136`, `route53`, `sakuracloud`, `standalone`, `transip`, and `vultr`. Also need to enter the credentials into the corresponding ini (or json for some plugins) file under `/config/dns-conf`. |
| `-e PROPAGATION=` | Optionally override (in seconds) the default propagation time for the dns plugins. | | `-e PROPAGATION=` | Optionally override (in seconds) the default propagation time for the dns plugins. |
| `-e EMAIL=` | Optional e-mail address used for cert expiration notifications (Required for ZeroSSL). | | `-e EMAIL=` | Optional e-mail address used for cert expiration notifications (Required for ZeroSSL). |
| `-e ONLY_SUBDOMAINS=false` | If you wish to get certs only for certain subdomains, but not the main domain (main domain may be hosted on another machine and cannot be validated), set this to `true` | | `-e ONLY_SUBDOMAINS=false` | If you wish to get certs only for certain subdomains, but not the main domain (main domain may be hosted on another machine and cannot be validated), set this to `true` |
| `-e EXTRA_DOMAINS=` | Additional fully qualified domain names (comma separated, no spaces) ie. `example.net,subdomain.example.net,*.example.org` | | `-e EXTRA_DOMAINS=` | Additional fully qualified domain names (comma separated, no spaces) ie. `extradomain.com,subdomain.anotherdomain.org,*.anotherdomain.org` |
| `-e STAGING=false` | Set to `true` to retrieve certs in staging mode. Rate limits will be much higher, but the resulting cert will not pass the browser's security test. Only to be used for testing purposes. | | `-e STAGING=false` | Set to `true` to retrieve certs in staging mode. Rate limits will be much higher, but the resulting cert will not pass the browser's security test. Only to be used for testing purposes. |
| `-e DISABLE_F2B=` | Set to `true` to disable the Fail2ban service in the container, if you're already running it elsewhere or using a different IPS. |
| `-e SWAG_AUTORELOAD=` | Set to `true` to enable automatic reloading of confs on change without stopping/restarting nginx. Your filesystem must support inotify. This functionality was previously offered [via mod](https://github.com/linuxserver/docker-mods/tree/swag-auto-reload). |
| `-e SWAG_AUTORELOAD_WATCHLIST=` | A [pipe](https://en.wikipedia.org/wiki/Vertical_bar)-separated list of additional folders for auto reload to watch in addition to `/config/nginx` |
| `-v /config` | Persistent config files | | `-v /config` | Persistent config files |
| `--read-only=true` | Run container with a read-only filesystem. Please [read the docs](https://docs.linuxserver.io/misc/read-only/). |
| `--cap-add=NET_ADMIN` | Required for fail2Ban to be able to modify iptables rules. |
### Portainer notice ### Portainer notice
@@ -407,8 +375,7 @@ Below are the instructions for updating containers:
### Image Update Notifications - Diun (Docker Image Update Notifier) ### Image Update Notifications - Diun (Docker Image Update Notifier)
>[!TIP] **tip**: We recommend [Diun](https://crazymax.dev/diun/) for update notifications. Other tools that automatically update containers unattended are not recommended or supported.
>We recommend [Diun](https://crazymax.dev/diun/) for update notifications. Other tools that automatically update containers unattended are not recommended or supported.
## Building locally ## Building locally
@@ -423,24 +390,16 @@ docker build \
-t lscr.io/linuxserver/swag:latest . -t lscr.io/linuxserver/swag:latest .
``` ```
The ARM variants can be built on x86_64 hardware and vice versa using `lscr.io/linuxserver/qemu-static` The ARM variants can be built on x86_64 hardware using `multiarch/qemu-user-static`
```bash ```bash
docker run --rm --privileged lscr.io/linuxserver/qemu-static --reset docker run --rm --privileged multiarch/qemu-user-static:register --reset
``` ```
Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64`. Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64`.
## Versions ## Versions
* **23.01.26:** - Reorder init to fix proxy conf version checks.
* **21.12.25:** - Add support for hetzner-cloud dns validation.
* **04.11.25:** - Switch default Gandi credentials from API Key to Token, allow DNS propagation time for Azure DNS plugin.
* **18.07.25:** - Rebase to Alpine 3.22 with PHP 8.4. Add QUIC support. Drop PHP bindings for mcrypt as it is no longer maintained.
* **05.05.25:** - Disable Certbot's built in log rotation.
* **19.01.25:** - Add [Auto Reload](https://github.com/linuxserver/docker-mods/tree/swag-auto-reload) functionality to SWAG.
* **17.12.24:** - Rebase to Alpine 3.21.
* **21.10.24:** - Fix naming issue with Dynu plugin. If you are using Dynu, please make sure your credentials are set in /config/dns-conf/dynu.ini and your DNSPLUGIN variable is set to dynu (not dynudns).
* **30.08.24:** - Fix zerossl cert revocation. * **30.08.24:** - Fix zerossl cert revocation.
* **24.07.14:** - Rebase to Alpine 3.20. Remove deprecated Google Domains certbot plugin. Existing users should update their nginx confs to avoid http2 deprecation warnings. * **24.07.14:** - Rebase to Alpine 3.20. Remove deprecated Google Domains certbot plugin. Existing users should update their nginx confs to avoid http2 deprecation warnings.
* **01.07.24:** - Fall back to iptables-legacy if iptables doesn't work. * **01.07.24:** - Fall back to iptables-legacy if iptables doesn't work.

View File

@@ -17,12 +17,12 @@ repo_vars:
- PR_DOCKERHUB_IMAGE = 'lspipepr/swag' - PR_DOCKERHUB_IMAGE = 'lspipepr/swag'
- DIST_IMAGE = 'alpine' - DIST_IMAGE = 'alpine'
- MULTIARCH='true' - MULTIARCH='true'
- CI='false' - CI='true'
- CI_WEB='false' - CI_WEB='false'
- CI_PORT='80' - CI_PORT='80'
- CI_SSL='false' - CI_SSL='false'
- CI_DELAY='30' - CI_DELAY='30'
- CI_DOCKERENV='' - CI_DOCKERENV='TEST_RUN=1'
- CI_AUTH='' - CI_AUTH=''
- CI_WEBPATH='' - CI_WEBPATH=''
sponsor_links: sponsor_links:

View File

@@ -1,369 +1,362 @@
NAME VERSION TYPE NAME VERSION TYPE
Simple Launcher 1.1.0.14 binary (+5 duplicates) Simple Launcher 1.1.0.14 dotnet (+5 duplicates)
acl-libs 2.3.2-r1 apk acme 2.11.0 python
acme 5.4.0 python alpine-baselayout 3.6.5-r0 apk
alpine-baselayout 3.7.0-r0 apk alpine-baselayout-data 3.6.5-r0 apk
alpine-baselayout-data 3.7.0-r0 apk alpine-keys 2.4-r1 apk
alpine-keys 2.5-r0 apk alpine-release 3.20.2-r0 apk
alpine-release 3.22.3-r0 apk aom-libs 3.9.1-r0 apk
aom-libs 3.12.1-r0 apk apache2-utils 2.4.62-r0 apk
apache2-utils 2.4.66-r0 apk apk-tools 2.14.4-r0 apk
apk-tools 2.14.9-r3 apk
apr 1.7.5-r0 apk apr 1.7.5-r0 apk
apr-util 1.6.3-r1 apk apr-util 1.6.3-r1 apk
argon2-libs 20190702-r5 apk argon2-libs 20190702-r5 apk
attrs 25.4.0 python attrs 24.2.0 python
autocommand 2.2.2 python autocommand 2.2.2 python
azure-common 1.1.28 python azure-common 1.1.28 python
azure-core 1.38.2 python azure-core 1.30.2 python
azure-identity 1.25.2 python azure-identity 1.17.1 python
azure-mgmt-core 1.6.0 python azure-mgmt-core 1.4.0 python
azure-mgmt-dns 9.0.0 python azure-mgmt-dns 8.1.0 python
backports-tarfile 1.2.0 python backports-tarfile 1.2.0 python
bash 5.2.37-r0 apk bash 5.2.26-r0 apk
beautifulsoup4 4.14.3 python beautifulsoup4 4.12.3 python
boto3 1.42.64 python boto3 1.35.14 python
botocore 1.42.64 python botocore 1.35.14 python
brotli-libs 1.1.0-r2 apk brotli-libs 1.1.0-r2 apk
bs4 0.0.2 python bs4 0.0.2 python
busybox 1.37.0-r20 apk busybox 1.36.1-r29 apk
busybox-binsh 1.37.0-r20 apk busybox-binsh 1.36.1-r29 apk
c-ares 1.34.6-r0 apk c-ares 1.28.1-r0 apk
c-client 2007f-r15 apk c-client 2007f-r15 apk
ca-certificates 20250911-r0 apk ca-certificates 20240705-r0 apk
ca-certificates-bundle 20250911-r0 apk ca-certificates-bundle 20240705-r0 apk
catatonit 0.2.1-r0 apk cachetools 5.5.0 python
certbot 5.4.0 python catatonit 0.2.0-r0 apk
certbot 2.11.0 python
certbot-dns-acmedns 0.1.0 python certbot-dns-acmedns 0.1.0 python
certbot-dns-aliyun 2.0.0 python certbot-dns-aliyun 2.0.0 python
certbot-dns-azure 1.5.0 python certbot-dns-azure 2.5.0 python
certbot-dns-bunny 3.0.0 python certbot-dns-bunny 0.0.9 python
certbot-dns-cloudflare 5.4.0 python certbot-dns-cloudflare 2.11.0 python
certbot-dns-cpanel 0.4.0 python certbot-dns-cpanel 0.4.0 python
certbot-dns-desec 1.3.2 python certbot-dns-desec 1.2.1 python
certbot-dns-digitalocean 5.4.0 python certbot-dns-digitalocean 2.11.0 python
certbot-dns-directadmin 1.0.15 python certbot-dns-directadmin 1.0.4 python
certbot-dns-dnsimple 5.4.0 python certbot-dns-dnsimple 2.11.0 python
certbot-dns-dnsmadeeasy 5.4.0 python certbot-dns-dnsmadeeasy 2.11.0 python
certbot-dns-dnspod 0.1.0 python certbot-dns-dnspod 0.1.0 python
certbot-dns-do 0.31.0 python certbot-dns-do 0.31.0 python
certbot-dns-domeneshop 0.2.9 python certbot-dns-domeneshop 0.2.9 python
certbot-dns-dreamhost 1.0 python certbot-dns-dreamhost 1.0 python
certbot-dns-duckdns 1.8.0 python certbot-dns-duckdns 1.3 python
certbot-dns-dynudns 0.0.6 python certbot-dns-dynudns 0.0.6 python
certbot-dns-freedns 0.2.0 python certbot-dns-freedns 0.2.0 python
certbot-dns-gehirn 5.4.0 python certbot-dns-gehirn 2.11.0 python
certbot-dns-glesys 2.1.0 python certbot-dns-glesys 2.1.0 python
certbot-dns-godaddy 2.8.0 python certbot-dns-godaddy 2.8.0 python
certbot-dns-google 5.4.0 python certbot-dns-google 2.11.0 python
certbot-dns-he 1.0.0 python certbot-dns-he 1.0.0 python
certbot-dns-hetzner 3.0.0 python certbot-dns-hetzner 2.0.1 python
certbot-dns-hetzner-cloud 1.0.5 python certbot-dns-infomaniak 0.2.2 python
certbot-dns-infomaniak 0.2.4 python certbot-dns-inwx 2.2.0 python
certbot-dns-inwx 3.0.3 python certbot-dns-ionos 2024.1.8 python
certbot-dns-ionos 2024.11.9 python certbot-dns-linode 2.11.0 python
certbot-dns-linode 5.4.0 python
certbot-dns-loopia 1.0.1 python certbot-dns-loopia 1.0.1 python
certbot-dns-luadns 5.4.0 python certbot-dns-luadns 2.11.0 python
certbot-dns-namecheap 1.0.0 python certbot-dns-namecheap 1.0.0 python
certbot-dns-netcup 2.0.0 python certbot-dns-netcup 1.4.3 python
certbot-dns-njalla 2.0.2 python certbot-dns-njalla 1.0.0 python
certbot-dns-nsone 5.4.0 python certbot-dns-nsone 2.11.0 python
certbot-dns-ovh 5.4.0 python certbot-dns-ovh 2.11.0 python
certbot-dns-porkbun 0.11.0 python certbot-dns-porkbun 0.8 python
certbot-dns-rfc2136 5.4.0 python certbot-dns-rfc2136 2.11.0 python
certbot-dns-route53 5.4.0 python certbot-dns-route53 2.11.0 python
certbot-dns-sakuracloud 5.4.0 python certbot-dns-sakuracloud 2.11.0 python
certbot-dns-standalone 1.2.1 python certbot-dns-standalone 1.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.2.25 python certifi 2024.8.30 python
cffi 2.0.0 python cffi 1.17.1 python
charset-normalizer 3.4.5 python charset-normalizer 3.3.2 python
cli UNKNOWN binary
cli-32 UNKNOWN binary
cli-64 UNKNOWN binary
cli-arm64 UNKNOWN binary
cloudflare 2.19.4 python cloudflare 2.19.4 python
composer 2.9.5 binary composer 2.7.9 binary
configargparse 1.7.3 python configargparse 1.7 python
configobj 5.0.9 python configobj 5.0.8 python
coreutils 9.7-r1 apk coreutils 9.5-r1 apk
coreutils-env 9.7-r1 apk coreutils-env 9.5-r1 apk
coreutils-fmt 9.7-r1 apk coreutils-fmt 9.5-r1 apk
coreutils-sha512sum 9.7-r1 apk coreutils-sha512sum 9.5-r1 apk
cryptography 46.0.5 python cryptography 43.0.1 python
curl 8.14.1-r2 apk curl 8.9.1-r1 apk
distro 1.9.0 python distro 1.9.0 python
dns-lexicon 3.23.2 python dns-lexicon 3.18.0 python
dns-lexicon-coop 3.24.2 python dnslib 0.9.25 python
dnslib 0.9.26 python dnspython 2.6.1 python
dnspython 2.8.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-r0 apk
fail2ban-pyc 1.1.0-r3 apk fail2ban-pyc 1.1.0-r0 apk
filelock 3.25.1 python filelock 3.15.4 python
findutils 4.10.0-r0 apk findutils 4.9.0-r5 apk
fontconfig 2.15.0-r3 apk fontconfig 2.15.0-r1 apk
freetype 2.13.3-r0 apk freetype 2.13.2-r0 apk
future 1.0.0 python future 1.0.0 python
gdbm 1.24-r0 apk gdbm 1.23-r1 apk
git 2.49.1-r0 apk git 2.45.2-r0 apk
git-init-template 2.49.1-r0 apk git-init-template 2.45.2-r0 apk
git-perl 2.49.1-r0 apk git-perl 2.45.2-r0 apk
gmp 6.3.0-r3 apk gmp 6.3.0-r1 apk
gnupg 2.4.9-r0 apk gnupg 2.4.5-r0 apk
gnupg-dirmngr 2.4.9-r0 apk gnupg-dirmngr 2.4.5-r0 apk
gnupg-gpgconf 2.4.9-r0 apk gnupg-gpgconf 2.4.5-r0 apk
gnupg-keyboxd 2.4.9-r0 apk gnupg-keyboxd 2.4.5-r0 apk
gnupg-utils 2.4.9-r0 apk gnupg-utils 2.4.5-r0 apk
gnupg-wks-client 2.4.9-r0 apk gnupg-wks-client 2.4.5-r0 apk
gnutls 3.8.12-r0 apk gnutls 3.8.5-r0 apk
google-api-core 2.30.0 python google-api-core 2.19.2 python
google-api-python-client 2.192.0 python google-api-python-client 2.144.0 python
google-auth 2.49.0 python google-auth 2.34.0 python
google-auth-httplib2 0.3.0 python google-auth-httplib2 0.2.0 python
googleapis-common-protos 1.73.0 python googleapis-common-protos 1.65.0 python
gpg 2.4.9-r0 apk gpg 2.4.5-r0 apk
gpg-agent 2.4.9-r0 apk gpg-agent 2.4.5-r0 apk
gpg-wks-server 2.4.9-r0 apk gpg-wks-server 2.4.5-r0 apk
gpgsm 2.4.9-r0 apk gpgsm 2.4.5-r0 apk
gpgv 2.4.9-r0 apk gpgv 2.4.5-r0 apk
gui UNKNOWN binary httplib2 0.22.0 python
gui-32 UNKNOWN binary icu-data-en 74.2-r0 apk
gui-64 UNKNOWN binary icu-libs 74.2-r0 apk
gui-arm64 UNKNOWN binary idna 3.8 python
hcloud 2.17.0 python importlib-metadata 8.0.0 python
httplib2 0.31.2 python importlib-resources 6.4.0 python
icu-data-en 76.1-r1 apk inflect 7.3.1 python
icu-libs 76.1-r1 apk iptables 1.8.10-r3 apk
idna 3.11 python iptables-legacy 1.8.10-r3 apk
importlib-metadata 8.7.1 python isodate 0.6.1 python
inotify-tools 4.23.9.0-r0 apk jaraco-context 5.3.0 python
inotify-tools-libs 4.23.9.0-r0 apk jaraco-functools 4.0.1 python
inwx-domrobot 3.2.0 python jaraco-text 3.12.1 python
iptables 1.8.11-r1 apk jmespath 1.0.1 python
iptables-legacy 1.8.11-r1 apk josepy 1.14.0 python
isodate 0.7.2 python jq 1.7.1-r0 apk
jaraco-context 6.1.0 python
jaraco-functools 4.4.0 python
jaraco-text 4.0.0 python
jinja2 3.1.6 python
jmespath 1.1.0 python
josepy 2.2.0 python
jq 1.8.1-r0 apk
jsonlines 4.0.0 python jsonlines 4.0.0 python
jsonpickle 4.1.1 python jsonpickle 3.3.0 python
libapk2 2.14.9-r3 apk libacl 2.3.2-r0 apk
libassuan 2.5.7-r0 apk libassuan 2.5.7-r0 apk
libattr 2.5.2-r2 apk libattr 2.5.2-r0 apk
libavif 1.3.0-r0 apk libavif 1.0.4-r0 apk
libbsd 0.12.2-r0 apk libbsd 0.12.2-r0 apk
libbz2 1.0.8-r6 apk libbz2 1.0.8-r6 apk
libcrypto3 3.5.5-r0 apk libcrypto3 3.3.2-r0 apk
libcurl 8.14.1-r2 apk libcurl 8.9.1-r1 apk
libdav1d 1.5.1-r0 apk libdav1d 1.4.2-r0 apk
libedit 20250104.3.1-r1 apk libedit 20240517.3.1-r0 apk
libevent 2.1.12-r8 apk libevent 2.1.12-r7 apk
libexpat 2.7.4-r0 apk libexpat 2.6.3-r0 apk
libffi 3.4.8-r0 apk libffi 3.4.6-r0 apk
libgcc 14.2.0-r6 apk libgcc 13.2.1_git20240309-r0 apk
libgcrypt 1.10.3-r1 apk libgcrypt 1.10.3-r0 apk
libgd 2.3.3-r10 apk libgd 2.3.3-r9 apk
libgpg-error 1.55-r0 apk libgpg-error 1.49-r0 apk
libice 1.1.2-r0 apk libice 1.1.1-r6 apk
libidn2 2.3.7-r0 apk libidn2 2.3.7-r0 apk
libintl 0.24.1-r0 apk libintl 0.22.5-r0 apk
libip4tc 1.8.11-r1 apk libip4tc 1.8.10-r3 apk
libip6tc 1.8.11-r1 apk libip6tc 1.8.10-r3 apk
libjpeg-turbo 3.1.0-r0 apk libjpeg-turbo 3.0.3-r0 apk
libksba 1.6.7-r0 apk libksba 1.6.6-r0 apk
libldap 2.6.8-r0 apk libldap 2.6.7-r0 apk
libmaxminddb-libs 1.9.1-r0 apk libmaxminddb-libs 1.9.1-r0 apk
libmcrypt 2.5.8-r10 apk
libmd 1.1.0-r0 apk libmd 1.1.0-r0 apk
libmemcached-libs 1.1.4-r1 apk libmemcached-libs 1.1.4-r1 apk
libmnl 1.0.5-r2 apk libmnl 1.0.5-r2 apk
libncursesw 6.5_p20250503-r0 apk libncursesw 6.4_p20240420-r0 apk
libnftnl 1.2.9-r0 apk libnftnl 1.2.6-r0 apk
libpanelw 6.5_p20250503-r0 apk libpanelw 6.4_p20240420-r0 apk
libpng 1.6.55-r0 apk libpng 1.6.43-r0 apk
libpq 17.8-r0 apk libpq 16.3-r0 apk
libproc2 4.0.4-r3 apk libproc2 4.0.4-r0 apk
libpsl 0.21.5-r3 apk libpsl 0.21.5-r1 apk
libsasl 2.1.28-r8 apk libsasl 2.1.28-r6 apk
libseccomp 2.6.0-r0 apk libseccomp 2.5.5-r1 apk
libsharpyuv 1.5.0-r0 apk libsharpyuv 1.3.2-r0 apk
libsm 1.2.5-r0 apk libsm 1.2.4-r4 apk
libsodium 1.0.20-r1 apk libsodium 1.0.19-r0 apk
libssl3 3.5.5-r0 apk libssl3 3.3.2-r0 apk
libstdc++ 14.2.0-r6 apk libstdc++ 13.2.1_git20240309-r0 apk
libtasn1 4.21.0-r0 apk libtasn1 4.19.0-r2 apk
libunistring 1.3-r0 apk libunistring 1.2-r0 apk
libuuid 2.41-r9 apk libuuid 2.40.1-r1 apk
libwebp 1.5.0-r0 apk libwebp 1.3.2-r0 apk
libx11 1.8.11-r0 apk libx11 1.8.9-r1 apk
libxau 1.0.12-r0 apk libxau 1.0.11-r4 apk
libxcb 1.17.0-r0 apk libxcb 1.16.1-r0 apk
libxdmcp 1.1.5-r1 apk libxdmcp 1.1.5-r1 apk
libxext 1.3.6-r2 apk libxext 1.3.6-r2 apk
libxml2 2.13.9-r0 apk libxml2 2.12.7-r0 apk
libxpm 3.5.17-r0 apk libxpm 3.5.17-r0 apk
libxslt 1.1.43-r3 apk libxslt 1.1.39-r1 apk
libxt 1.3.1-r0 apk libxt 1.3.0-r5 apk
libxtables 1.8.11-r1 apk libxtables 1.8.10-r3 apk
libyuv 0.0.1887.20251502-r1 apk libzip 1.10.1-r0 apk
libzip 1.11.4-r0 apk linux-pam 1.6.0-r0 apk
linux-pam 1.7.0-r4 apk
logrotate 3.21.0-r1 apk logrotate 3.21.0-r1 apk
loopialib 0.2.0 python loopialib 0.2.0 python
lxml 6.0.2 python lxml 5.3.0 python
lz4-libs 1.10.0-r0 apk lz4-libs 1.9.4-r5 apk
markupsafe 3.0.3 python memcached 1.6.27-r0 apk
memcached 1.6.32-r0 apk mock 5.1.0 python
mock 5.2.0 python more-itertools 10.3.0 python
more-itertools 10.8.0 python mpdecimal 4.0.0-r0 apk
mpdecimal 4.0.1-r0 apk msal 1.31.0 python
msal 1.35.1 python msal-extensions 1.2.0 python
msal-extensions 1.3.1 python musl 1.2.5-r0 apk
musl 1.2.5-r10 apk musl-utils 1.2.5-r0 apk
musl-utils 1.2.5-r10 apk my-test-package 1.0 python
nano 8.4-r0 apk nano 8.0-r0 apk
ncurses-terminfo-base 6.5_p20250503-r0 apk ncurses-terminfo-base 6.4_p20240420-r0 apk
netcat-openbsd 1.229.1-r0 apk netcat-openbsd 1.226-r0 apk
nettle 3.10.2-r0 apk nettle 3.9.1-r0 apk
nghttp2-libs 1.65.0-r0 apk nghttp2-libs 1.62.1-r0 apk
nginx 1.28.2-r0 apk nginx 1.26.2-r0 apk
nginx-mod-devel-kit 1.28.2-r0 apk nginx-mod-devel-kit 1.26.2-r0 apk
nginx-mod-http-brotli 1.28.2-r0 apk nginx-mod-http-brotli 1.26.2-r0 apk
nginx-mod-http-dav-ext 1.28.2-r0 apk nginx-mod-http-dav-ext 1.26.2-r0 apk
nginx-mod-http-echo 1.28.2-r0 apk nginx-mod-http-echo 1.26.2-r0 apk
nginx-mod-http-fancyindex 1.28.2-r0 apk nginx-mod-http-fancyindex 1.26.2-r0 apk
nginx-mod-http-geoip2 1.28.2-r0 apk nginx-mod-http-geoip2 1.26.2-r0 apk
nginx-mod-http-headers-more 1.28.2-r0 apk nginx-mod-http-headers-more 1.26.2-r0 apk
nginx-mod-http-image-filter 1.28.2-r0 apk nginx-mod-http-image-filter 1.26.2-r0 apk
nginx-mod-http-perl 1.28.2-r0 apk nginx-mod-http-perl 1.26.2-r0 apk
nginx-mod-http-redis2 1.28.2-r0 apk nginx-mod-http-redis2 1.26.2-r0 apk
nginx-mod-http-set-misc 1.28.2-r0 apk nginx-mod-http-set-misc 1.26.2-r0 apk
nginx-mod-http-upload-progress 1.28.2-r0 apk nginx-mod-http-upload-progress 1.26.2-r0 apk
nginx-mod-http-xslt-filter 1.28.2-r0 apk nginx-mod-http-xslt-filter 1.26.2-r0 apk
nginx-mod-mail 1.28.2-r0 apk nginx-mod-mail 1.26.2-r0 apk
nginx-mod-rtmp 1.28.2-r0 apk nginx-mod-rtmp 1.26.2-r0 apk
nginx-mod-stream 1.28.2-r0 apk nginx-mod-stream 1.26.2-r0 apk
nginx-mod-stream-geoip2 1.28.2-r0 apk nginx-mod-stream-geoip2 1.26.2-r0 apk
nginx-vim 1.28.2-r0 apk nginx-vim 1.26.2-r0 apk
npth 1.8-r0 apk npth 1.6-r4 apk
oniguruma 6.9.10-r0 apk oniguruma 6.9.9-r0 apk
openssl 3.5.5-r0 apk openssl 3.3.2-r0 apk
p11-kit 0.25.5-r2 apk p11-kit 0.25.3-r0 apk
packaging 26.0 python (+1 duplicate) packaging 24.1 python
parsedatetime 2.6 python parsedatetime 2.6 python
pcre2 10.46-r0 apk pcre 8.45-r3 apk
perl 5.40.3-r0 apk pcre2 10.43-r0 apk
perl-error 0.17030-r0 apk perl 5.38.2-r0 apk
perl-git 2.49.1-r0 apk perl-error 0.17029-r2 apk
php84 8.4.16-r0 apk perl-git 2.45.2-r0 apk
php84-bcmath 8.4.16-r0 apk php83 8.3.10-r0 apk
php84-bz2 8.4.16-r0 apk php83-bcmath 8.3.10-r0 apk
php84-common 8.4.16-r0 apk php83-bz2 8.3.10-r0 apk
php84-ctype 8.4.16-r0 apk php83-common 8.3.10-r0 apk
php84-curl 8.4.16-r0 apk php83-ctype 8.3.10-r0 apk
php84-dom 8.4.16-r0 apk php83-curl 8.3.10-r0 apk
php84-exif 8.4.16-r0 apk php83-dom 8.3.10-r0 apk
php84-fileinfo 8.4.16-r0 apk php83-exif 8.3.10-r0 apk
php84-fpm 8.4.16-r0 apk php83-fileinfo 8.3.10-r0 apk
php84-ftp 8.4.16-r0 apk php83-fpm 8.3.10-r0 apk
php84-gd 8.4.16-r0 apk php83-ftp 8.3.10-r0 apk
php84-gmp 8.4.16-r0 apk php83-gd 8.3.10-r0 apk
php84-iconv 8.4.16-r0 apk php83-gmp 8.3.10-r0 apk
php84-intl 8.4.16-r0 apk php83-iconv 8.3.10-r0 apk
php84-ldap 8.4.16-r0 apk php83-imap 8.3.10-r0 apk
php84-mbstring 8.4.16-r0 apk php83-intl 8.3.10-r0 apk
php84-mysqli 8.4.16-r0 apk php83-ldap 8.3.10-r0 apk
php84-mysqlnd 8.4.16-r0 apk php83-mbstring 8.3.10-r0 apk
php84-opcache 8.4.16-r0 apk php83-mysqli 8.3.10-r0 apk
php84-openssl 8.4.16-r0 apk php83-mysqlnd 8.3.10-r0 apk
php84-pdo 8.4.16-r0 apk php83-opcache 8.3.10-r0 apk
php84-pdo_mysql 8.4.16-r0 apk php83-openssl 8.3.10-r0 apk
php84-pdo_odbc 8.4.16-r0 apk php83-pdo 8.3.10-r0 apk
php84-pdo_pgsql 8.4.16-r0 apk php83-pdo_mysql 8.3.10-r0 apk
php84-pdo_sqlite 8.4.16-r0 apk php83-pdo_odbc 8.3.10-r0 apk
php84-pear 8.4.16-r0 apk php83-pdo_pgsql 8.3.10-r0 apk
php84-pecl-apcu 5.1.27-r0 apk php83-pdo_sqlite 8.3.10-r0 apk
php84-pecl-igbinary 3.2.16-r1 apk php83-pear 8.3.10-r0 apk
php84-pecl-imap 1.0.3-r0 apk php83-pecl-apcu 5.1.23-r0 apk
php84-pecl-memcached 3.3.0-r0 apk php83-pecl-igbinary 3.2.15-r0 apk
php84-pecl-msgpack 3.0.0-r0 apk php83-pecl-mcrypt 1.0.7-r0 apk
php84-pecl-redis 6.3.0-r0 apk php83-pecl-memcached 3.2.0-r0 apk
php84-pgsql 8.4.16-r0 apk php83-pecl-msgpack 2.2.0-r2 apk
php84-phar 8.4.16-r0 apk php83-pecl-redis 6.0.2-r0 apk
php84-posix 8.4.16-r0 apk php83-pgsql 8.3.10-r0 apk
php84-session 8.4.16-r0 apk php83-phar 8.3.10-r0 apk
php84-simplexml 8.4.16-r0 apk php83-posix 8.3.10-r0 apk
php84-soap 8.4.16-r0 apk php83-session 8.3.10-r0 apk
php84-sockets 8.4.16-r0 apk php83-simplexml 8.3.10-r0 apk
php84-sodium 8.4.16-r0 apk php83-soap 8.3.10-r0 apk
php84-sqlite3 8.4.16-r0 apk php83-sockets 8.3.10-r0 apk
php84-tokenizer 8.4.16-r0 apk php83-sodium 8.3.10-r0 apk
php84-xml 8.4.16-r0 apk php83-sqlite3 8.3.10-r0 apk
php84-xmlreader 8.4.16-r0 apk php83-tokenizer 8.3.10-r0 apk
php84-xmlwriter 8.4.16-r0 apk php83-xml 8.3.10-r0 apk
php84-xsl 8.4.16-r0 apk php83-xmlreader 8.3.10-r0 apk
php84-zip 8.4.16-r0 apk php83-xmlwriter 8.3.10-r0 apk
pinentry 1.3.1-r0 apk php83-xsl 8.3.10-r0 apk
pip 26.0.1 python php83-zip 8.3.10-r0 apk
pkb-client 2.2.0 python pinentry 1.3.0-r0 apk
platformdirs 4.4.0 python pip 24.2 python
popt 1.19-r4 apk pkb-client 1.2 python
procps-ng 4.0.4-r3 apk platformdirs 4.2.2 python
proto-plus 1.27.1 python popt 1.19-r3 apk
protobuf 6.33.5 python portalocker 2.10.1 python
procps-ng 4.0.4-r0 apk
proto-plus 1.24.0 python
protobuf 5.28.0 python
pyacmedns 0.4 python pyacmedns 0.4 python
pyasn1 0.6.2 python pyasn1 0.6.0 python
pyasn1-modules 0.4.2 python pyasn1-modules 0.4.0 python
pyc 3.12.12-r0 apk pyc 3.12.3-r2 apk
pycparser 3.0 python pycparser 2.22 python
pyjwt 2.11.0 python pyjwt 2.9.0 python
pynamecheap 0.0.3 python pynamecheap 0.0.3 python
pyopenssl 25.3.0 python pyopenssl 24.2.1 python
pyotp 2.9.0 python pyotp 2.9.0 python
pyparsing 3.3.2 python pyparsing 3.1.4 python
pyrfc3339 2.1.0 python pyrfc3339 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
python3 3.12.12-r0 apk python3 3.12.3-r2 apk
python3-pyc 3.12.12-r0 apk python3-pyc 3.12.3-r2 apk
python3-pycache-pyc0 3.12.12-r0 apk python3-pycache-pyc0 3.12.3-r2 apk
pyyaml 6.0.3 python pytz 2024.1 python
readline 8.2.13-r1 apk pyyaml 6.0.2 python
requests 2.32.5 python readline 8.2.10-r0 apk
requests-file 3.0.1 python requests 2.32.3 python
requests-file 2.1.0 python
requests-mock 1.12.1 python requests-mock 1.12.1 python
rsa 4.9.1 python rsa 4.9 python
s3transfer 0.16.0 python s3transfer 0.10.2 python
scanelf 1.3.8-r1 apk scanelf 1.3.7-r2 apk
setuptools 82.0.1 python setuptools 74.1.2 python
shadow 4.17.3-r0 apk shadow 4.15.1-r0 apk
six 1.17.0 python six 1.16.0 python
skalibs-libs 2.14.4.0-r0 apk skalibs 2.14.1.1-r0 apk
soupsieve 2.8.3 python soupsieve 2.6 python
sqlite-libs 3.49.2-r1 apk sqlite-libs 3.45.3-r1 apk
ssl_client 1.37.0-r20 apk ssl_client 1.36.1-r29 apk
tiff 4.7.1-r0 apk tiff 4.6.0t-r0 apk
tldextract 5.3.1 python tldextract 5.1.2 python
tomli 2.4.0 python tomli 2.0.1 python
typing-extensions 4.15.0 python typeguard 4.3.0 python
tzdata 2025c-r0 apk typing-extensions 4.12.2 python (+1 duplicate)
tzdata 2024a-r1 apk
unixodbc 2.3.12-r0 apk unixodbc 2.3.12-r0 apk
uritemplate 4.2.0 python uritemplate 4.1.1 python
urllib3 2.6.3 python urllib3 2.2.2 python
utmps-libs 0.1.3.1-r0 apk utmps-libs 0.1.2.2-r1 apk
wheel 0.46.3 python (+1 duplicate) wheel 0.43.0 python
whois 5.6.3-r0 apk wheel 0.44.0 python
xz-libs 5.8.1-r0 apk whois 5.5.23-r0 apk
zipp 3.23.0 python xz-libs 5.6.2-r0 apk
zlib 1.3.1-r2 apk zipp 3.19.2 python
zope-interface 8.2 python zlib 1.3.1-r1 apk
zstd-libs 1.5.7-r0 apk zope-interface 7.0.3 python
zstd-libs 1.5.6-r0 apk

View File

@@ -6,49 +6,44 @@ project_url: "https://linuxserver.io"
project_logo: "https://github.com/linuxserver/docker-templates/raw/master/linuxserver.io/img/swag.gif" project_logo: "https://github.com/linuxserver/docker-templates/raw/master/linuxserver.io/img/swag.gif"
project_blurb: "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." project_blurb: "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."
project_lsio_github_repo_url: "https://github.com/linuxserver/docker-{{ project_name }}" project_lsio_github_repo_url: "https://github.com/linuxserver/docker-{{ project_name }}"
project_categories: "Reverse Proxy"
# supported architectures # supported architectures
available_architectures: available_architectures:
- { arch: "{{ arch_x86_64 }}", tag: "amd64-latest"} - { arch: "{{ arch_x86_64 }}", tag: "amd64-latest"}
- { arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"} - { arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"}
# container parameters # container parameters
common_param_env_vars_enabled: true common_param_env_vars_enabled: true
param_container_name: "{{ project_name }}" param_container_name: "{{ project_name }}"
param_usage_include_env: true param_usage_include_env: true
param_env_vars: param_env_vars:
- {env_var: "URL", env_value: "example.com", desc: "Top url you have control over (e.g. `example.com` if you own it, or `customsubdomain.example.com` if dynamic dns)."} - { env_var: "URL", env_value: "yourdomain.url", desc: "Top url you have control over (`customdomain.com` if you own it, or `customsubdomain.ddnsprovider.com` if dynamic dns)." }
- { env_var: "VALIDATION", env_value: "http", desc: "Certbot validation method to use, options are `http` or `dns` (`dns` method also requires `DNSPLUGIN` variable set).", env_options: ["http", "dns"] } - { env_var: "VALIDATION", env_value: "http", desc: "Certbot validation method to use, options are `http` or `dns` (`dns` method also requires `DNSPLUGIN` variable set).", env_options: ["http", "dns"] }
param_usage_include_vols: true param_usage_include_vols: true
param_volumes: param_volumes:
- { vol_path: "/config", vol_host_path: "/path/to/{{ project_name }}/config", desc: "Persistent config files" } - { vol_path: "/config", vol_host_path: "/path/to/{{ project_name }}/config", desc: "Persistent config files" }
param_usage_include_ports: true param_usage_include_ports: true
param_ports: param_ports:
- {external_port: "443", internal_port: "443", port_desc: "HTTPS port"} - { external_port: "443", internal_port: "443", port_desc: "Https port" }
cap_add_param: true cap_add_param: true
cap_add_param_vars: cap_add_param_vars:
- {cap_add_var: "NET_ADMIN", desc: "Required for fail2Ban to be able to modify iptables rules."} - { cap_add_var: "NET_ADMIN" }
# optional container parameters # optional container parameters
opt_param_usage_include_env: true opt_param_usage_include_env: true
opt_param_env_vars: opt_param_env_vars:
- { env_var: "SUBDOMAINS", env_value: "www,", desc: "Subdomains you'd like the cert to cover (comma separated, no spaces) ie. `www,ftp,cloud`. For a wildcard cert, set this *exactly* to `wildcard` (wildcard cert is available via `dns` validation only)" } - { env_var: "SUBDOMAINS", env_value: "www,", desc: "Subdomains you'd like the cert to cover (comma separated, no spaces) ie. `www,ftp,cloud`. For a wildcard cert, set this *exactly* to `wildcard` (wildcard cert is available via `dns` validation only)" }
- { env_var: "CERTPROVIDER", env_value: "", desc: "Optionally define the cert provider. Set to `zerossl` for ZeroSSL certs (requires existing [ZeroSSL account](https://app.zerossl.com/signup) and the e-mail address entered in `EMAIL` env var). Otherwise defaults to Let's Encrypt." } - { env_var: "CERTPROVIDER", env_value: "", desc: "Optionally define the cert provider. Set to `zerossl` for ZeroSSL certs (requires existing [ZeroSSL account](https://app.zerossl.com/signup) and the e-mail address entered in `EMAIL` env var). Otherwise defaults to Let's Encrypt." }
- {env_var: "DNSPLUGIN", env_value: "cloudflare", desc: "Required if `VALIDATION` is set to `dns`. Options are `acmedns`, `aliyun`, `azure`, `bunny`, `cloudflare`, `cpanel`, `desec`, `digitalocean`, `directadmin`, `dnsimple`, `dnsmadeeasy`, `dnspod`, `do`, `domeneshop`, `dreamhost`, `duckdns`, `dynu`, `freedns`, `gandi`, `gehirn`, `glesys`, `godaddy`, `google`, `he`, `hetzner`, `hetzner-cloud`, `infomaniak`, `inwx`, `ionos`, `linode`, `loopia`, `luadns`, `namecheap`, `netcup`, `njalla`, `nsone`, `ovh`, `porkbun`, `rfc2136`, `route53`, `sakuracloud`, `standalone`, `transip`, and `vultr`. Also need to enter the credentials into the corresponding ini (or json for some plugins) file under `/config/dns-conf`."} - { env_var: "DNSPLUGIN", env_value: "cloudflare", desc: "Required if `VALIDATION` is set to `dns`. Options are `acmedns`, `aliyun`, `azure`, `bunny`, `cloudflare`, `cpanel`, `desec`, `digitalocean`, `directadmin`, `dnsimple`, `dnsmadeeasy`, `dnspod`, `do`, `domeneshop`, `dreamhost`, `duckdns`, `dynudns`, `freedns`, `gandi`, `gehirn`, `glesys`, `godaddy`, `google`, `he`, `hetzner`, `infomaniak`, `inwx`, `ionos`, `linode`, `loopia`, `luadns`, `namecheap`, `netcup`, `njalla`, `nsone`, `ovh`, `porkbun`, `rfc2136`, `route53`, `sakuracloud`, `standalone`, `transip`, and `vultr`. Also need to enter the credentials into the corresponding ini (or json for some plugins) file under `/config/dns-conf`." }
- { env_var: "PROPAGATION", env_value: "", desc: "Optionally override (in seconds) the default propagation time for the dns plugins." } - { env_var: "PROPAGATION", env_value: "", desc: "Optionally override (in seconds) the default propagation time for the dns plugins." }
- { env_var: "EMAIL", env_value: "", desc: "Optional e-mail address used for cert expiration notifications (Required for ZeroSSL)." } - { env_var: "EMAIL", env_value: "", desc: "Optional e-mail address used for cert expiration notifications (Required for ZeroSSL)." }
- { env_var: "ONLY_SUBDOMAINS", env_value: "false", desc: "If you wish to get certs only for certain subdomains, but not the main domain (main domain may be hosted on another machine and cannot be validated), set this to `true`" } - { env_var: "ONLY_SUBDOMAINS", env_value: "false", desc: "If you wish to get certs only for certain subdomains, but not the main domain (main domain may be hosted on another machine and cannot be validated), set this to `true`" }
- {env_var: "EXTRA_DOMAINS", env_value: "", desc: "Additional fully qualified domain names (comma separated, no spaces) ie. `example.net,subdomain.example.net,*.example.org`"} - { env_var: "EXTRA_DOMAINS", env_value: "", desc: "Additional fully qualified domain names (comma separated, no spaces) ie. `extradomain.com,subdomain.anotherdomain.org,*.anotherdomain.org`" }
- { env_var: "STAGING", env_value: "false", desc: "Set to `true` to retrieve certs in staging mode. Rate limits will be much higher, but the resulting cert will not pass the browser's security test. Only to be used for testing purposes." } - { env_var: "STAGING", env_value: "false", desc: "Set to `true` to retrieve certs in staging mode. Rate limits will be much higher, but the resulting cert will not pass the browser's security test. Only to be used for testing purposes." }
- {env_var: "DISABLE_F2B", env_value: "", desc: "Set to `true` to disable the Fail2ban service in the container, if you're already running it elsewhere or using a different IPS."}
- {env_var: "SWAG_AUTORELOAD", env_value: "", desc: "Set to `true` to enable automatic reloading of confs on change without stopping/restarting nginx. Your filesystem must support inotify. This functionality was previously offered [via mod](https://github.com/linuxserver/docker-mods/tree/swag-auto-reload)."}
- {env_var: "SWAG_AUTORELOAD_WATCHLIST", env_value: "", desc: "A [pipe](https://en.wikipedia.org/wiki/Vertical_bar)-separated list of additional folders for auto reload to watch in addition to `/config/nginx`"}
opt_param_usage_include_ports: true opt_param_usage_include_ports: true
opt_param_ports: opt_param_ports:
- {external_port: "80", internal_port: "80", port_desc: "HTTP port (required for HTTP validation and HTTP -> HTTPS redirect)"} - { external_port: "80", internal_port: "80", port_desc: "Http port (required for http validation and http -> https redirect)" }
- {external_port: "443", internal_port: "443/udp", port_desc: "QUIC (HTTP/3) port. Must be enabled in the default and proxy confs."}
readonly_supported: true
readonly_message: |
* `/tmp` must be mounted to tmpfs
* fail2ban will not be available
# application setup block # application setup block
app_setup_block_enabled: true app_setup_block_enabled: true
app_setup_block: | app_setup_block: |
@@ -64,7 +59,7 @@ app_setup_block: |
1. Certs that only cover your main subdomain (ie. `yoursubdomain.duckdns.org`, leave the `SUBDOMAINS` variable empty) 1. Certs that only cover your main subdomain (ie. `yoursubdomain.duckdns.org`, leave the `SUBDOMAINS` variable empty)
2. Certs that cover sub-subdomains of your main subdomain (ie. `*.yoursubdomain.duckdns.org`, set the `SUBDOMAINS` variable to `wildcard`) 2. Certs that cover sub-subdomains of your main subdomain (ie. `*.yoursubdomain.duckdns.org`, set the `SUBDOMAINS` variable to `wildcard`)
* `--cap-add=NET_ADMIN` is required for fail2ban to modify iptables * `--cap-add=NET_ADMIN` is required for fail2ban to modify iptables
* After setup, navigate to `https://example.com` to access the default homepage (http access through port 80 is disabled by default, you can enable it by editing the default site config at `/config/nginx/site-confs/default.conf`). * After setup, navigate to `https://yourdomain.url` to access the default homepage (http access through port 80 is disabled by default, you can enable it by editing the default site config at `/config/nginx/site-confs/default.conf`).
* Certs are checked nightly and if expiration is within 30 days, renewal is attempted. If your cert is about to expire in less than 30 days, check the logs under `/config/log/letsencrypt` to see why the renewals have been failing. It is recommended to input your e-mail in docker parameters so you receive expiration notices from Let's Encrypt in those circumstances. * Certs are checked nightly and if expiration is within 30 days, renewal is attempted. If your cert is about to expire in less than 30 days, check the logs under `/config/log/letsencrypt` to see why the renewals have been failing. It is recommended to input your e-mail in docker parameters so you receive expiration notices from Let's Encrypt in those circumstances.
### Certbot Plugins ### Certbot Plugins
@@ -123,7 +118,7 @@ app_setup_block: |
* You can check which jails are active via `docker exec -it swag fail2ban-client status` * You can check which jails are active via `docker exec -it swag fail2ban-client status`
* You can check the status of a specific jail via `docker exec -it swag fail2ban-client status <jail name>` * You can check the status of a specific jail via `docker exec -it swag fail2ban-client status <jail name>`
* You can unban an IP via `docker exec -it swag fail2ban-client set <jail name> unbanip <IP>` * You can unban an IP via `docker exec -it swag fail2ban-client set <jail name> unbanip <IP>`
* A list of commands for fail2ban-client can be found [here](https://manpages.ubuntu.com/manpages/noble/man1/fail2ban-client.1.html) * A list of commands can be found here: <https://www.fail2ban.org/wiki/index.php/Commands>
### Updating configs ### Updating configs
@@ -139,94 +134,12 @@ app_setup_block: |
* Proxy sample files WILL be updated, however your renamed (enabled) proxy files will not. * Proxy sample files WILL be updated, however your renamed (enabled) proxy files will not.
* You can check the new sample and adjust your active config as needed. * You can check the new sample and adjust your active config as needed.
### QUIC support
This image supports QUIC (also known as HTTP/3) but it must be explicitly enabled in each proxy conf, and the default conf, because if the listener is enabled and you don't expose 443/UDP, it can break connections with some browsers.
To enable QUIC, expose 443/UDP to your clients, then uncomment both QUIC listeners in all of your active proxy confs, as well as the default conf, and restart the container.
You should also uncomment the `Alt-Svc` header in your `ssl.conf` so that browsers are aware that you offer QUIC connectivity.
It is [recommended](https://quic-go.net/docs/quic/optimizations/#udp-buffer-sizes) to increase the UDP send/recieve buffer **on the host** by setting the `net.core.rmem_max` and `net.core.wmem_max` sysctls. Suggested values are 4-16Mb (4194304-16777216 bytes). For persistence between reboots use `/etc/sysctl.d/`.
### Migration from the old `linuxserver/letsencrypt` image ### Migration from the old `linuxserver/letsencrypt` image
Please follow the instructions [on this blog post](https://www.linuxserver.io/blog/2020-08-21-introducing-swag#migrate). Please follow the instructions [on this blog post](https://www.linuxserver.io/blog/2020-08-21-introducing-swag#migrate).
# init diagram
init_diagram: |
"swag:latest": {
docker-mods
base {
fix-attr +\nlegacy cont-init
}
docker-mods -> base
legacy-services
custom services
init-services -> legacy-services
init-services -> custom services
custom services -> legacy-services
legacy-services -> ci-service-check
init-migrations -> init-adduser
init-swag-config -> init-certbot-config
init-nginx-end -> init-config
init-os-end -> init-config
init-config -> init-config-end
init-crontab-config -> init-config-end
init-outdated-config -> init-config-end
init-config -> init-crontab-config
init-mods-end -> init-custom-files
init-adduser -> init-device-perms
base -> init-envfile
init-require-url -> init-fail2ban-config
init-os-end -> init-folders
init-php -> init-keygen
base -> init-migrations
init-config-end -> init-mods
init-mods-package-install -> init-mods-end
init-mods -> init-mods-package-install
init-samples -> init-nginx
init-version-checks -> init-nginx-end
init-adduser -> init-os-end
init-device-perms -> init-os-end
init-envfile -> init-os-end
init-renew -> init-outdated-config
init-keygen -> init-permissions
init-certbot-config -> init-permissions-config
init-nginx -> init-php
init-permissions-config -> init-renew
init-config -> init-require-url
init-folders -> init-samples
init-custom-files -> init-services
init-fail2ban-config -> init-swag-config
init-permissions -> init-swag-folders
init-swag-folders -> init-swag-samples
init-permissions -> init-version-checks
init-swag-samples -> init-version-checks
init-services -> svc-cron
svc-cron -> legacy-services
init-services -> svc-fail2ban
svc-fail2ban -> legacy-services
init-services -> svc-nginx
svc-nginx -> legacy-services
init-services -> svc-php-fpm
svc-php-fpm -> legacy-services
init-services -> svc-swag-auto-reload
svc-swag-auto-reload -> legacy-services
}
Base Images: {
"baseimage-alpine-nginx:3.22" <- "baseimage-alpine:3.22"
}
"swag:latest" <- Base Images
# changelog # changelog
changelogs: changelogs:
- {date: "23.01.26:", desc: "Reorder init to fix proxy conf version checks."}
- {date: "21.12.25:", desc: "Add support for hetzner-cloud dns validation."}
- {date: "04.11.25:", desc: "Switch default Gandi credentials from API Key to Token, allow DNS propagation time for Azure DNS plugin."}
- {date: "18.07.25:", desc: "Rebase to Alpine 3.22 with PHP 8.4. Add QUIC support. Drop PHP bindings for mcrypt as it is no longer maintained."}
- {date: "05.05.25:", desc: "Disable Certbot's built in log rotation."}
- {date: "19.01.25:", desc: "Add [Auto Reload](https://github.com/linuxserver/docker-mods/tree/swag-auto-reload) functionality to SWAG."}
- {date: "17.12.24:", desc: "Rebase to Alpine 3.21."}
- {date: "21.10.24:", desc: "Fix naming issue with Dynu plugin. If you are using Dynu, please make sure your credentials are set in /config/dns-conf/dynu.ini and your DNSPLUGIN variable is set to dynu (not dynudns)."}
- { date: "30.08.24:", desc: "Fix zerossl cert revocation." } - { date: "30.08.24:", desc: "Fix zerossl cert revocation." }
- { date: "24.07.14:", desc: "Rebase to Alpine 3.20. Remove deprecated Google Domains certbot plugin. Existing users should update their nginx confs to avoid http2 deprecation warnings."} - { date: "24.07.14:", desc: "Rebase to Alpine 3.20. Remove deprecated Google Domains certbot plugin. Existing users should update their nginx confs to avoid http2 deprecation warnings."}
- { date: "01.07.24:", desc: "Fall back to iptables-legacy if iptables doesn't work." } - { date: "01.07.24:", desc: "Fall back to iptables-legacy if iptables doesn't work." }

View File

@@ -6,4 +6,4 @@ echo
echo "<------------------------------------------------->" echo "<------------------------------------------------->"
echo "cronjob running on $(date)" echo "cronjob running on $(date)"
echo "Running certbot renew" echo "Running certbot renew"
certbot renew --non-interactive --config-dir /config/etc/letsencrypt --logs-dir /config/log/letsencrypt --work-dir /tmp/letsencrypt --config /config/etc/letsencrypt/cli.ini certbot renew --non-interactive

View File

@@ -1,6 +1,7 @@
# Instructions: https://github.com/obynio/certbot-plugin-gandi#usage # Instructions: https://github.com/obynio/certbot-plugin-gandi#usage
# Replace with your Gandi Live DNS v5 Personal Access Token # Replace with your value
dns_gandi_token=TOKEN # live dns v5 api key
dns_gandi_api_key=APIKEY
# optional organization id, remove it if not used # optional organization id, remove it if not used
#dns_gandi_sharing_id=SHARINGID #dns_gandi_sharing_id=SHARINGID

View File

@@ -1,2 +0,0 @@
# Hetzner Cloud API Token
dns_hetzner_cloud_api_token = your_api_token_here

View File

@@ -1,7 +1,9 @@
#!/usr/bin/with-contenv bash #!/usr/bin/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
# Notice: This file will be overwritten when updated by lsio. Add your custom scripts into a new file in this folder.
cd /config/keys/letsencrypt || exit 1 cd /config/keys/letsencrypt || exit 1
echo "**** Generating pfx and fullchain bundle certs ****"
openssl pkcs12 -export -out privkey.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem -passout pass: openssl pkcs12 -export -out privkey.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem -passout pass:
sleep 1 sleep 1
cat {privkey,fullchain}.pem >priv-fullchain-bundle.pem cat {privkey,fullchain}.pem >priv-fullchain-bundle.pem

View File

@@ -1,15 +1,18 @@
#!/usr/bin/with-contenv bash #!/usr/bin/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
# Notice: This file will be overwritten when updated by lsio. Add your custom scripts into a new file in this folder.
# shellcheck source=/dev/null # shellcheck source=/dev/null
. /config/.donoteditthisfile.conf . /config/.donoteditthisfile.conf
if [[ ! "${ORIGVALIDATION}" = "dns" ]] && [[ ! "${ORIGVALIDATION}" = "duckdns" ]]; then if [[ ! "${ORIGVALIDATION}" = "dns" ]] && [[ ! "${ORIGVALIDATION}" = "duckdns" ]]; then
if pgrep -f "s6-supervise svc-nginx" >/dev/null; then if pgrep -f "s6-supervise svc-nginx" >/dev/null; then
echo "**** Starting Nginx ****"
s6-svc -u /run/service/svc-nginx s6-svc -u /run/service/svc-nginx
fi fi
else else
if pgrep -f "nginx:" >/dev/null; then if pgrep -f "nginx:" >/dev/null; then
echo "**** Reloading Nginx to load the new cert ****"
s6-svc -h /run/service/svc-nginx s6-svc -h /run/service/svc-nginx
fi fi
fi fi

View File

@@ -1,11 +1,13 @@
#!/usr/bin/with-contenv bash #!/usr/bin/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
# Notice: This file will be overwritten when updated by lsio. Add your custom scripts into a new file in this folder.
# shellcheck source=/dev/null # shellcheck source=/dev/null
. /config/.donoteditthisfile.conf . /config/.donoteditthisfile.conf
if [[ ! "${ORIGVALIDATION}" = "dns" ]] && [[ ! "${ORIGVALIDATION}" = "duckdns" ]]; then if [[ ! "${ORIGVALIDATION}" = "dns" ]] && [[ ! "${ORIGVALIDATION}" = "duckdns" ]]; then
if pgrep -f "nginx:" >/dev/null; then if pgrep -f "nginx:" >/dev/null; then
echo "**** Stopping Nginx in preparation of cert generation/renewal ****"
s6-svc -d /run/service/svc-nginx s6-svc -d /run/service/svc-nginx
fi fi
fi fi

View File

@@ -1,8 +1,13 @@
## Version 2025/03/25 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/authelia-location.conf.sample ## Version 2024/03/14 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/authelia-location.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
# For authelia 4.37 and below, make sure that the authelia configuration.yml has 'path: "authelia"' defined
# For authelia 4.38 and above, make sure that the authelia configuration.yml has 'address: "tcp://:9091/authelia"' defined
## Send a subrequest to Authelia to verify if the user is authenticated and has permission to access the resource ## Send a subrequest to Authelia to verify if the user is authenticated and has permission to access the resource
## For authelia 4.37 and below, use the following line
# auth_request /authelia/api/verify;
## For authelia 4.38 and above, use the following line
auth_request /authelia/api/authz/auth-request; auth_request /authelia/api/authz/auth-request;
## If the subreqest returns 200 pass to the backend, if the subrequest returns 401 redirect to the portal ## If the subreqest returns 200 pass to the backend, if the subrequest returns 401 redirect to the portal

View File

@@ -1,15 +1,44 @@
## Version 2025/03/25 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/authelia-server.conf.sample ## Version 2024/03/16 - 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
# For authelia 4.37 and below, make sure that the authelia configuration.yml has 'path: "authelia"' defined
# For authelia 4.38 and above, make sure that the authelia configuration.yml has 'address: "tcp://:9091/authelia"' defined
# location for authelia auth requests # location for authelia subfolder requests
location ^~ /authelia {
auth_request off; # requests to this subfolder must be accessible without authentication
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_authelia authelia;
proxy_pass http://$upstream_authelia:9091;
}
# location for authelia 4.37 and below auth requests
location = /authelia/api/verify {
internal;
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_authelia authelia;
proxy_pass http://$upstream_authelia:9091;
## Include the Set-Cookie header if present
auth_request_set $set_cookie $upstream_http_set_cookie;
add_header Set-Cookie $set_cookie;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
# location for authelia 4.38 and above auth requests
location = /authelia/api/authz/auth-request { location = /authelia/api/authz/auth-request {
internal; internal;
include /config/nginx/proxy.conf; include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf; include /config/nginx/resolver.conf;
set $upstream_authelia authelia; set $upstream_authelia authelia;
proxy_pass http://$upstream_authelia:9091/api/authz/auth-request; proxy_pass http://$upstream_authelia:9091;
## Include the Set-Cookie header if present ## Include the Set-Cookie header if present
auth_request_set $set_cookie $upstream_http_set_cookie; auth_request_set $set_cookie $upstream_http_set_cookie;
@@ -33,6 +62,11 @@ location @authelia_proxy_signin {
## 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;
if ($signin_url = '') {
## Set the $signin_url variable
set $signin_url https://$http_host/authelia/?rd=$target_url;
}
## Redirect to login ## Redirect to login
return 302 $signin_url; return 302 $signin_url;
} }

View File

@@ -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 2023/04/27 - 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
@@ -19,7 +19,7 @@ location = /outpost.goauthentik.io/auth/nginx {
include /config/nginx/proxy.conf; include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf; include /config/nginx/resolver.conf;
set $upstream_authentik authentik-server; set $upstream_authentik authentik-server;
proxy_pass http://$upstream_authentik:9000/outpost.goauthentik.io/auth/nginx; proxy_pass http://$upstream_authentik:9000;
## Include the Set-Cookie header if present ## Include the Set-Cookie header if present
auth_request_set $set_cookie $upstream_http_set_cookie; auth_request_set $set_cookie $upstream_http_set_cookie;

View File

@@ -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 2024/07/16 - 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 {
@@ -13,9 +13,7 @@ server {
# main server block # main server block
server { server {
listen 443 ssl default_server; listen 443 ssl default_server;
# listen 443 quic reuseport default_server;
listen [::]:443 ssl default_server; listen [::]:443 ssl default_server;
# listen [::]:443 quic reuseport default_server;
server_name _; server_name _;
@@ -36,9 +34,6 @@ server {
# enable for Authentik (requires authentik-location.conf in the location block) # enable for Authentik (requires authentik-location.conf in the location block)
#include /config/nginx/authentik-server.conf; #include /config/nginx/authentik-server.conf;
# enable for Tinyauth (requires tinyauth-location.conf in the location block)
#include /config/nginx/tinyauth-server.conf;
location / { location / {
# enable for basic auth # enable for basic auth
#auth_basic "Restricted"; #auth_basic "Restricted";
@@ -53,9 +48,6 @@ server {
# enable for Authentik (requires authentik-server.conf in the server block) # enable for Authentik (requires authentik-server.conf in the server block)
#include /config/nginx/authentik-location.conf; #include /config/nginx/authentik-location.conf;
# enable for Tinyauth (requires tinyauth-server.conf in the server block)
#include /config/nginx/tinyauth-location.conf;
try_files $uri $uri/ /index.html /index.htm /index.php$is_args$args; try_files $uri $uri/ /index.html /index.htm /index.php$is_args$args;
} }
@@ -88,3 +80,5 @@ server {
# enable subdomain method reverse proxy confs # enable subdomain method reverse proxy confs
include /config/nginx/proxy-confs/*.subdomain.conf; include /config/nginx/proxy-confs/*.subdomain.conf;
# enable proxy cache for auth
proxy_cache_path cache/ keys_zone=auth_cache:10m;

View File

@@ -1,9 +0,0 @@
## Version 2025/06/08 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/tinyauth-location.conf.sample
# 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
## Send a subrequest to tinyauth to verify if the user is authenticated and has permission to access the resource
auth_request /tinyauth;
## If the subreqest returns 200 pass to the backend, if the subrequest returns 401 redirect to the portal
error_page 401 = @tinyauth_login;

View File

@@ -1,35 +0,0 @@
## Version 2025/06/08 - 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
# Rename /config/nginx/proxy-confs/tinyauth.subdomain.conf.sample to /config/nginx/proxy-confs/tinyauth.subdomain.conf
# location for tinyauth auth requests
location /tinyauth {
internal;
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_tinyauth tinyauth;
proxy_pass http://$upstream_tinyauth:3000/api/auth/nginx;
proxy_set_header x-forwarded-proto $scheme;
proxy_set_header x-forwarded-host $http_host;
proxy_set_header x-forwarded-uri $request_uri;
}
# virtual location for tinyauth 401 redirects
location @tinyauth_login {
internal;
## Set the $target_url variable based on the original request
set_escape_uri $target_url $scheme://$http_host$request_uri;
## Set the $signin_url variable
set $domain $host;
if ($host ~* "^[^.]+\.([^.]+\..+)$") {
set $domain $1;
}
set $signin_url https://tinyauth.$domain/login?redirect_uri=$target_url;
## Redirect to login
return 302 $signin_url;
}

View File

@@ -5,4 +5,4 @@
0 3 * * 6 run-parts /etc/periodic/weekly 0 3 * * 6 run-parts /etc/periodic/weekly
0 5 1 * * run-parts /etc/periodic/monthly 0 5 1 * * run-parts /etc/periodic/monthly
8 2 * * * /app/le-renew.sh >> /config/log/letsencrypt/renewal.log 2>&1 8 2 * * * /app/le-renew.sh >> /config/log/letsencrypt/letsencrypt.log 2>&1

View File

@@ -38,6 +38,12 @@ if [[ "${VALIDATION}" = "dns" ]] && ! echo "${CERTBOT_DNS_AUTHENTICATORS}" | gre
sleep infinity sleep infinity
fi fi
# set owner of certbot's CONFIG_DIR, WORK_DIR, and LOGS_DIR to abc
lsiown -R abc:abc \
/etc/letsencrypt \
/var/lib/letsencrypt \
/var/log/letsencrypt
# set_ini_value logic: # set_ini_value logic:
# - if the name is not found in the file, append the name=value to the end of the file # - if the name is not found in the file, append the name=value to the end of the file
# - if the name is found in the file, replace the value # - if the name is found in the file, replace the value
@@ -56,25 +62,15 @@ touch /config/etc/letsencrypt/cli.ini
lsiown abc:abc /config/etc/letsencrypt/cli.ini lsiown abc:abc /config/etc/letsencrypt/cli.ini
grep -qF 'agree-tos' /config/etc/letsencrypt/cli.ini || echo 'agree-tos=true' >>/config/etc/letsencrypt/cli.ini grep -qF 'agree-tos' /config/etc/letsencrypt/cli.ini || echo 'agree-tos=true' >>/config/etc/letsencrypt/cli.ini
# Check for broken dns credentials value in cli.ini and remove
sed -i '/dns--credentials/d' /config/etc/letsencrypt/cli.ini
# Disable Certbot's built in log rotation
set_ini_value "max-log-backups" "0" /config/etc/letsencrypt/cli.ini
# copy dns default configs # copy dns default configs
cp -n /defaults/dns-conf/* /config/dns-conf/ 2> >(grep -v 'cp: not replacing') cp -n /defaults/dns-conf/* /config/dns-conf/ 2> >(grep -v 'cp: not replacing')
lsiown -R abc:abc /config/dns-conf lsiown -R abc:abc /config/dns-conf
# copy default renewal hooks # copy default renewal hooks
cp -nR /defaults/etc/letsencrypt/renewal-hooks/* /config/etc/letsencrypt/renewal-hooks/ 2> >(grep -v 'cp: not replacing') chmod -R +x /defaults/etc/letsencrypt/renewal-hooks
cp -Rf /defaults/etc/letsencrypt/renewal-hooks/* /config/etc/letsencrypt/renewal-hooks/ 2> >(grep -v 'cp: not replacing')
lsiown -R abc:abc /config/etc/letsencrypt/renewal-hooks lsiown -R abc:abc /config/etc/letsencrypt/renewal-hooks
# replace nginx service location in renewal hooks
find /config/etc/letsencrypt/renewal-hooks/ -type f -exec sed -i 's|/run/service/nginx|/run/service/svc-nginx|g' {} \;
find /config/etc/letsencrypt/renewal-hooks/ -type f -exec sed -i 's|/var/run/s6/services/nginx|/run/service/svc-nginx|g' {} \;
find /config/etc/letsencrypt/renewal-hooks/ -type f -exec sed -i 's|s6-supervise nginx|s6-supervise svc-nginx|g' {} \;
# create original config file if it doesn't exist, move non-hidden legacy file to hidden # create original config file if it doesn't exist, move non-hidden legacy file to hidden
if [[ -f "/config/donoteditthisfile.conf" ]]; then if [[ -f "/config/donoteditthisfile.conf" ]]; then
mv /config/donoteditthisfile.conf /config/.donoteditthisfile.conf mv /config/donoteditthisfile.conf /config/.donoteditthisfile.conf
@@ -174,8 +170,8 @@ else
fi fi
# cleanup unused csr and keys folders # cleanup unused csr and keys folders
rm -rf /config/etc/letsencrypt/csr rm -rf /etc/letsencrypt/csr
rm -rf /config/etc/letsencrypt/keys rm -rf /etc/letsencrypt/keys
# checking for changes in cert variables, revoking certs if necessary # checking for changes in cert variables, revoking certs if necessary
if [[ ! "${URL}" = "${ORIGURL}" ]] || if [[ ! "${URL}" = "${ORIGURL}" ]] ||
@@ -196,9 +192,9 @@ if [[ ! "${URL}" = "${ORIGURL}" ]] ||
REV_ACMESERVER=("https://acme-v02.api.letsencrypt.org/directory") REV_ACMESERVER=("https://acme-v02.api.letsencrypt.org/directory")
fi fi
if [[ -f /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/fullchain.pem ]]; then if [[ -f /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/fullchain.pem ]]; then
certbot revoke --config-dir /config/etc/letsencrypt --logs-dir /config/log/letsencrypt --work-dir /tmp/letsencrypt --config /config/etc/letsencrypt/cli.ini --non-interactive --cert-path /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/fullchain.pem --key-path /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/privkey.pem --server "${REV_ACMESERVER[@]}" || true certbot revoke --non-interactive --cert-path /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/fullchain.pem --key-path /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/privkey.pem --server "${REV_ACMESERVER[@]}" || true
else else
certbot revoke --config-dir /config/etc/letsencrypt --logs-dir /config/log/letsencrypt --work-dir /tmp/letsencrypt --config /config/etc/letsencrypt/cli.ini --non-interactive --cert-name "${ORIGDOMAIN}" --server "${REV_ACMESERVER[@]}" || true certbot revoke --non-interactive --cert-name "${ORIGDOMAIN}" --server "${REV_ACMESERVER[@]}" || true
fi fi
rm -rf /config/etc/letsencrypt/{accounts,archive,live,renewal} rm -rf /config/etc/letsencrypt/{accounts,archive,live,renewal}
fi fi
@@ -211,9 +207,9 @@ if [[ -f "/config/keys/letsencrypt/chain.pem" ]] && { [[ "${CERTPROVIDER}" == "l
echo "The cert seems to be using the old LE root cert, which is no longer valid. Deleting and revoking." echo "The cert seems to be using the old LE root cert, which is no longer valid. Deleting and revoking."
REV_ACMESERVER=("https://acme-v02.api.letsencrypt.org/directory") REV_ACMESERVER=("https://acme-v02.api.letsencrypt.org/directory")
if [[ -f /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/fullchain.pem ]]; then if [[ -f /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/fullchain.pem ]]; then
certbot revoke --config-dir /config/etc/letsencrypt --logs-dir /config/log/letsencrypt --work-dir /tmp/letsencrypt --config /config/etc/letsencrypt/cli.ini --non-interactive --cert-path /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/fullchain.pem --server "${REV_ACMESERVER[@]}" || true certbot revoke --non-interactive --cert-path /config/etc/letsencrypt/live/"${ORIGDOMAIN}"/fullchain.pem --server "${REV_ACMESERVER[@]}" || true
else else
certbot revoke --config-dir /config/etc/letsencrypt --logs-dir /config/log/letsencrypt --work-dir /tmp/letsencrypt --config /config/etc/letsencrypt/cli.ini --non-interactive --cert-name "${ORIGDOMAIN}" --server "${REV_ACMESERVER[@]}" || true certbot revoke --non-interactive --cert-name "${ORIGDOMAIN}" --server "${REV_ACMESERVER[@]}" || true
fi fi
rm -rf /config/etc/letsencrypt/{accounts,archive,live,renewal} rm -rf /config/etc/letsencrypt/{accounts,archive,live,renewal}
fi fi
@@ -303,7 +299,7 @@ if [[ "${VALIDATION}" = "dns" ]]; then
sed -i "/^dns-${DNSPLUGIN}-credentials\b/d" /config/etc/letsencrypt/cli.ini sed -i "/^dns-${DNSPLUGIN}-credentials\b/d" /config/etc/letsencrypt/cli.ini
fi fi
# plugins that don't support setting propagation # plugins that don't support setting propagation
if [[ "${DNSPLUGIN}" =~ ^(gandi|route53|standalone)$ ]]; then if [[ "${DNSPLUGIN}" =~ ^(azure|gandi|route53|standalone)$ ]]; then
if [[ -n "${PROPAGATION}" ]]; then echo "${DNSPLUGIN} dns plugin does not support setting propagation time"; fi if [[ -n "${PROPAGATION}" ]]; then echo "${DNSPLUGIN} dns plugin does not support setting propagation time"; fi
sed -i "/^dns-${DNSPLUGIN}-propagation-seconds\b/d" /config/etc/letsencrypt/cli.ini sed -i "/^dns-${DNSPLUGIN}-propagation-seconds\b/d" /config/etc/letsencrypt/cli.ini
fi fi
@@ -346,7 +342,7 @@ if [[ ! -f "/config/keys/letsencrypt/fullchain.pem" ]]; then
set_ini_value "eab-hmac-key" "${ZEROSSL_EAB_HMAC_KEY}" /config/etc/letsencrypt/cli.ini set_ini_value "eab-hmac-key" "${ZEROSSL_EAB_HMAC_KEY}" /config/etc/letsencrypt/cli.ini
fi fi
echo "Generating new certificate" echo "Generating new certificate"
certbot certonly --config-dir /config/etc/letsencrypt --logs-dir /config/log/letsencrypt --work-dir /tmp/letsencrypt --config /config/etc/letsencrypt/cli.ini --non-interactive --renew-by-default certbot certonly --non-interactive --renew-by-default
if [[ ! -d /config/keys/letsencrypt ]]; then if [[ ! -d /config/keys/letsencrypt ]]; then
if [[ "${VALIDATION}" = "dns" ]]; then if [[ "${VALIDATION}" = "dns" ]]; then
echo "ERROR: Cert does not exist! Please see the validation error above. Make sure you entered correct credentials into the ${DNSCREDENTIALFILE} file." echo "ERROR: Cert does not exist! Please see the validation error above. Make sure you entered correct credentials into the ${DNSCREDENTIALFILE} file."

View File

@@ -1,14 +1,13 @@
#!/usr/bin/with-contenv bash #!/usr/bin/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
if [[ -z ${LSIO_READ_ONLY_FS} ]] && [[ -z ${LSIO_NON_ROOT_USER} ]] && [[ "${DISABLE_F2B,,}" != "true" ]]; then
if ! iptables -L &> /dev/null; then if ! iptables -L &> /dev/null; then
ln -sf /usr/sbin/xtables-legacy-multi /usr/sbin/iptables ln -sf /sbin/xtables-legacy-multi /sbin/iptables
ln -sf /usr/sbin/xtables-legacy-multi /usr/sbin/iptables-save ln -sf /sbin/xtables-legacy-multi /sbin/iptables-save
ln -sf /usr/sbin/xtables-legacy-multi /usr/sbin/iptables-restore ln -sf /sbin/xtables-legacy-multi /sbin/iptables-restore
ln -sf /usr/sbin/xtables-legacy-multi /usr/sbin/ip6tables ln -sf /sbin/xtables-legacy-multi /sbin/ip6tables
ln -sf /usr/sbin/xtables-legacy-multi /usr/sbin/ip6tables-save ln -sf /sbin/xtables-legacy-multi /sbin/ip6tables-save
ln -sf /usr/sbin/xtables-legacy-multi /usr/sbin/ip6tables-restore ln -sf /sbin/xtables-legacy-multi /sbin/ip6tables-restore
fi fi
# copy/update the fail2ban config defaults to/in /config # copy/update the fail2ban config defaults to/in /config
@@ -37,4 +36,3 @@ if [[ -z ${LSIO_READ_ONLY_FS} ]] && [[ -z ${LSIO_NON_ROOT_USER} ]] && [[ "${DISA
if [[ ! -f /config/log/nginx/access.log ]]; then if [[ ! -f /config/log/nginx/access.log ]]; then
touch /config/log/nginx/access.log touch /config/log/nginx/access.log
fi fi
fi

View File

@@ -7,6 +7,6 @@ mkdir -p \
/config/etc/letsencrypt/renewal-hooks \ /config/etc/letsencrypt/renewal-hooks \
/config/log/{fail2ban,letsencrypt,nginx} \ /config/log/{fail2ban,letsencrypt,nginx} \
/config/nginx/proxy-confs \ /config/nginx/proxy-confs \
/run/fail2ban \ /run/fail2ban
/tmp/letsencrypt rm -rf /etc/letsencrypt
ln -s /config/etc/letsencrypt /etc/letsencrypt

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-folders-config/run

View File

@@ -22,14 +22,6 @@ if [[ ! -f /config/nginx/authentik-server.conf ]]; then
cp /defaults/nginx/authentik-server.conf.sample /config/nginx/authentik-server.conf cp /defaults/nginx/authentik-server.conf.sample /config/nginx/authentik-server.conf
fi fi
# copy tinyauth config files if they don't exist
if [[ ! -f /config/nginx/tinyauth-location.conf ]]; then
cp /defaults/nginx/tinyauth-location.conf.sample /config/nginx/tinyauth-location.conf
fi
if [[ ! -f /config/nginx/tinyauth-server.conf ]]; then
cp /defaults/nginx/tinyauth-server.conf.sample /config/nginx/tinyauth-server.conf
fi
# copy old ldap config file to new location # copy old ldap config file to new location
if [[ -f /config/nginx/ldap.conf ]] && [[ ! -f /config/nginx/ldap-server.conf ]]; then if [[ -f /config/nginx/ldap.conf ]] && [[ ! -f /config/nginx/ldap-server.conf ]]; then
cp /config/nginx/ldap.conf /config/nginx/ldap-server.conf cp /config/nginx/ldap.conf /config/nginx/ldap-server.conf

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-nginx-config/run

View File

@@ -11,9 +11,3 @@ if [[ -f /config/nginx/ldap.conf ]]; then
Ensure your configs are updated and remove /config/nginx/ldap.conf Ensure your configs are updated and remove /config/nginx/ldap.conf
If you do not use this config, simply remove it." If you do not use this config, simply remove it."
fi fi
if grep -qrle ' /etc/letsencrypt' /config/nginx; then
echo " The following nginx confs are using certificates from the obsolete location
/etc/letsencrypt and should be updated to point to /config/etc/letsencrypt
"
echo -n " " && grep -rle ' /etc/letsencrypt' /config/nginx
fi

View File

@@ -2,7 +2,8 @@
# shellcheck shell=bash # shellcheck shell=bash
# permissions # permissions
find /config/log ! -path '/config/log/logrotate.status' -exec chmod +r {} \+
lsiown -R abc:abc \ lsiown -R abc:abc \
/config /config
chmod -R 0644 /etc/logrotate.d
chmod -R +r /config/log
chmod +x /app/le-renew.sh

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-samples-config/run

View File

@@ -1 +0,0 @@
/etc/s6-overlay/s6-rc.d/init-swag-config/run

View File

@@ -1 +0,0 @@
/etc/s6-overlay/s6-rc.d/init-swag-folders/run

View File

@@ -1 +0,0 @@
/etc/s6-overlay/s6-rc.d/init-swag-samples/run

View File

@@ -0,0 +1,7 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# Echo init finish for test runs
if [[ -n "${TEST_RUN}" ]]; then
echo '[services.d] done.'
fi

View File

@@ -0,0 +1 @@
oneshot

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-test-run/run

View File

@@ -1,9 +1,5 @@
#!/usr/bin/with-contenv bash #!/usr/bin/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
if [[ -z ${LSIO_READ_ONLY_FS} ]] && [[ -z ${LSIO_NON_ROOT_USER} ]] && [[ "${DISABLE_F2B,,}" != "true" ]]; then
exec \ exec \
fail2ban-client -x -f start fail2ban-client -x -f start
else
sleep infinity
fi

View File

@@ -1,41 +0,0 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
if [[ ${SWAG_AUTORELOAD,,} == "true" ]]; then
if [[ -f "/etc/s6-overlay/s6-rc.d/svc-mod-swag-auto-reload/run" ]]; then
echo "ERROR: Legacy SWAG Auto Reload Mod detected, to use the built-in Auto Reload functionality please remove it from your container config."
sleep infinity
else
echo "Auto-reload: Watching the following folders for changes to .conf files:"
echo "/config/nginx"
ACTIVE_WATCH=("/config/nginx")
for i in $(echo "${SWAG_AUTORELOAD_WATCHLIST}" | tr "|" " "); do
if [ -f "${i}" ] || [ -d "${i}" ]; then
echo "${i}"
ACTIVE_WATCH+=("${i}")
fi
done
function wait_for_changes {
inotifywait -rq \
--event modify,move,create,delete \
--includei '\.conf$' \
"${ACTIVE_WATCH[@]}"
}
while wait_for_changes; do
NGINX_CONF=()
if ! grep -q "/config/nginx/nginx.conf" /etc/nginx/nginx.conf; then
NGINX_CONF=("-c" "/config/nginx/nginx.conf")
fi
if /usr/sbin/nginx "${NGINX_CONF[@]}" -t; then
echo "Changes to nginx config detected and the changes are valid, reloading nginx"
/usr/sbin/nginx "${NGINX_CONF[@]}" -s reload
else
echo "Changes to nginx config detected but the changes are not valid, skipping nginx reload. Please fix your config."
fi
done
fi
else
sleep infinity
fi

View File

@@ -1 +0,0 @@
longrun

View File

@@ -1,7 +0,0 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# Migrate existing renewal confs with old paths from /etc/letsencrypt to /config/etc/letsencrypt
if ls /config/etc/letsencrypt/renewal/*.conf >/dev/null 2>&1; then
sed -i 's| /etc/letsencrypt| /config/etc/letsencrypt|' /config/etc/letsencrypt/renewal/*.conf
fi