Compare commits

..

18 Commits

Author SHA1 Message Date
Michel Roegl-Brunner
8c5cd94914 Remove json files 2026-03-12 15:37:17 +01:00
community-scripts-pr-app[bot]
56dca9e163 Update CHANGELOG.md (#12826)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 14:24:52 +00:00
Michel Roegl-Brunner
281ebe0e1e Delete Test (#12825)
* Delete ct/test.sh

* Delete install/test-install.sh
2026-03-12 15:24:16 +01:00
community-scripts-pr-app[bot]
36bedd85cc Update CHANGELOG.md (#12824)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 14:22:04 +00:00
push-app-to-main[bot]
ef7badb776 Add test (ct) (#12823)
Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
2026-03-12 15:21:38 +01:00
community-scripts-pr-app[bot]
2ca6278caf Update CHANGELOG.md (#12820)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 13:30:43 +00:00
community-scripts-pr-app[bot]
0257dafe22 Update CHANGELOG.md (#12819)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 13:30:14 +00:00
Michel Roegl-Brunner
ef942a61c0 Cleanup workflows (#12818)
* Cleanup Workflows

* Cleanup unneded workflows
2026-03-12 14:29:48 +01:00
community-scripts-pr-app[bot]
57b59e8fbd Update CHANGELOG.md (#12817)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 13:20:22 +00:00
ANLO.PO
ee4111f2b0 Fix incorrect port in upstream requests by forwarding original host and port (#12812)
Replace `Host $host` with `Host $http_host` so the upstream application receives the original host including the port (e.g. `manyfold:8081`).
Add `X-Forwarded-Host` and `X-Forwarded-Port` headers to ensure the Rails app generates correct absolute URLs instead of defaulting to port 80 when running behind nginx on a non-standard port.
2026-03-12 14:19:54 +01:00
community-scripts-pr-app[bot]
106f9c5adf Update CHANGELOG.md (#12816)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 13:00:00 +00:00
community-scripts-pr-app[bot]
96920367f8 Update CHANGELOG.md (#12815)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 12:59:43 +00:00
community-scripts-pr-app[bot]
21af1cb143 Update CHANGELOG.md (#12814)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 12:59:33 +00:00
CanbiZ (MickLesk)
bfedeb0277 Cleanup: remove frontend, move JSONs to json/ top-level (#12813) 2026-03-12 13:59:18 +01:00
Chris
abccdef6cb Pin Patchmon to 1.4.2 (#12789) 2026-03-12 13:59:04 +01:00
community-scripts-pr-app[bot]
12bdbcce5c chore: update github-versions.json (#12811)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 12:11:11 +00:00
community-scripts-pr-app[bot]
51418f0d99 Update CHANGELOG.md (#12809)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 11:21:56 +00:00
CanbiZ (MickLesk)
3601388abe core: add mode=generated for unattended frontend installs (#12807) 2026-03-12 12:21:28 +01:00
625 changed files with 30 additions and 35489 deletions

View File

@@ -1,68 +0,0 @@
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy as build
ARG TARGETOS
ARG TARGETARCH
ARG DOCKER_VERSION=27.5.1
ARG BUILDX_VERSION=0.20.1
ARG RUNNER_ARCH="x64"
RUN apt update -y && apt install sudo curl unzip -y
WORKDIR /actions-runner
RUN RUNNER_VERSION=$(curl -s https://api.github.com/repos/actions/runner/releases/latest | grep "tag_name" | head -n 1 | awk '{print substr($2, 3, length($2)-4)}') \
&& curl -f -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${RUNNER_ARCH}-${RUNNER_VERSION}.tar.gz \
&& tar xzf ./runner.tar.gz \
&& rm runner.tar.gz
RUN RUNNER_CONTAINER_HOOKS_VERSION=$(curl -s https://api.github.com/repos/actions/runner-container-hooks/releases/latest | grep "tag_name" | head -n 1 | awk '{print substr($2, 3, length($2)-4)}') \
&& curl -f -L -o runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \
&& unzip ./runner-container-hooks.zip -d ./k8s \
&& rm runner-container-hooks.zip
RUN export RUNNER_ARCH=${TARGETARCH} \
&& if [ "$RUNNER_ARCH" = "amd64" ]; then export DOCKER_ARCH=x86_64 ; fi \
&& if [ "$RUNNER_ARCH" = "arm64" ]; then export DOCKER_ARCH=aarch64 ; fi \
&& curl -fLo docker.tgz https://download.docker.com/${TARGETOS}/static/stable/${DOCKER_ARCH}/docker-${DOCKER_VERSION}.tgz \
&& tar zxvf docker.tgz \
&& rm -rf docker.tgz \
&& mkdir -p /usr/local/lib/docker/cli-plugins \
&& curl -fLo /usr/local/lib/docker/cli-plugins/docker-buildx \
"https://github.com/docker/buildx/releases/download/v${BUILDX_VERSION}/buildx-v${BUILDX_VERSION}.linux-${TARGETARCH}" \
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy
ENV DEBIAN_FRONTEND=noninteractive
ENV RUNNER_MANUALLY_TRAP_SIG=1
ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1
ENV ImageOS=ubuntu22
RUN apt update -y \
&& apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common curl jq unzip \
&& rm -rf /var/lib/apt/lists/*
RUN add-apt-repository ppa:git-core/ppa \
&& apt update -y \
&& apt install -y git \
&& rm -rf /var/lib/apt/lists/*
RUN adduser --disabled-password --gecos "" --uid 1001 runner \
&& groupadd docker --gid 123 \
&& usermod -aG sudo runner \
&& usermod -aG docker runner \
&& echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers \
&& echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >> /etc/sudoers
# Install own dependencies in final image
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y nodejs \
&& apt-get install -y gh jq git
WORKDIR /home/runner
COPY --chown=runner:docker --from=build /actions-runner .
COPY --from=build /usr/local/lib/docker/cli-plugins/docker-buildx /usr/local/lib/docker/cli-plugins/docker-buildx
RUN install -o root -g root -m 755 docker/* /usr/bin/ && rm -rf docker
USER runner

2
.github/workflows/autolabeler.yml generated vendored
View File

@@ -93,7 +93,7 @@ jobs:
const websiteRegex = new RegExp(`- \\[(x|X)\\]\\s*${escapedWebsite}`, "i");
if (websiteRegex.test(prBody)) {
const hasJson = prFiles.some((f) => f.filename.startsWith("frontend/public/json/"));
const hasJson = prFiles.some((f) => f.filename.startsWith("json/"));
const hasUpdateScript = labelsToAdd.has("update script");
const hasContentLabel = ["bugfix", "feature", "refactor"].some((l) => labelsToAdd.has(l));

View File

@@ -1,55 +0,0 @@
name: Auto-Close Wrong Template Issues
on:
issues:
types: [opened]
jobs:
close_tteck_issues:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest
steps:
- name: Auto-close if wrong Template issue detected
uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue;
const content = `${issue.title}\n${issue.body}`;
const issueNumber = issue.number;
// Regex patterns (case-insensitive, flexible versioning)
const patterns = [
/Template\s+debian-13-standard_[\d.]+-[\d]+_amd64\.tar\.zst\s*\[(online|local)\]/i,
/Template\s+debian-13-standard_[\d.]+-[\d]+_amd64\.tar\.zst\s+is\s+missing\s+or\s+corrupted/i,
/Container\s+creation\s+failed\.?\s+Checking\s+if\s+template\s+is\s+corrupted\s+or\s+incomplete/i,
/Template\s+is\s+valid,\s+but\s+container\s+creation\s+still\s+failed/i,
/exit\s+code\s+0:\s+while\s+executing\s+command\s+bash\s+-c\s+"\$?\(curl\s+-fsSL\s+https:\/\/raw\.githubusercontent\.com\/[\w/-]+\/create_lxc\.sh\)"/i
];
const matched = patterns.some((regex) => regex.test(content));
if (matched) {
const message = "👋 Hello!\n\n" +
"It looks like you are referencing a **container creation issue with a Debian 13 template** (e.g. `debian-13-standard_13.x-x_amd64.tar.zst`).\n\n" +
"We receive many similar reports about this, and it's not related to the scripts themselves but to **a Proxmox base template bug**.\n\n" +
"Please refer to [discussion #8126](https://github.com/community-scripts/ProxmoxVE/discussions/8126) for details.\n" +
"If your issue persists after following the guidance there, feel free to reopen this issue.\n\n" +
"_This issue was automatically closed by a bot._";
await github.rest.issues.createComment({
...context.repo,
issue_number: issueNumber,
body: message
});
await github.rest.issues.addLabels({
...context.repo,
issue_number: issueNumber,
labels: ["not planned"]
});
await github.rest.issues.update({
...context.repo,
issue_number: issueNumber,
state: "closed"
});
}

View File

@@ -1,126 +0,0 @@
name: Crawl Versions from newreleases.io
on:
workflow_dispatch:
schedule:
# Runs at 12:00 AM and 12:00 PM UTC
- cron: "0 0,12 * * *"
permissions:
contents: write
pull-requests: write
jobs:
crawl-versions:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
with:
repository: community-scripts/ProxmoxVE
ref: main
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Crawl from newreleases.io
env:
token: ${{ secrets.NEWRELEASES_TOKEN }}
run: |
page=1
projects_file="project_json"
output_file="frontend/public/json/versions.json"
echo "[]" > $output_file
while true; do
echo "Start loop on page: $page"
projects=$(curl -s -H "X-Key: $token" "https://api.newreleases.io/v1/projects?page=$page")
total_pages=$(echo "$projects" | jq -r '.total_pages')
if [ -z "$total_pages" ] || [ "$total_pages" -eq 0 ]; then
echo "No pages available. Exiting."
exit 1
fi
if [ $page == $total_pages ]; then
break
fi
if [ -z "$projects" ] || ! echo "$projects" | jq -e '.projects' > /dev/null; then
echo "No more projects or invalid response. Exiting."
break
fi
echo "$projects" > "$projects_file"
jq -r '.projects[] | "\(.id) \(.name)"' "$projects_file" | while read -r id name; do
version=$(curl -s -H "X-Key: $token" "https://api.newreleases.io/v1/projects/$id/latest-release")
version_data=$(echo "$version" | jq -r '.version // empty')
date=$(echo "$version" | jq -r '.date // empty')
if [ -n "$version_data" ]; then
jq --arg name "$name" --arg version "$version_data" --arg date "$date" \
'. += [{"name": $name, "version": $version, "date": $date}]' "$output_file" > "$output_file.tmp" && mv "$output_file.tmp" "$output_file"
fi
done
((page++))
done
- name: Commit JSON
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "GitHub Actions[bot]"
git checkout -b update_versions || git checkout update_versions
git add frontend/public/json/versions.json
if git diff --cached --quiet; then
echo "No changes detected."
echo "changed=false" >> "$GITHUB_ENV"
exit 0
else
echo "Changes detected:"
git diff --stat --cached
echo "changed=true" >> "$GITHUB_ENV"
fi
git commit -m "Update versions.json"
git push origin update_versions --force
gh pr create --title "[Github Action] Update versions.json" --body "Update versions.json, crawled from newreleases.io" --base main --head update_versions --label "automated pr"
- name: Approve pull request
if: env.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER=$(gh pr list --head "update_versions" --json number --jq '.[].number')
if [ -n "$PR_NUMBER" ]; then
gh pr review $PR_NUMBER --approve
fi
- name: Approve pull request and merge
if: env.changed == 'true'
env:
GH_TOKEN: ${{ secrets.PAT_AUTOMERGE }}
run: |
PR_NUMBER=$(gh pr list --head "update_versions" --json number --jq '.[].number')
if [ -n "$PR_NUMBER" ]; then
gh pr review $PR_NUMBER --approve
gh pr merge $PR_NUMBER --squash --admin
fi
- name: Re-approve pull request after update
if: env.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER=$(gh pr list --head "update_versions" --json number --jq '.[].number')
if [ -n "$PR_NUMBER" ]; then
gh pr review $PR_NUMBER --approve
fi

175
.github/workflows/bak/script-test.yml generated vendored
View File

@@ -1,175 +0,0 @@
name: Run Scripts on PVE Node for testing
permissions:
pull-requests: write
on:
pull_request_target:
branches:
- main
paths:
- "install/**.sh"
- "ct/**.sh"
jobs:
run-install-script:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: pvenode
steps:
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: 0
- name: Add Git safe directory
run: |
git config --global --add safe.directory /__w/ProxmoxVE/ProxmoxVE
- name: Set up GH_TOKEN
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV
- name: Get Changed Files
run: |
CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only)
CHANGED_FILES=$(echo "$CHANGED_FILES" | tr '\n' ' ')
echo "Changed files: $CHANGED_FILES"
echo "SCRIPT=$CHANGED_FILES" >> $GITHUB_ENV
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get scripts
id: check-install-script
run: |
ALL_FILES=()
ADDED_FILES=()
for FILE in ${{ env.SCRIPT }}; do
if [[ $FILE =~ ^install/.*-install\.sh$ ]] || [[ $FILE =~ ^ct/.*\.sh$ ]]; then
STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//')
if [[ ! " ${ADDED_FILES[@]} " =~ " $STRIPPED_NAME " ]]; then
ALL_FILES+=("$FILE")
ADDED_FILES+=("$STRIPPED_NAME") # Mark this base file as added (without the path)
fi
fi
done
ALL_FILES=$(echo "${ALL_FILES[@]}" | xargs)
echo "$ALL_FILES"
echo "ALL_FILES=$ALL_FILES" >> $GITHUB_ENV
- name: Run scripts
id: run-install
continue-on-error: true
run: |
set +e
#run for each files in /ct
for FILE in ${{ env.ALL_FILES }}; do
STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//')
echo "Running Test for: $STRIPPED_NAME"
if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "$FILE"; then
echo "The script contains an interactive prompt. Skipping execution."
continue
fi
if [[ $FILE =~ ^install/.*-install\.sh$ ]]; then
CT_SCRIPT="ct/$STRIPPED_NAME.sh"
if [[ ! -f $CT_SCRIPT ]]; then
echo "No CT script found for $STRIPPED_NAME"
ERROR_MSG="No CT script found for $FILE"
echo "$ERROR_MSG" > result_$STRIPPED_NAME.log
continue
fi
if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "install/$STRIPPED_NAME-install.sh"; then
echo "The script contains an interactive prompt. Skipping execution."
continue
fi
echo "Found CT script for $STRIPPED_NAME"
chmod +x "$CT_SCRIPT"
RUNNING_FILE=$CT_SCRIPT
elif [[ $FILE =~ ^ct/.*\.sh$ ]]; then
INSTALL_SCRIPT="install/$STRIPPED_NAME-install.sh"
if [[ ! -f $INSTALL_SCRIPT ]]; then
echo "No install script found for $STRIPPED_NAME"
ERROR_MSG="No install script found for $FILE"
echo "$ERROR_MSG" > result_$STRIPPED_NAME.log
continue
fi
echo "Found install script for $STRIPPED_NAME"
chmod +x "$INSTALL_SCRIPT"
RUNNING_FILE=$FILE
if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "ct/$STRIPPED_NAME.sh"; then
echo "The script contains an interactive prompt. Skipping execution."
continue
fi
fi
git remote add community-scripts https://github.com/community-scripts/ProxmoxVE.git
git fetch community-scripts
rm -f .github/workflows/scripts/app-test/pr-build.func || true
rm -f .github/workflows/scripts/app-test/pr-install.func || true
rm -f .github/workflows/scripts/app-test/pr-alpine-install.func || true
rm -f .github/workflows/scripts/app-test/pr-create-lxc.sh || true
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-build.func
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-install.func
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-alpine-install.func
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-create-lxc.sh
chmod +x $RUNNING_FILE
chmod +x .github/workflows/scripts/app-test/pr-create-lxc.sh
chmod +x .github/workflows/scripts/app-test/pr-install.func
chmod +x .github/workflows/scripts/app-test/pr-alpine-install.func
chmod +x .github/workflows/scripts/app-test/pr-build.func
sed -i 's|source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)|source .github/workflows/scripts/app-test/pr-build.func|g' "$RUNNING_FILE"
echo "Executing $RUNNING_FILE"
ERROR_MSG=$(./$RUNNING_FILE 2>&1 > /dev/null)
echo "Finished running $FILE"
if [ -n "$ERROR_MSG" ]; then
echo "ERROR in $STRIPPED_NAME: $ERROR_MSG"
echo "$ERROR_MSG" > result_$STRIPPED_NAME.log
fi
done
set -e # Restore exit-on-error
- name: Cleanup PVE Node
run: |
containers=$(pct list | tail -n +2 | awk '{print $0 " " $4}' | awk '{print $1}')
for container_id in $containers; do
status=$(pct status $container_id | awk '{print $2}')
if [[ $status == "running" ]]; then
pct stop $container_id
pct destroy $container_id
fi
done
- name: Post error comments
run: |
ERROR="false"
SEARCH_LINE=".github/workflows/scripts/app-test/pr-build.func: line 255:"
# Get all existing comments on the PR
EXISTING_COMMENTS=$(gh pr view ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --json comments --jq '.comments[].body')
for FILE in ${{ env.ALL_FILES }}; do
STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//')
if [[ ! -f result_$STRIPPED_NAME.log ]]; then
continue
fi
ERROR_MSG=$(cat result_$STRIPPED_NAME.log)
if [ -n "$ERROR_MSG" ]; then
CLEANED_ERROR_MSG=$(echo "$ERROR_MSG" | sed "s|$SEARCH_LINE.*||")
COMMENT_BODY=":warning: The script _**$FILE**_ failed with the following message: <br> <div><strong>${CLEANED_ERROR_MSG}</strong></div>"
# Check if the comment already exists
if echo "$EXISTING_COMMENTS" | grep -qF "$COMMENT_BODY"; then
echo "Skipping duplicate comment for $FILE"
else
echo "Posting error message for $FILE"
gh pr comment ${{ github.event.pull_request.number }} \
--repo ${{ github.repository }} \
--body "$COMMENT_BODY"
ERROR="true"
fi
fi
done
echo "ERROR=$ERROR" >> $GITHUB_ENV

View File

@@ -1,243 +0,0 @@
name: Script Format Check
permissions:
pull-requests: write
on:
pull_request_target:
branches:
- main
paths:
- "install/*.sh"
- "ct/*.sh"
jobs:
run-install-script:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: pvenode
steps:
- name: Checkout PR branch (supports forks)
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: 0
- name: Add Git safe directory
run: |
git config --global --add safe.directory /__w/ProxmoxVE/ProxmoxVE
- name: Set up GH_TOKEN
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV
- name: Get Changed Files
run: |
CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only)
CHANGED_FILES=$(echo "$CHANGED_FILES" | tr '\n' ' ')
echo "Changed files: $CHANGED_FILES"
echo "SCRIPT=$CHANGED_FILES" >> $GITHUB_ENV
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check scripts
id: run-install
continue-on-error: true
run: |
for FILE in ${{ env.SCRIPT }}; do
STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//')
echo "Running Test for: $STRIPPED_NAME"
FILE_STRIPPED="${FILE##*/}"
LOG_FILE="result_$FILE_STRIPPED.log"
if [[ $FILE =~ ^ct/.*\.sh$ ]]; then
FIRST_LINE=$(sed -n '1p' "$FILE")
[[ "$FIRST_LINE" != "#!/usr/bin/env bash" ]] && echo "Line 1 was $FIRST_LINE | Should be: #!/usr/bin/env bash" >> "$LOG_FILE"
SECOND_LINE=$(sed -n '2p' "$FILE")
[[ "$SECOND_LINE" != "source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)" ]] &&
echo "Line 2 was $SECOND_LINE | Should be: source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)" >> "$LOG_FILE"
THIRD_LINE=$(sed -n '3p' "$FILE")
if ! [[ "$THIRD_LINE" =~ ^#\ Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ community-scripts\ ORG$ || "$THIRD_LINE" =~ ^Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ tteck$ ]]; then
echo "Line 3 was $THIRD_LINE | Should be: # Copyright (c) 2021-2026 community-scripts ORG" >> "$LOG_FILE"
fi
EXPECTED_AUTHOR="# Author:"
EXPECTED_LICENSE="# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE"
EXPECTED_SOURCE="# Source:"
EXPECTED_EMPTY=""
for i in {4..7}; do
LINE=$(sed -n "${i}p" "$FILE")
case $i in
4)
[[ $LINE == $EXPECTED_AUTHOR* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_AUTHOR" >> $LOG_FILE
;;
5)
[[ "$LINE" == "$EXPECTED_LICENSE" ]] || printf "Line %d was: '%s' | Should be: '%s'\n" "$i" "$LINE" "$EXPECTED_LICENSE" >> $LOG_FILE
;;
6)
[[ $LINE == $EXPECTED_SOURCE* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_SOURCE" >> $LOG_FILE
;;
7)
[[ -z $LINE ]] || printf "Line %d was: '%s' | Should be empty\n" "$i" "$LINE" >> $LOG_FILE
;;
esac
done
EXPECTED_PREFIXES=(
"APP="
"var_tags="
"var_cpu=" # Must be a number
"var_ram=" # Must be a number
"var_disk=" # Must be a number
"var_os=" # Must be debian, alpine, or ubuntu
"var_version="
"var_unprivileged=" # Must be 0 or 1
)
for i in {8..15}; do
LINE=$(sed -n "${i}p" "$FILE")
INDEX=$((i - 8))
case $INDEX in
2|3|4) # var_cpu, var_ram, var_disk (must be numbers)
if [[ "$LINE" =~ ^${EXPECTED_PREFIXES[$INDEX]}([0-9]+)$ ]]; then
continue # Valid
else
echo "Line $i was '$LINE' | Should be: '${EXPECTED_PREFIXES[$INDEX]}<NUMBER>'" >> "$LOG_FILE"
fi
;;
5) # var_os (must be debian, alpine, or ubuntu)
if [[ "$LINE" =~ ^var_os=(debian|alpine|ubuntu)$ ]]; then
continue # Valid
else
echo "Line $i was '$LINE' | Should be: 'var_os=[debian|alpine|ubuntu]'" >> "$LOG_FILE"
fi
;;
7) # var_unprivileged (must be 0 or 1)
if [[ "$LINE" =~ ^var_unprivileged=[01]$ ]]; then
continue # Valid
else
echo "Line $i was '$LINE' | Should be: 'var_unprivileged=[0|1]'" >> "$LOG_FILE"
fi
;;
*) # Other lines (must start with expected prefix)
if [[ "$LINE" == ${EXPECTED_PREFIXES[$INDEX]}* ]]; then
continue # Valid
else
echo "Line $i was '$LINE' | Should start with '${EXPECTED_PREFIXES[$INDEX]}'" >> "$LOG_FILE"
fi
;;
esac
done
for i in {16..20}; do
LINE=$(sed -n "${i}p" "$FILE")
EXPECTED=(
"header_info \"$APP\""
"variables"
"color"
"catch_errors"
"function update_script() {"
)
[[ "$LINE" != "${EXPECTED[$((i-16))]}" ]] && echo "Line $i was $LINE | Should be: ${EXPECTED[$((i-16))]}" >> "$LOG_FILE"
done
cat "$LOG_FILE"
elif [[ $FILE =~ ^install/.*-install\.sh$ ]]; then
FIRST_LINE=$(sed -n '1p' "$FILE")
[[ "$FIRST_LINE" != "#!/usr/bin/env bash" ]] && echo "Line 1 was $FIRST_LINE | Should be: #!/usr/bin/env bash" >> "$LOG_FILE"
SECOND_LINE=$(sed -n '2p' "$FILE")
[[ -n "$SECOND_LINE" ]] && echo "Line 2 should be empty" >> "$LOG_FILE"
THIRD_LINE=$(sed -n '3p' "$FILE")
if ! [[ "$THIRD_LINE" =~ ^#\ Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ community-scripts\ ORG$ || "$THIRD_LINE" =~ ^Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ tteck$ ]]; then
echo "Line 3 was $THIRD_LINE | Should be: # Copyright (c) 2021-2026 community-scripts ORG" >> "$LOG_FILE"
fi
EXPECTED_AUTHOR="# Author:"
EXPECTED_LICENSE="# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE"
EXPECTED_SOURCE="# Source:"
EXPECTED_EMPTY=""
for i in {4..7}; do
LINE=$(sed -n "${i}p" "$FILE")
case $i in
4)
[[ $LINE == $EXPECTED_AUTHOR* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_AUTHOR" >> $LOG_FILE
;;
5)
[[ "$LINE" == "$EXPECTED_LICENSE" ]] || printf "Line %d was: '%s' | Should be: '%s'\n" "$i" "$LINE" "$EXPECTED_LICENSE" >> $LOG_FILE
;;
6)
[[ $LINE == $EXPECTED_SOURCE* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_SOURCE" >> $LOG_FILE
;;
7)
[[ -z $LINE ]] || printf "Line %d was: '%s' | Should be empty\n" "$i" "$LINE" >> $LOG_FILE
;;
esac
done
[[ "$(sed -n '8p' "$FILE")" != 'source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"' ]] && echo 'Line 8 should be: source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"' >> "$LOG_FILE"
for i in {9..14}; do
LINE=$(sed -n "${i}p" "$FILE")
EXPECTED=(
"color"
"verb_ip6"
"catch_errors"
"setting_up_container"
"network_check"
"update_os"
)
[[ "$LINE" != "${EXPECTED[$((i-9))]}" ]] && echo "Line $i was $LINE | Should be: ${EXPECTED[$((i-9))]}" >> "$LOG_FILE"
done
[[ -n "$(sed -n '15p' "$FILE")" ]] && echo "Line 15 should be empty" >> "$LOG_FILE"
[[ "$(sed -n '16p' "$FILE")" != 'msg_info "Installing Dependencies"' ]] && echo 'Line 16 should be: msg_info "Installing Dependencies"' >> "$LOG_FILE"
LAST_3_LINES=$(tail -n 3 "$FILE")
[[ "$LAST_3_LINES" != *"$STD apt-get -y autoremove"* ]] && echo 'Third to last line should be: $STD apt-get -y autoremove' >> "$LOG_FILE"
[[ "$LAST_3_LINES" != *"$STD apt-get -y autoclean"* ]] && echo 'Second to last line should be: $STD apt-get -y clean' >> "$LOG_FILE"
[[ "$LAST_3_LINES" != *'msg_ok "Cleaned"'* ]] && echo 'Last line should be: msg_ok "Cleaned"' >> "$LOG_FILE"
cat "$LOG_FILE"
fi
done
- name: Post error comments
run: |
ERROR="false"
for FILE in ${{ env.SCRIPT }}; do
FILE_STRIPPED="${FILE##*/}"
LOG_FILE="result_$FILE_STRIPPED.log"
echo $LOG_FILE
if [[ ! -f $LOG_FILE ]]; then
continue
fi
ERROR_MSG=$(cat $LOG_FILE)
if [ -n "$ERROR_MSG" ]; then
echo "Posting error message for $FILE"
echo ${ERROR_MSG}
gh pr comment ${{ github.event.pull_request.number }} \
--repo ${{ github.repository }} \
--body ":warning: The script _**$FILE**_ has the following formatting errors: <br> <div><strong>${ERROR_MSG}</strong></div>"
ERROR="true"
fi
done
echo "ERROR=$ERROR" >> $GITHUB_ENV
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Fail if error
if: ${{ env.ERROR == 'true' }}
run: exit 1

View File

@@ -1,158 +0,0 @@
name: Validate filenames
on:
pull_request_target:
paths:
- "ct/*.sh"
- "install/*.sh"
- "frontend/public/json/*.json"
jobs:
check-files:
if: github.repository == 'community-scripts/ProxmoxVE'
name: Check changed files
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Get pull request information
if: github.event_name == 'pull_request_target'
uses: actions/github-script@v7
id: pr
with:
script: |
const { data: pullRequest } = await github.rest.pulls.get({
...context.repo,
pull_number: context.payload.pull_request.number,
});
return pullRequest;
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Ensure the full history is fetched for accurate diffing
ref: ${{ github.event_name == 'pull_request_target' && fromJSON(steps.pr.outputs.result).merge_commit_sha || '' }}
- name: Get changed files
id: changed-files
run: |
if ${{ github.event_name == 'pull_request_target' }}; then
echo "files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ steps.pr.outputs.result && fromJSON(steps.pr.outputs.result).merge_commit_sha }} | xargs)" >> $GITHUB_OUTPUT
else
echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | xargs)" >> $GITHUB_OUTPUT
fi
- name: "Validate filenames in ct and install directory"
if: always() && steps.changed-files.outputs.files != ''
id: check-scripts
run: |
CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^(ct|install)/.*\.sh$' || true; })
NON_COMPLIANT_FILES=""
for FILE in $CHANGED_FILES; do
BASENAME=$(echo "$(basename "${FILE%.*}")")
if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
fi
done
if [ -n "$NON_COMPLIANT_FILES" ]; then
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
echo "Non-compliant filenames found, change to lowercase:"
for FILE in $NON_COMPLIANT_FILES; do
echo "$FILE"
done
exit 1
fi
- name: "Validate filenames in json directory."
if: always() && steps.changed-files.outputs.files != ''
id: check-json
run: |
CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^json/.*\.json$' || true; })
NON_COMPLIANT_FILES=""
for FILE in $CHANGED_FILES; do
BASENAME=$(echo "$(basename "${FILE%.*}")")
if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
fi
done
if [ -n "$NON_COMPLIANT_FILES" ]; then
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
echo "Non-compliant filenames found, change to lowercase:"
for FILE in $NON_COMPLIANT_FILES; do
echo "$FILE"
done
exit 1
fi
- name: Post results and comment
if: always() && steps.check-scripts.outputs.files != '' && steps.check-json.outputs.files != '' && github.event_name == 'pull_request_target'
uses: actions/github-script@v7
with:
script: |
const result = "${{ job.status }}" === "success" ? "success" : "failure";
const nonCompliantFiles = {
script: "${{ steps.check-scripts.outputs.files }}",
JSON: "${{ steps.check-json.outputs.files }}",
};
const issueNumber = context.payload.pull_request
? context.payload.pull_request.number
: null;
const commentIdentifier = "validate-filenames";
let newCommentBody = `<!-- ${commentIdentifier}-start -->\n### Filename validation\n\n`;
if (result === "failure") {
newCommentBody += ":x: We found issues in the following changed files:\n\n";
for (const [check, files] of Object.entries(nonCompliantFiles)) {
if (files) {
newCommentBody += `**${check.charAt(0).toUpperCase() + check.slice(1)} filename invalid:**\n${files
.trim()
.split(" ")
.map((file) => `- ${file}`)
.join("\n")}\n\n`;
}
}
newCommentBody +=
"Please change the filenames to lowercase and use only alphanumeric characters and dashes.\n";
} else {
newCommentBody += `:rocket: All files passed filename validation!\n`;
}
newCommentBody += `\n\n<!-- ${commentIdentifier}-end -->`;
if (issueNumber) {
const { data: comments } = await github.rest.issues.listComments({
...context.repo,
issue_number: issueNumber,
});
const existingComment = comments.find(
(comment) => comment.user.login === "github-actions[bot]",
);
if (existingComment) {
if (existingComment.body.includes(commentIdentifier)) {
const re = new RegExp(String.raw`<!-- ${commentIdentifier}-start -->[\s\S]*?<!-- ${commentIdentifier}-end -->`, "");
newCommentBody = existingComment.body.replace(re, newCommentBody);
} else {
newCommentBody = existingComment.body + '\n\n---\n\n' + newCommentBody;
}
await github.rest.issues.updateComment({
...context.repo,
comment_id: existingComment.id,
body: newCommentBody,
});
} else {
await github.rest.issues.createComment({
...context.repo,
issue_number: issueNumber,
body: newCommentBody,
});
}
}

View File

@@ -1,164 +0,0 @@
name: Close Discussion on PR Merge
on:
push:
branches:
- main
permissions:
contents: read
discussions: write
jobs:
close-discussion:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Set Up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install Dependencies
run: npm install zx @octokit/graphql
- name: Close Discussion
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_SHA: ${{ github.sha }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
npx zx << 'EOF'
import { graphql } from "@octokit/graphql";
(async function () {
try {
const token = process.env.GITHUB_TOKEN;
const commitSha = process.env.GITHUB_SHA;
const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/");
if (!token || !commitSha || !owner || !repo) {
console.log("Missing required environment variables.");
process.exit(1);
}
const graphqlWithAuth = graphql.defaults({
headers: { authorization: `Bearer ${token}` },
});
// Find PR from commit SHA
const searchQuery = `
query($owner: String!, $repo: String!, $sha: GitObjectID!) {
repository(owner: $owner, name: $repo) {
object(oid: $sha) {
... on Commit {
associatedPullRequests(first: 1) {
nodes {
number
body
}
}
}
}
}
}
`;
const prResult = await graphqlWithAuth(searchQuery, {
owner,
repo,
sha: commitSha,
});
const pr = prResult.repository.object.associatedPullRequests.nodes[0];
if (!pr) {
console.log("No PR found for this commit.");
return;
}
const prNumber = pr.number;
const prBody = pr.body;
const match = prBody.match(/#(\d+)/);
if (!match) {
console.log("No discussion ID found in PR body.");
return;
}
const discussionNumber = match[1];
console.log(`Extracted Discussion Number: ${discussionNumber}`);
// Fetch GraphQL discussion ID
const discussionQuery = `
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
discussion(number: $number) {
id
}
}
}
`;
let discussionQLId;
try {
const discussionResponse = await graphqlWithAuth(discussionQuery, {
owner,
repo,
number: parseInt(discussionNumber, 10),
});
discussionQLId = discussionResponse.repository.discussion.id;
if (!discussionQLId) {
console.log("Failed to fetch discussion GraphQL ID.");
return;
}
} catch (error) {
console.error("Discussion not found or error occurred while fetching discussion:", error);
return;
}
// Post comment
const commentMutation = `
mutation($discussionId: ID!, $body: String!) {
addDiscussionComment(input: { discussionId: $discussionId, body: $body }) {
comment { id body }
}
}
`;
const commentResponse = await graphqlWithAuth(commentMutation, {
discussionId: discussionQLId,
body: `Merged with PR #${prNumber}`,
});
const commentId = commentResponse.addDiscussionComment.comment.id;
if (!commentId) {
console.log("Failed to post the comment.");
return;
}
console.log(`Comment Posted Successfully! Comment ID: ${commentId}`);
// Mark comment as answer
const markAnswerMutation = `
mutation($id: ID!) {
markDiscussionCommentAsAnswer(input: { id: $id }) {
discussion { id title }
}
}
`;
await graphqlWithAuth(markAnswerMutation, { id: commentId });
console.log("Comment marked as answer successfully!");
} catch (error) {
console.error("Error:", error);
process.exit(1);
}
})();
EOF

View File

@@ -1,38 +0,0 @@
name: Build and Publish Docker Image
on:
push:
branches:
- main
paths:
- '.github/runner/docker/**'
schedule:
- cron: '0 0 * * *'
jobs:
build:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest #To ensure it always builds we use the github runner with all the right tooling
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker image
run: |
repo_name=${{ github.repository }} # Get repository name
repo_name_lower=$(echo $repo_name | tr '[:upper:]' '[:lower:]') # Convert to lowercase
docker build -t ghcr.io/$repo_name_lower/gh-runner-self:latest -f .github/runner/docker/gh-runner-self.dockerfile .
- name: Push Docker image to GHCR
run: |
repo_name=${{ github.repository }} # Get repository name
repo_name_lower=$(echo $repo_name | tr '[:upper:]' '[:lower:]') # Convert to lowercase
docker push ghcr.io/$repo_name_lower/gh-runner-self:latest

View File

@@ -1,29 +0,0 @@
name: Delete JSON date PR Branch
on:
pull_request:
types: [closed]
branches:
- main
jobs:
delete_branch:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest
steps:
- name: Checkout the code
uses: actions/checkout@v3
- name: Delete PR Update Branch
if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'pr-update-json-')
run: |
PR_BRANCH="${{ github.event.pull_request.head.ref }}"
echo "Deleting branch $PR_BRANCH..."
# Avoid deleting the default branch (e.g., main)
if [[ "$PR_BRANCH" != "main" ]]; then
git push origin --delete "$PR_BRANCH"
else
echo "Skipping deletion of the main branch"
fi

View File

@@ -5,7 +5,7 @@ on:
branches:
- main
paths:
- "frontend/public/json/**"
- "json/**"
- "vm/**"
- "tools/**"
- "turnkey/**"
@@ -29,7 +29,7 @@ jobs:
slugs=""
# Deleted JSON files: get slug from previous commit
deleted_json=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- frontend/public/json/ | grep '\.json$' || true)
deleted_json=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- json/ | grep '\.json$' || true)
for f in $deleted_json; do
[[ -z "$f" ]] && continue
s=$(git show "$BEFORE:$f" 2>/dev/null | jq -r '.slug // empty' 2>/dev/null || true)

147
.github/workflows/frontend-cicd.yml generated vendored
View File

@@ -1,147 +0,0 @@
# Based on https://github.com/actions/starter-workflows/blob/main/pages/nextjs.yml
name: Frontend CI/CD
on:
push:
branches: ["main"]
paths:
- frontend/**
pull_request:
branches: ["main"]
types: [opened, synchronize, reopened, edited]
paths:
- frontend/**
workflow_dispatch:
permissions:
contents: read
concurrency:
group: pages-${{ github.ref }}
cancel-in-progress: false
jobs:
test-json-files:
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Test JSON files
run: |
python3 << 'EOF'
import json
import glob
import os
import sys
def test_json_files():
# Change to the correct directory
json_dir = "public/json"
if not os.path.exists(json_dir):
print(f"❌ Directory not found: {json_dir}")
return False
# Find all JSON files
pattern = os.path.join(json_dir, "*.json")
json_files = glob.glob(pattern)
if not json_files:
print(f"⚠️ No JSON files found in {json_dir}")
return True
print(f"Testing {len(json_files)} JSON files for valid syntax...")
invalid_files = []
for file_path in json_files:
try:
with open(file_path, 'r', encoding='utf-8') as f:
json.load(f)
print(f"✅ Valid JSON: {file_path}")
except json.JSONDecodeError as e:
print(f"❌ Invalid JSON syntax in: {file_path}")
print(f" Error: {e}")
invalid_files.append(file_path)
except Exception as e:
print(f"⚠️ Error reading: {file_path}")
print(f" Error: {e}")
invalid_files.append(file_path)
print("\n=== JSON Validation Summary ===")
print(f"Total files tested: {len(json_files)}")
print(f"Valid files: {len(json_files) - len(invalid_files)}")
print(f"Invalid files: {len(invalid_files)}")
if invalid_files:
print("\n❌ Found invalid JSON file(s):")
for file_path in invalid_files:
print(f" - {file_path}")
return False
else:
print("\n✅ All JSON files have valid syntax!")
return True
if __name__ == "__main__":
success = test_json_files()
sys.exit(0 if success else 1)
EOF
build:
if: github.repository == 'community-scripts/ProxmoxVE'
needs: test-json-files
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Configure Next.js for pages
uses: actions/configure-pages@v5
with:
static_site_generator: next
- name: Build with Next.js
run: bun run build
- name: Upload artifact
if: github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v3
with:
path: frontend/out
deploy:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main' && github.repository == 'community-scripts/ProxmoxVE'
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

View File

@@ -5,7 +5,7 @@ on:
branches:
- main
paths:
- "frontend/public/json/**"
- "json/**"
jobs:
push-json:
@@ -19,7 +19,7 @@ jobs:
- name: Get changed JSON files with slug
id: changed
run: |
changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.event.after }}" -- frontend/public/json/ | grep '\.json$' || true)
changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.event.after }}" -- json/ | grep '\.json$' || true)
with_slug=""
for f in $changed; do
[[ -f "$f" ]] || continue
@@ -96,7 +96,7 @@ jobs:
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
let categoryIdToName = {};
try {
const metadata = JSON.parse(fs.readFileSync('frontend/public/json/metadata.json', 'utf8'));
const metadata = JSON.parse(fs.readFileSync('json/metadata.json', 'utf8'));
(metadata.categories || []).forEach(function(cat) { categoryIdToName[cat.id] = cat.name; });
} catch (e) { console.warn('Could not load metadata.json:', e.message); }
let typeValueToId = {};

48
.github/workflows/push-to-gitea.yaml generated vendored
View File

@@ -1,48 +0,0 @@
name: Sync to Gitea
on:
push:
branches:
- main
jobs:
sync:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest
steps:
- name: Checkout source repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Change all links to git.community-scripts.org
run: |
echo "Searching for files containing raw.githubusercontent.com URLs..."
# Find all files containing GitHub raw URLs, excluding certain directories
files_with_github_urls=$(grep -r "https://raw.githubusercontent.com/community-scripts/ProxmoxVE" . --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=.github/workflows --files-with-matches || true)
if [ -n "$files_with_github_urls" ]; then
echo "$files_with_github_urls" | while read file; do
if [ -f "$file" ]; then
sed -i 's|https://raw\.githubusercontent\.com/community-scripts/ProxmoxVE/|https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/|g' "$file"
fi
done
else
echo "No files found containing GitHub raw URLs"
fi
- name: Push to Gitea
run: |
git config --global user.name "Push From Github"
git config --global user.email "actions@github.com"
git remote add gitea https://$GITEA_USER:$GITEA_TOKEN@git.community-scripts.org/community-scripts/ProxmoxVE.git
git add .
git commit -m "Sync to Gitea"
git push gitea --all --force
env:
GITEA_USER: ${{ secrets.GITEA_USERNAME }}
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}

View File

@@ -1,85 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Michel Roegl-Brunner (michelroegl-brunner)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
color() {
return
}
catch_errors() {
set -Eeuo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# This function handles errors
error_handler() {
local line_number="$1"
local command="$2"
SCRIPT_NAME=$(basename "$0")
local error_message="$SCRIPT_NAME: Failure in line $line_number while executing command $command"
echo -e "\n$error_message"
exit 0
}
verb_ip6() {
STD=""
return
}
msg_info() {
local msg="$1"
echo -ne "${msg}\n"
}
msg_ok() {
local msg="$1"
echo -e "${msg}\n"
}
msg_error() {
local msg="$1"
echo -e "${msg}\n"
}
RETRY_NUM=10
RETRY_EVERY=3
i=$RETRY_NUM
setting_up_container() {
while [ $i -gt 0 ]; do
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
break
fi
echo 1>&2 -en "No Network! "
sleep $RETRY_EVERY
i=$((i - 1))
done
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then
echo 1>&2 -e "\n No Network After $RETRY_NUM Tries"
echo -e "Check Network Settings"
exit 1
fi
msg_ok "Set up Container OS"
msg_ok "Network Connected: $(hostname -i)"
}
network_check() {
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi
set -e
}
update_os() {
msg_info "Updating Container OS"
$STD apk -U upgrade
msg_ok "Updated Container OS"
}
motd_ssh() {
return
}
customize() {
return
}

View File

@@ -1,260 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Michel Roegl-Brunner (michelroegl-brunner)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
variables() {
NSAPP=$(echo ${APP,,} | tr -d ' ') # This function sets the NSAPP variable by converting the value of the APP variable to lowercase and removing any spaces.
var_install="${NSAPP}-install" # sets the var_install variable by appending "-install" to the value of NSAPP.
}
NEXTID=$(pvesh get /cluster/nextid)
timezone=$(cat /etc/timezone)
header_info() {
return
}
base_settings() {
# Default Settings
CT_TYPE="1"
DISK_SIZE="4"
CORE_COUNT="1"
RAM_SIZE="1024"
VERBOSE="no"
PW=""
CT_ID=$NEXTID
HN=$NSAPP
BRG="vmbr0"
NET="dhcp"
GATE=""
APT_CACHER=""
APT_CACHER_IP=""
DISABLEIP6="no"
MTU=""
SD=""
NS=""
MAC=""
VLAN=""
SSH="no"
SSH_AUTHORIZED_KEY=""
TAGS="community-script;"
# Override default settings with variables from ct script
CT_TYPE=${var_unprivileged:-$CT_TYPE}
DISK_SIZE=${var_disk:-$DISK_SIZE}
CORE_COUNT=${var_cpu:-$CORE_COUNT}
RAM_SIZE=${var_ram:-$RAM_SIZE}
VERB=${var_verbose:-$VERBOSE}
TAGS="${TAGS}${var_tags:-}"
# Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts
if [ -z "$var_os" ]; then
var_os="debian"
fi
if [ -z "$var_version" ]; then
var_version="12"
fi
}
color() {
# Colors
YW=$(echo "\033[33m")
YWB=$(echo "\033[93m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
BGN=$(echo "\033[4;92m")
GN=$(echo "\033[1;92m")
DGN=$(echo "\033[32m")
# Formatting
CL=$(echo "\033[m")
UL=$(echo "\033[4m")
BOLD=$(echo "\033[1m")
BFR="\\r\\033[K"
HOLD=" "
TAB=" "
# Icons
CM="${TAB}✔️${TAB}${CL}"
CROSS="${TAB}✖️${TAB}${CL}"
INFO="${TAB}💡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
OSVERSION="${TAB}🌟${TAB}${CL}"
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
DISKSIZE="${TAB}💾${TAB}${CL}"
CPUCORE="${TAB}🧠${TAB}${CL}"
RAMSIZE="${TAB}🛠️${TAB}${CL}"
SEARCH="${TAB}🔍${TAB}${CL}"
VERIFYPW="${TAB}🔐${TAB}${CL}"
CONTAINERID="${TAB}🆔${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
BRIDGE="${TAB}🌉${TAB}${CL}"
NETWORK="${TAB}📡${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
DISABLEIPV6="${TAB}🚫${TAB}${CL}"
DEFAULT="${TAB}⚙️${TAB}${CL}"
MACADDRESS="${TAB}🔗${TAB}${CL}"
VLANTAG="${TAB}🏷️${TAB}${CL}"
ROOTSSH="${TAB}🔑${TAB}${CL}"
CREATING="${TAB}🚀${TAB}${CL}"
ADVANCED="${TAB}🧩${TAB}${CL}"
}
catch_errors() {
set -Eeuo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# This function handles errors
error_handler() {
local line_number="$1"
local command="$2"
SCRIPT_NAME=$(basename "$0")
local error_message="$SCRIPT_NAME: Failure in line $line_number while executing command $command"
echo -e "\n$error_message"
exit 100
}
msg_info() {
local msg="$1"
echo -ne "${msg}\n"
}
msg_ok() {
local msg="$1"
echo -e "${msg}\n"
}
msg_error() {
local msg="$1"
echo -e "${msg}\n"
}
start() {
base_settings
return
}
build_container() {
# if [ "$VERB" == "yes" ]; then set -x; fi
if [ "$CT_TYPE" == "1" ]; then
FEATURES="keyctl=1,nesting=1"
else
FEATURES="nesting=1"
fi
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR >/dev/null
if [ "$var_os" == "alpine" ]; then
export FUNCTIONS_FILE_PATH="$(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/.github/workflows/scripts/app-test/pr-alpine-install.func)"
else
export FUNCTIONS_FILE_PATH="$(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/.github/workflows/scripts/app-test/pr-install.func)"
fi
export CACHER="$APT_CACHER"
export CACHER_IP="$APT_CACHER_IP"
export tz=""
export DISABLEIPV6="$DISABLEIP6"
export APPLICATION="$APP"
export app="$NSAPP"
export PASSWORD="$PW"
export VERBOSE="$VERB"
export SSH_ROOT="${SSH}"
export SSH_AUTHORIZED_KEY
export CTID="$CT_ID"
export CTTYPE="$CT_TYPE"
export PCT_OSTYPE="$var_os"
export PCT_OSVERSION="$var_version"
export PCT_DISK_SIZE="$DISK_SIZE"
export tz="$timezone"
export PCT_OPTIONS="
-features $FEATURES
-hostname $HN
-tags $TAGS
$SD
$NS
-net0 name=eth0,bridge=$BRG$MAC,ip=$NET$GATE$VLAN$MTU
-onboot 1
-cores $CORE_COUNT
-memory $RAM_SIZE
-unprivileged $CT_TYPE
$PW
"
echo "Container ID: $CTID"
# This executes create_lxc.sh and creates the container and .conf file
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/.github/workflows/scripts/app-test/pr-create-lxc.sh)"
LXC_CONFIG=/etc/pve/lxc/${CTID}.conf
if [ "$CT_TYPE" == "0" ]; then
cat <<EOF >>$LXC_CONFIG
# USB passthrough
lxc.cgroup2.devices.allow: a
lxc.cap.drop:
lxc.cgroup2.devices.allow: c 188:* rwm
lxc.cgroup2.devices.allow: c 189:* rwm
lxc.mount.entry: /dev/serial/by-id dev/serial/by-id none bind,optional,create=dir
lxc.mount.entry: /dev/ttyUSB0 dev/ttyUSB0 none bind,optional,create=file
lxc.mount.entry: /dev/ttyUSB1 dev/ttyUSB1 none bind,optional,create=file
lxc.mount.entry: /dev/ttyACM0 dev/ttyACM0 none bind,optional,create=file
lxc.mount.entry: /dev/ttyACM1 dev/ttyACM1 none bind,optional,create=file
EOF
fi
if [ "$CT_TYPE" == "0" ]; then
if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" ]]; then
cat <<EOF >>$LXC_CONFIG
# VAAPI hardware transcoding
lxc.cgroup2.devices.allow: c 226:0 rwm
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.cgroup2.devices.allow: c 29:0 rwm
lxc.mount.entry: /dev/fb0 dev/fb0 none bind,optional,create=file
lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file
EOF
fi
else
if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" ]]; then
if [[ -e "/dev/dri/renderD128" ]]; then
if [[ -e "/dev/dri/card0" ]]; then
cat <<EOF >>$LXC_CONFIG
# VAAPI hardware transcoding
dev0: /dev/dri/card0,gid=44
dev1: /dev/dri/renderD128,gid=104
EOF
else
cat <<EOF >>$LXC_CONFIG
# VAAPI hardware transcoding
dev0: /dev/dri/card1,gid=44
dev1: /dev/dri/renderD128,gid=104
EOF
fi
fi
fi
fi
# This starts the container and executes <app>-install.sh
msg_info "Starting LXC Container"
pct start "$CTID"
msg_ok "Started LXC Container"
if [[ ! -f "/root/actions-runner/_work/ProxmoxVE/ProxmoxVE/install/$var_install.sh" ]]; then
msg_error "No install script found for $APP"
exit 1
fi
if [ "$var_os" == "alpine" ]; then
sleep 3
pct exec "$CTID" -- /bin/sh -c 'cat <<EOF >/etc/apk/repositories
http://dl-cdn.alpinelinux.org/alpine/latest-stable/main
http://dl-cdn.alpinelinux.org/alpine/latest-stable/community
EOF'
pct exec "$CTID" -- ash -c "apk add bash >/dev/null"
fi
lxc-attach -n "$CTID" -- bash -c "$(cat /root/actions-runner/_work/ProxmoxVE/ProxmoxVE/install/$var_install.sh)"
}
description() {
IP=$(pct exec "$CTID" ip a s dev eth0 | awk '/inet / {print $2}' | cut -d/ -f1)
}

View File

@@ -1,163 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Michel Roegl-Brunner (michelroegl-brunner)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
color() {
return
}
catch_errors() {
set -Eeuo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# This function handles errors
error_handler() {
local exit_code="$?"
local line_number="$1"
local command="$2"
local error_message="Failure in line $line_number: exit code $exit_code: while executing command $command"
echo -e "\n$error_message"
exit 100
}
verb_ip6() {
return
}
msg_info() {
local msg="$1"
echo -ne "${msg}\n"
}
msg_ok() {
local msg="$1"
echo -e "${msg}\n"
}
msg_error() {
local msg="$1"
echo -e "${msg}\n"
}
VALIDCT=$(pvesm status -content rootdir | awk 'NR>1')
if [ -z "$VALIDCT" ]; then
msg_error "Unable to detect a valid Container Storage location."
exit 1
fi
VALIDTMP=$(pvesm status -content vztmpl | awk 'NR>1')
if [ -z "$VALIDTMP" ]; then
msg_error "Unable to detect a valid Template Storage location."
exit 1
fi
function select_storage() {
local CLASS=$1
local CONTENT
local CONTENT_LABEL
case $CLASS in
container)
CONTENT='rootdir'
CONTENT_LABEL='Container'
;;
template)
CONTENT='vztmpl'
CONTENT_LABEL='Container template'
;;
*) false || {
msg_error "Invalid storage class."
exit 201
} ;;
esac
# This Queries all storage locations
local -a MENU
while read -r line; do
local TAG=$(echo $line | awk '{print $1}')
local TYPE=$(echo $line | awk '{printf "%-10s", $2}')
local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
local ITEM="Type: $TYPE Free: $FREE "
local OFFSET=2
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
local MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
fi
MENU+=("$TAG" "$ITEM" "OFF")
done < <(pvesm status -content $CONTENT | awk 'NR>1')
# Select storage location
if [ $((${#MENU[@]} / 3)) -eq 1 ]; then
printf ${MENU[0]}
else
msg_error "STORAGE ISSUES!"
exit 202
fi
}
[[ "${CTID:-}" ]] || {
msg_error "You need to set 'CTID' variable."
exit 203
}
[[ "${PCT_OSTYPE:-}" ]] || {
msg_error "You need to set 'PCT_OSTYPE' variable."
exit 204
}
# Test if ID is valid
[ "$CTID" -ge "100" ] || {
msg_error "ID cannot be less than 100."
exit 205
}
# Test if ID is in use
if pct status $CTID &>/dev/null; then
echo -e "ID '$CTID' is already in use."
unset CTID
msg_error "Cannot use ID that is already in use."
exit 206
fi
TEMPLATE_STORAGE=$(select_storage template) || exit
CONTAINER_STORAGE=$(select_storage container) || exit
pveam update >/dev/null
TEMPLATE_SEARCH=${PCT_OSTYPE}-${PCT_OSVERSION:-}
mapfile -t TEMPLATES < <(pveam available -section system | sed -n "s/.*\($TEMPLATE_SEARCH.*\)/\1/p" | sort -t - -k 2 -V)
[ ${#TEMPLATES[@]} -gt 0 ] || {
msg_error "Unable to find a template when searching for '$TEMPLATE_SEARCH'."
exit 207
}
TEMPLATE="${TEMPLATES[-1]}"
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE"; then
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null ||
{
msg_error "A problem occurred while downloading the LXC template."
exit 208
}
fi
grep -q "root:100000:65536" /etc/subuid || echo "root:100000:65536" >>/etc/subuid
grep -q "root:100000:65536" /etc/subgid || echo "root:100000:65536" >>/etc/subgid
PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}})
[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "$CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}")
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null ||
{
msg_error "A problem occurred while re-downloading the LXC template."
exit 208
}
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
msg_error "A problem occurred while trying to create container after re-downloading template."
exit 200
fi
fi

View File

@@ -1,93 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Michel Roegl-Brunner (michelroegl-brunner)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
color() {
return
}
catch_errors() {
set -Euo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
error_handler() {
local line_number="$1"
local command="$2"
local error_message="Failure in line $line_number while executing command '$command'"
echo -e "\n$error_message\n" >&2
exit 1
}
verb_ip6() {
STD="silent"
silent() {
"$@" >/dev/null 2>&1 || error_handler "${BASH_LINENO[0]}" "$*"
}
return
}
msg_info() {
local msg="$1"
echo -ne "${msg}\n"
}
msg_ok() {
local msg="$1"
echo -e "${msg}\n"
}
msg_error() {
local msg="$1"
echo -e "${msg}\n"
}
RETRY_NUM=10
RETRY_EVERY=3
setting_up_container() {
sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen
locale_line=$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print $1}' | head -n 1)
echo "LANG=${locale_line}" >/etc/default/locale
locale-gen >/dev/null
export LANG=${locale_line}
echo $tz >/etc/timezone
ln -sf /usr/share/zoneinfo/$tz /etc/localtime
for ((i = RETRY_NUM; i > 0; i--)); do
if [ "$(hostname -I)" != "" ]; then
break
fi
sleep $RETRY_EVERY
done
if [ "$(hostname -I)" = "" ]; then
echo 1>&2 -e "\nNo Network After $RETRY_NUM Tries"
echo -e "Check Network Settings"
exit 101
fi
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
systemctl disable -q --now systemd-networkd-wait-online.service
}
network_check() {
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi
set -e
}
update_os() {
export DEBIAN_FRONTEND=noninteractive
apt-get update >/dev/null 2>&1
apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade >/dev/null
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
}
motd_ssh() {
return
}
customize() {
return
}

View File

@@ -1,20 +0,0 @@
#!/bin/bash
FILE=$1
TODAY=$(date -u +"%Y-%m-%d")
if [[ -z "$FILE" ]]; then
echo "No file specified. Exiting."
exit 1
fi
if [[ ! -f "$FILE" ]]; then
echo "File $FILE not found. Exiting."
exit 1
fi
DATE_IN_JSON=$(jq -r '.date_created' "$FILE" 2>/dev/null || echo "")
if [[ "$DATE_IN_JSON" != "$TODAY" ]]; then
jq --arg date "$TODAY" '.date_created = $date' "$FILE" >tmp.json && mv tmp.json "$FILE"
fi

View File

@@ -1,23 +0,0 @@
#!/usr/bin/env bash
# Verzeichnis, das die JSON-Dateien enthält
json_dir="./json/*.json"
current_date=$(date +"%Y-%m-%d")
for json_file in $json_dir; do
if [[ -f "$json_file" ]]; then
current_json_date=$(jq -r '.date_created' "$json_file")
if [[ "$current_json_date" != "$current_date" ]]; then
echo "Updating $json_file with date $current_date"
jq --arg date "$current_date" '.date_created = $date' "$json_file" >temp.json && mv temp.json "$json_file"
git add "$json_file"
git commit -m "Update date_created to $current_date in $json_file"
else
echo "Date in $json_file is already up to date."
fi
fi
done
git push origin HEAD

View File

@@ -1,152 +0,0 @@
name: Update JSON Date
on:
push:
branches:
- main
paths:
- "frontend/public/json/**.json"
workflow_dispatch:
jobs:
update-app-files:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Generate a token for PR approval and merge
id: generate-token-merge
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.APP_ID_APPROVE_AND_MERGE }}
private-key: ${{ secrets.APP_KEY_APPROVE_AND_MERGE }}
- name: Generate dynamic branch name
id: timestamp
run: echo "BRANCH_NAME=pr-update-json-$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV
- name: Set up GH_TOKEN
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 2 # Ensure we have the last two commits
- name: Get Previous Commit
id: prev_commit
run: |
PREV_COMMIT=$(git rev-parse HEAD^)
echo "Previous commit: $PREV_COMMIT"
echo "prev_commit=$PREV_COMMIT" >> $GITHUB_ENV
- name: Get Newly Added JSON Files
id: new_json_files
run: |
git diff --name-only --diff-filter=A ${{ env.prev_commit }} HEAD | grep '^frontend/public/json/.*\.json$' > new_files.txt || true
echo "New files detected:"
cat new_files.txt || echo "No new files."
- name: Disable file mode changes
run: git config core.fileMode false
- name: Set up Git
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Change JSON Date
id: change-json-date
run: |
current_date=$(date +"%Y-%m-%d")
while IFS= read -r file; do
# Skip empty lines
[[ -z "$file" ]] && continue
if [[ -f "$file" ]]; then
echo "Processing $file..."
current_json_date=$(jq -r '.date_created // empty' "$file")
if [[ -z "$current_json_date" || "$current_json_date" != "$current_date" ]]; then
echo "Updating $file with date $current_date"
jq --arg date "$current_date" '.date_created = $date' "$file" > temp.json && mv temp.json "$file"
else
echo "Date in $file is already up to date."
fi
else
echo "Warning: File $file not found!"
fi
done < new_files.txt
rm new_files.txt
- name: Check if there are any changes
run: |
echo "Checking for changes..."
git add -A
git status
if git diff --cached --quiet; then
echo "No changes detected."
echo "changed=false" >> "$GITHUB_ENV"
else
echo "Changes detected:"
git diff --stat --cached
echo "changed=true" >> "$GITHUB_ENV"
fi
# Step 7: Commit and create PR if changes exist
- name: Commit and create PR if changes exist
if: env.changed == 'true'
run: |
git commit -m "Update date in json"
git checkout -b ${{ env.BRANCH_NAME }}
git push origin ${{ env.BRANCH_NAME }}
gh pr create --title "[core] update date in json" \
--body "This PR is auto-generated by a GitHub Action to update the date in json." \
--head ${{ env.BRANCH_NAME }} \
--base main \
--label "automated pr"
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
- name: Approve pull request
if: env.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER=$(gh pr list --head "${{ env.BRANCH_NAME }}" --json number --jq '.[].number')
if [ -n "$PR_NUMBER" ]; then
gh pr review $PR_NUMBER --approve
fi
- name: Approve pull request and merge
if: env.changed == 'true'
env:
GH_TOKEN: ${{ steps.generate-token-merge.outputs.token }}
run: |
git config --global user.name "github-actions-automege[bot]"
git config --global user.email "github-actions-automege[bot]@users.noreply.github.com"
PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number')
if [ -n "$PR_NUMBER" ]; then
gh pr review $PR_NUMBER --approve
gh pr merge $PR_NUMBER --squash --admin
fi
- name: No changes detected
if: env.changed == 'false'
run: echo "No changes to commit. Workflow completed successfully."

View File

@@ -1,236 +0,0 @@
name: Update GitHub Versions (New)
on:
workflow_dispatch:
schedule:
# Runs 4x daily: 00:00, 06:00, 12:00, 18:00 UTC
- cron: "0 0,6,12,18 * * *"
permissions:
contents: write
pull-requests: write
env:
VERSIONS_FILE: frontend/public/json/github-versions.json
BRANCH_NAME: automated/update-github-versions
AUTOMATED_PR_LABEL: "automated pr"
jobs:
update-github-versions:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Generate a token for PR approval and merge
id: generate-token-merge
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.APP_ID_APPROVE_AND_MERGE }}
private-key: ${{ secrets.APP_KEY_APPROVE_AND_MERGE }}
- name: Checkout Repository
uses: actions/checkout@v4
with:
ref: main
- name: Extract GitHub versions from install scripts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
echo "========================================="
echo " Extracting GitHub versions from scripts"
echo "========================================="
# Initialize versions array
versions_json="[]"
# Function to add a version entry
add_version() {
local slug="$1"
local repo="$2"
local version="$3"
local pinned="$4"
local date="$5"
versions_json=$(echo "$versions_json" | jq \
--arg slug "$slug" \
--arg repo "$repo" \
--arg version "$version" \
--argjson pinned "$pinned" \
--arg date "$date" \
'. += [{"slug": $slug, "repo": $repo, "version": $version, "pinned": $pinned, "date": $date}]')
}
# Get list of slugs from JSON files
echo ""
echo "=== Scanning JSON files for slugs ==="
for json_file in frontend/public/json/*.json; do
[[ ! -f "$json_file" ]] && continue
# Skip non-app JSON files
basename_file=$(basename "$json_file")
case "$basename_file" in
metadata.json|versions.json|github-versions.json|dependency-check.json|update-apps.json)
continue
;;
esac
# Extract slug from JSON
slug=$(jq -r '.slug // empty' "$json_file" 2>/dev/null)
[[ -z "$slug" ]] && continue
# Find corresponding script (install script or addon script)
install_script=""
if [[ -f "install/${slug}-install.sh" ]]; then
install_script="install/${slug}-install.sh"
elif [[ -f "tools/addon/${slug}.sh" ]]; then
install_script="tools/addon/${slug}.sh"
else
continue
fi
# Look for fetch_and_deploy_gh_release calls
# Pattern: fetch_and_deploy_gh_release "app" "owner/repo" ["mode"] ["version"]
while IFS= read -r line; do
# Skip commented lines
[[ "$line" =~ ^[[:space:]]*# ]] && continue
# Extract repo and version from fetch_and_deploy_gh_release
if [[ "$line" =~ fetch_and_deploy_gh_release[[:space:]]+\"[^\"]*\"[[:space:]]+\"([^\"]+)\"([[:space:]]+\"([^\"]+)\")?([[:space:]]+\"([^\"]+)\")? ]]; then
repo="${BASH_REMATCH[1]}"
mode="${BASH_REMATCH[3]:-tarball}"
pinned_version="${BASH_REMATCH[5]:-latest}"
# Check if version is pinned (not "latest" and not empty)
is_pinned=false
target_version=""
if [[ -n "$pinned_version" && "$pinned_version" != "latest" ]]; then
is_pinned=true
target_version="$pinned_version"
fi
# Fetch version from GitHub
if [[ "$is_pinned" == "true" ]]; then
# For pinned versions, verify it exists and get date
response=$(gh api "repos/${repo}/releases/tags/${target_version}" 2>/dev/null || echo '{}')
if echo "$response" | jq -e '.tag_name' > /dev/null 2>&1; then
version=$(echo "$response" | jq -r '.tag_name')
date=$(echo "$response" | jq -r '.published_at // empty')
add_version "$slug" "$repo" "$version" "true" "$date"
echo "[$slug] ✓ $version (pinned)"
else
echo "[$slug] ⚠ pinned version $target_version not found"
fi
else
# Fetch latest release
response=$(gh api "repos/${repo}/releases/latest" 2>/dev/null || echo '{}')
if echo "$response" | jq -e '.tag_name' > /dev/null 2>&1; then
version=$(echo "$response" | jq -r '.tag_name')
date=$(echo "$response" | jq -r '.published_at // empty')
add_version "$slug" "$repo" "$version" "false" "$date"
echo "[$slug] ✓ $version"
else
# Try tags as fallback
version=$(gh api "repos/${repo}/tags" --jq '.[0].name // empty' 2>/dev/null || echo "")
if [[ -n "$version" ]]; then
add_version "$slug" "$repo" "$version" "false" ""
echo "[$slug] ✓ $version (from tags)"
else
echo "[$slug] ⚠ no version found"
fi
fi
fi
break # Only first match per script
fi
done < <(grep 'fetch_and_deploy_gh_release' "$install_script" 2>/dev/null || true)
done
# Save versions file
echo "$versions_json" | jq --arg date "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'{generated: $date, versions: (. | sort_by(.slug))}' > "$VERSIONS_FILE"
total=$(echo "$versions_json" | jq 'length')
echo ""
echo "========================================="
echo " Total versions extracted: $total"
echo "========================================="
- name: Check for changes
id: check-changes
run: |
# Check if file is new (untracked) or has changes
if [[ ! -f "$VERSIONS_FILE" ]]; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "Versions file was not created"
elif ! git ls-files --error-unmatch "$VERSIONS_FILE" &>/dev/null; then
# File exists but is not tracked - it's new
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "New file created: $VERSIONS_FILE"
elif git diff --quiet "$VERSIONS_FILE" 2>/dev/null; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No changes detected"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Changes detected:"
git diff --stat "$VERSIONS_FILE" 2>/dev/null || true
fi
- name: Commit and push changes
if: steps.check-changes.outputs.changed == 'true'
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add "$VERSIONS_FILE"
git commit -m "chore: update github-versions.json"
git checkout -b $BRANCH_NAME || git checkout $BRANCH_NAME
git push origin $BRANCH_NAME --force
- name: Create pull request if not exists
if: steps.check-changes.outputs.changed == 'true'
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
PR_EXISTS=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number')
if [ -z "$PR_EXISTS" ]; then
gh pr create --title "[Github Action] Update github-versions.json" \
--body "This PR is auto-generated by a Github Action to update the github-versions.json file." \
--head $BRANCH_NAME \
--base main \
--label "$AUTOMATED_PR_LABEL"
fi
- name: Approve pull request
if: steps.check-changes.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number')
if [ -n "$PR_NUMBER" ]; then
gh pr review $PR_NUMBER --approve
fi
- name: Approve pull request and merge
if: steps.check-changes.outputs.changed == 'true'
env:
GH_TOKEN: ${{ steps.generate-token-merge.outputs.token }}
run: |
git config --global user.name "github-actions-automege[bot]"
git config --global user.email "github-actions-automege[bot]@users.noreply.github.com"
PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number')
if [ -n "$PR_NUMBER" ]; then
gh pr review $PR_NUMBER --approve
gh pr merge $PR_NUMBER --squash --admin
fi

7
.gitignore vendored
View File

@@ -24,13 +24,6 @@ venv/
env/
*.env
# Node.js dependencies (frontend folder was excluded, but keeping this rule for reference)
frontend/node_modules/
frontend/.svelte-kit/
frontend/.turbo/
frontend/.vite/
frontend/build/
# API and Backend specific exclusions
api/.env
api/__pycache__/

View File

@@ -426,10 +426,15 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- #### 🐞 Bug Fixes
- manyfold: fix incorrect port in upstream requests by forwarding original host [@anlopo](https://github.com/anlopo) ([#12812](https://github.com/community-scripts/ProxmoxVE/pull/12812))
- SparkyFitness: install pnpm dependencies from workspace root [@MickLesk](https://github.com/MickLesk) ([#12792](https://github.com/community-scripts/ProxmoxVE/pull/12792))
- n8n: add build-essential to update dependencies [@MickLesk](https://github.com/MickLesk) ([#12795](https://github.com/community-scripts/ProxmoxVE/pull/12795))
- Frigate openvino labelmap patch [@semtex1987](https://github.com/semtex1987) ([#12751](https://github.com/community-scripts/ProxmoxVE/pull/12751))
- #### 🔧 Refactor
- Pin Patchmon to 1.4.2 [@vhsdream](https://github.com/vhsdream) ([#12789](https://github.com/community-scripts/ProxmoxVE/pull/12789))
### 💾 Core
- #### 🐞 Bug Fixes
@@ -438,12 +443,18 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- #### ✨ New Features
- core: add mode=generated for unattended frontend installs [@MickLesk](https://github.com/MickLesk) ([#12807](https://github.com/community-scripts/ProxmoxVE/pull/12807))
- core: validate storage availability when loading defaults [@MickLesk](https://github.com/MickLesk) ([#12794](https://github.com/community-scripts/ProxmoxVE/pull/12794))
- #### 🔧 Refactor
- tools.func: support older NVIDIA driver versions with 2 segments (xxx.xxx) [@MickLesk](https://github.com/MickLesk) ([#12796](https://github.com/community-scripts/ProxmoxVE/pull/12796))
### 📂 Github
- Cleanup: remove old workflow files [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12818](https://github.com/community-scripts/ProxmoxVE/pull/12818))
- Cleanup: remove frontend, move JSONs to json/ top-level [@MickLesk](https://github.com/MickLesk) ([#12813](https://github.com/community-scripts/ProxmoxVE/pull/12813))
## 2026-03-11
### 🚀 Updated Scripts

View File

@@ -37,7 +37,7 @@ function update_script() {
fi
NODE_VERSION="24" setup_nodejs
if check_for_gh_release "PatchMon" "PatchMon/PatchMon"; then
if check_for_gh_release "PatchMon" "PatchMon/PatchMon" "v1.4.2"; then
msg_info "Stopping Service"
systemctl stop patchmon-server
msg_ok "Stopped Service"
@@ -47,7 +47,7 @@ function update_script() {
cp /opt/patchmon/frontend/.env /opt/frontend.env
msg_ok "Backup Created"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "PatchMon" "PatchMon/PatchMon" "tarball" "latest" "/opt/patchmon"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "PatchMon" "PatchMon/PatchMon" "tarball" "v1.4.2" "/opt/patchmon"
msg_info "Updating PatchMon"
VERSION=$(get_latest_github_release "PatchMon/PatchMon")

39
frontend/.gitignore vendored
View File

@@ -1,39 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# wrangler
.worker-next
.wrangler
# testing
/coverage
# next.js
/.next/
out
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# # local env files
# .env*.local
# .env
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

51
frontend/.vscode/settings.json generated vendored
View File

@@ -1,51 +0,0 @@
{
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off", "fixable": true },
{ "rule": "format/*", "severity": "off", "fixable": true },
{ "rule": "*-indent", "severity": "off", "fixable": true },
{ "rule": "*-spacing", "severity": "off", "fixable": true },
{ "rule": "*-spaces", "severity": "off", "fixable": true },
{ "rule": "*-order", "severity": "off", "fixable": true },
{ "rule": "*-dangle", "severity": "off", "fixable": true },
{ "rule": "*-newline", "severity": "off", "fixable": true },
{ "rule": "*quotes", "severity": "off", "fixable": true },
{ "rule": "*semi", "severity": "off", "fixable": true }
],
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"json5",
"jsonc",
"yaml",
"toml",
"xml",
"gql",
"graphql",
"astro",
"svelte",
"css",
"less",
"scss",
"pcss",
"postcss"
]
}

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024-Present Bram Suurd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,281 +0,0 @@
# Proxmox VE Helper-Scripts Frontend
> 🚀 **Modern frontend for the Community-Scripts Proxmox VE Helper-Scripts repository**
A comprehensive, user-friendly interface built with Next.js that provides access to 300+ automation scripts for Proxmox Virtual Environment management. This frontend serves as the official website for the Community-Scripts organization's Proxmox VE Helper-Scripts repository.
![Next.js](https://img.shields.io/badge/Next.js-15.2.4-black?style=flat-square&logo=next.js)
![React](https://img.shields.io/badge/React-19.0.0-blue?style=flat-square&logo=react)
![TypeScript](https://img.shields.io/badge/TypeScript-5.8.2-blue?style=flat-square&logo=typescript)
![Tailwind CSS](https://img.shields.io/badge/Tailwind-3.4.17-06B6D4?style=flat-square&logo=tailwindcss)
![License](https://img.shields.io/badge/License-MIT-green?style=flat-square)
## 🌟 Features
### Core Functionality
- **📜 Script Management**: Browse, search, and filter 300+ Proxmox VE scripts
- **📱 Responsive Design**: Mobile-first approach with modern UI/UX
- **🔍 Advanced Search**: Fuzzy search with category filtering
- **📊 Analytics Integration**: Built-in analytics for usage tracking
- **🌙 Dark/Light Mode**: Theme switching with system preference detection
- **⚡ Performance Optimized**: Static site generation for lightning-fast loading
### Technical Features
- **🎨 Modern UI Components**: Built with Radix UI and shadcn/ui
- **📈 Data Visualization**: Charts and metrics using Chart.js
- **🔄 State Management**: React Query for efficient data fetching
- **📝 Type Safety**: Full TypeScript implementation
- **🚀 Static Export**: Optimized for GitHub Pages deployment
## 🛠️ Tech Stack
### Frontend Framework
- **[Next.js 15.2.4](https://nextjs.org/)** - React framework with App Router
- **[React 19.0.0](https://react.dev/)** - Latest React with concurrent features
- **[TypeScript 5.8.2](https://www.typescriptlang.org/)** - Type-safe JavaScript
### Styling & UI
- **[Tailwind CSS 3.4.17](https://tailwindcss.com/)** - Utility-first CSS framework
- **[Radix UI](https://www.radix-ui.com/)** - Unstyled, accessible UI components
- **[shadcn/ui](https://ui.shadcn.com/)** - Re-usable components built on Radix UI
- **[Framer Motion](https://www.framer.com/motion/)** - Animation library
- **[Lucide React](https://lucide.dev/)** - Icon library
### Data & State Management
- **[TanStack Query 5.71.1](https://tanstack.com/query)** - Powerful data synchronization
- **[Zod 3.24.2](https://zod.dev/)** - TypeScript-first schema validation
- **[nuqs 2.4.1](https://nuqs.47ng.com/)** - Type-safe search params state manager
### Development Tools
- **[Vitest 3.1.1](https://vitest.dev/)** - Fast unit testing framework
- **[React Testing Library](https://testing-library.com/react)** - Simple testing utilities
- **[ESLint](https://eslint.org/)** - Code linting and formatting
- **[Prettier](https://prettier.io/)** - Code formatting
### Additional Libraries
- **[Chart.js](https://www.chartjs.org/)** - Data visualization
- **[Fuse.js](https://fusejs.io/)** - Fuzzy search
- **[date-fns](https://date-fns.org/)** - Date utility library
- **[Next Themes](https://github.com/pacocoursey/next-themes)** - Theme management
## 🚀 Getting Started
### Prerequisites
- **Node.js 18+** (recommend using the latest LTS version)
- **npm**, **yarn**, **pnpm**, or **bun** package manager
- **Git** for version control
### Installation
1. **Clone the repository**
```bash
git clone https://github.com/community-scripts/ProxmoxVE.git
cd ProxmoxVE/frontend
```
2. **Install dependencies**
```bash
# Using npm
npm install
# Using yarn
yarn install
# Using pnpm
pnpm install
# Using bun
bun install
```
3. **Start the development server**
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
4. **Open your browser**
Navigate to [http://localhost:3000](http://localhost:3000) to see the application running.
### Environment Configuration
The application uses the following environment variables:
- `BASE_PATH`: Set to "ProxmoxVE" for GitHub Pages deployment
- Analytics configuration is handled in `src/config/siteConfig.tsx`
## 🧪 Development
### Available Scripts
```bash
# Development
npm run dev # Start development server with Turbopack
npm run build # Build for production
npm run start # Start production server (after build)
# Code Quality
npm run lint # Run ESLint
npm run typecheck # Run TypeScript type checking
npm run format:write # Format code with Prettier
npm run format:check # Check code formatting
# Deployment
npm run deploy # Build and deploy to GitHub Pages
```
### Development Workflow
1. **Feature Development**
- Create a new branch for your feature
- Follow the established TypeScript and React patterns
- Use the existing component library (shadcn/ui)
- Ensure responsive design principles
2. **Code Standards**
- Follow TypeScript strict mode
- Use functional components with hooks
- Implement proper error boundaries
- Write descriptive variable and function names
- Use early returns for better readability
3. **Styling Guidelines**
- Use Tailwind CSS utility classes
- Follow mobile-first responsive design
- Implement dark/light mode considerations
- Use CSS variables from the design system
4. **Testing**
- Write unit tests for utility functions
- Test React components with React Testing Library
- Ensure accessibility standards are met
- Run tests before committing
### Component Development
The project uses a component-driven development approach:
```typescript
// Example component structure
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
interface ComponentProps {
title: string;
className?: string;
}
export const Component = ({ title, className }: ComponentProps) => {
return (
<div className={cn("default-classes", className)}>
<Button>{title}</Button>
</div>
);
};
```
### Configuration for Static Export
The application is configured for static export in `next.config.mjs`:
```javascript
const nextConfig = {
output: "export",
basePath: `/ProxmoxVE`,
images: {
unoptimized: true // Required for static export
}
};
```
## 🤝 Contributing
We welcome contributions from the community! Here's how you can help:
### Getting Started
1. **Fork the repository** on GitHub
2. **Clone your fork** locally
3. **Create a new branch** for your feature or bugfix
4. **Make your changes** following our coding standards
5. **Submit a pull request** with a clear description
### Contribution Guidelines
#### Code Style
- Follow the existing TypeScript and React patterns
- Use descriptive variable and function names
- Implement proper error handling
- Write self-documenting code with appropriate comments
#### Component Guidelines
- Use functional components with hooks
- Implement proper TypeScript types
- Follow accessibility best practices
- Ensure responsive design
- Use the existing design system components
#### Pull Request Process
1. Update documentation if needed
2. Update the README if you've added new features
3. Request review from maintainers
### Areas for Contribution
- **🐛 Bug fixes**: Report and fix issues
- **✨ New features**: Enhance functionality
- **📚 Documentation**: Improve guides and examples
- **🎨 UI/UX**: Improve design and user experience
- **♿ Accessibility**: Enhance accessibility features
- **🚀 Performance**: Optimize loading and runtime performance
## 📄 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## 🙏 Acknowledgments
- **[tteck](https://github.com/tteck)** - Original creator of the Proxmox VE Helper-Scripts
- **[Community-Scripts Organization](https://github.com/community-scripts)** - Maintaining and expanding the project
- **[Proxmox Community](https://forum.proxmox.com/)** - For continuous feedback and support
- **All Contributors** - Thank you for your valuable contributions!
## 📚 Additional Resources
- **[Proxmox VE Documentation](https://pve.proxmox.com/pve-docs/)**
- **[Community Scripts Repository](https://github.com/community-scripts/ProxmoxVE)**
- **[Discord Community](https://discord.gg/3AnUqsXnmK)**
- **[GitHub Discussions](https://github.com/community-scripts/ProxmoxVE/discussions)**
## 🔗 Links
- **🌐 Live Website**: [https://community-scripts.github.io/ProxmoxVE/](https://community-scripts.github.io/ProxmoxVE/)
- **💬 Discord Server**: [https://discord.gg/3AnUqsXnmK](https://discord.gg/3AnUqsXnmK)
- **📝 Change Log**: [https://github.com/community-scripts/ProxmoxVE/blob/main/CHANGELOG.md](https://github.com/community-scripts/ProxmoxVE/blob/main/CHANGELOG.md)
---
**Made with ❤️ by the Community-Scripts team and contributors**

2031
frontend/bun.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +0,0 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "@/styles/globals.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
},
"registries": {
"@animate-ui": "https://animate-ui.com/r/{name}.json"
}
}

View File

@@ -1,41 +0,0 @@
import antfu from "@antfu/eslint-config";
export default antfu(
{
type: "app",
typescript: true,
formatters: true,
next: true,
stylistic: {
indent: 2,
semi: true,
quotes: "double",
},
ignores: ["src/components/ui/**", "README.md", "public/json/**"],
},
{
rules: {
"ts/no-redeclare": "off",
"ts/consistent-type-definitions": ["error", "type"],
"no-console": ["warn"],
"antfu/no-top-level-await": ["off"],
"node/prefer-global/process": ["off"],
"node/no-process-env": ["error"],
"perfectionist/sort-imports": [
"error",
{
type: "line-length",
order: "desc",
},
],
"unicorn/filename-case": [
"error",
{
case: "kebabCase",
ignore: ["README.md"],
},
],
},
},
);

View File

@@ -1,29 +0,0 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config) => {
config.resolve.alias.canvas = false;
return config;
},
images: {
remotePatterns: [
{
protocol: "https",
hostname: "**",
},
],
},
env: {
BASE_PATH: "ProxmoxVE",
},
eslint: {
ignoreDuringBuilds: true,
},
output: "export",
basePath: `/ProxmoxVE`,
};
export default nextConfig;

87
frontend/package.json generated
View File

@@ -1,87 +0,0 @@
{
"name": "proxmox-helper-scripts-website",
"type": "module",
"version": "1.0.0",
"private": true,
"author": {
"name": "Bram Suurd",
"url": "https://github.com/community-scripts"
},
"license": "MIT",
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "eslint . --fix",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-tooltip": "^1.2.8",
"@tanstack/react-query": "^5.90.12",
"@types/react-syntax-highlighter": "^15.5.13",
"chart.js": "^4.5.1",
"chartjs-plugin-datalabels": "^2.2.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"framer-motion": "^12.23.26",
"fuse.js": "^7.1.0",
"lucide-react": "^0.561.0",
"mini-svg-data-uri": "^1.4.4",
"motion": "^12.23.26",
"next": "15.5.8",
"next-themes": "^0.4.6",
"nuqs": "^2.8.5",
"react": "19.2.3",
"react-chartjs-2": "^5.3.1",
"react-code-blocks": "^0.1.6",
"react-datepicker": "^9.0.0",
"react-day-picker": "^9.12.0",
"react-dom": "19.2.3",
"react-icons": "^5.5.0",
"react-syntax-highlighter": "^16.1.0",
"react-use-measure": "^2.1.7",
"recharts": "3.6.0",
"sharp": "^0.34.5",
"sonner": "^2.0.7",
"tailwind-merge": "^3.4.0",
"zod": "^4.2.1"
},
"devDependencies": {
"@antfu/eslint-config": "^6.7.1",
"@eslint-react/eslint-plugin": "^2.3.13",
"@next/eslint-plugin-next": "^15.5.8",
"@tanstack/eslint-plugin-query": "^5.91.2",
"@types/node": "^25.0.2",
"@types/react": "npm:types-react@19.0.0-rc.1",
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
"@typescript-eslint/eslint-plugin": "^8.50.0",
"@typescript-eslint/parser": "^8.50.0",
"@vitejs/plugin-react": "^5.1.2",
"eslint": "^9.39.2",
"eslint-config-next": "15.5.8",
"eslint-plugin-format": "^1.1.0",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.25",
"jsdom": "^27.3.0",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7",
"tailwindcss-animated": "^1.1.2",
"typescript": "^5.9.3"
}
}

View File

@@ -1,8 +0,0 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};
export default config;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

View File

@@ -1,44 +0,0 @@
{
"name": "2FAuth",
"slug": "2fauth",
"categories": [
6
],
"date_created": "2024-12-20",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://docs.2fauth.app/",
"website": "https://2fauth.app/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/2fauth.webp",
"config_path": "cat /opt/2fauth/.env",
"description": "2FAuth is a web based self-hosted alternative to One Time Passcode (OTP) generators like Google Authenticator, designed for both mobile and desktop. It aims to ease you perform your 2FA authentication steps whatever the device you handle, with a clean and suitable interface.",
"install_methods": [
{
"type": "default",
"script": "ct/2fauth.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 2,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Database credentials: `cat ~/2FAuth.creds`",
"type": "info"
},
{
"text": "The very first account created is automatically set up as an administrator account.",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Actual Budget",
"slug": "actualbudget",
"categories": [
23
],
"date_created": "2025-05-06",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 5006,
"documentation": "https://github.com/community-scripts/ProxmoxVE/discussions/807",
"website": "https://actualbudget.org/",
"config_path": "/opt/actualbudget-data/config.json",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/actual-budget.webp",
"description": "Actual Budget is a super fast and privacy-focused app for managing your finances. At its heart is the well proven and much loved Envelope Budgeting methodology.",
"install_methods": [
{
"type": "default",
"script": "ct/actualbudget.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,52 +0,0 @@
{
"name": "PVE LXC Tag",
"slug": "add-iptag",
"categories": [
1
],
"date_created": "2025-06-16",
"type": "pve",
"updateable": false,
"privileged": false,
"interface_port": null,
"documentation": null,
"website": null,
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/proxmox.webp",
"config_path": "/opt/iptag/iptag.conf",
"description": "This script automatically adds IP address as tags to LXC containers or VM's using a systemd service. The service also updates the tags if a LXC/VM IP address is changed.",
"install_methods": [
{
"type": "default",
"script": "tools/pve/add-iptag.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Execute within the Proxmox shell",
"type": "info"
},
{
"text": "Configuration: `nano /opt/iptag/iptag.conf`. iptag Service must be restarted after change. See here for full documentation: `https://github.com/community-scripts/ProxmoxVE/discussions/5790`",
"type": "info"
},
{
"text": "The Proxmox Node must contain ipcalc and net-tools. `apt-get install -y ipcalc net-tools`",
"type": "warning"
},
{
"text": "You can execute the ip tool manually with `iptag-run`",
"type": "info"
}
]
}

View File

@@ -1,48 +0,0 @@
{
"name": "NetBird",
"slug": "add-netbird-lxc",
"categories": [
1
],
"date_created": "2024-05-19",
"type": "addon",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://docs.netbird.io/",
"website": "https://netbird.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/netbird.webp",
"config_path": "",
"description": "NetBird combines a configuration-free peer-to-peer private network and a centralized access control system in a single platform, making it easy to create secure private networks for your organization or home.",
"install_methods": [
{
"type": "default",
"script": "tools/addon/add-netbird-lxc.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "After the script finishes, reboot the LXC then run `netbird up` in the LXC console",
"type": "info"
},
{
"text": "Execute within the Proxmox main shell",
"type": "info"
},
{
"text": "The script only works in Debian/Ubuntu, not in Alpine!",
"type": "warning"
}
]
}

View File

@@ -1,44 +0,0 @@
{
"name": "Tailscale",
"slug": "add-tailscale-lxc",
"categories": [
1
],
"date_created": "2024-05-02",
"type": "addon",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://tailscale.com/kb/1017/install",
"website": "https://tailscale.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/tailscale.webp",
"config_path": "",
"description": "Tailscale is a software-defined networking solution that enables secure communication between devices over the internet. It creates a virtual private network (VPN) that enables devices to communicate with each other as if they were on the same local network. Tailscale works even when the devices are separated by firewalls or subnets, and provides secure and encrypted communication between devices. With Tailscale, users can connect devices, servers, computers, and cloud instances to create a secure network, making it easier to manage and control access to resources. Tailscale is designed to be easy to set up and use, providing a streamlined solution for secure communication between devices over the internet.",
"install_methods": [
{
"type": "default",
"script": "tools/addon/add-tailscale-lxc.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "After the script finishes, reboot the LXC then run `tailscale up` in the LXC console",
"type": "info"
},
{
"text": "Execute within the Proxmox host shell",
"type": "info"
}
]
}

View File

@@ -1,51 +0,0 @@
{
"name": "AdGuard Home",
"slug": "adguard",
"categories": [
5
],
"date_created": "2024-04-28",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3000,
"documentation": "https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started",
"website": "https://adguard.com/en/adguard-home/overview.html",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/adguard-home.webp",
"config_path": "/opt/AdGuardHome/AdGuardHome.yaml",
"description": "AdGuard Home is an open-source, self-hosted network-wide ad blocker. It blocks advertisements, trackers, phishing and malware websites, and provides protection against online threats. AdGuard Home is a DNS-based solution, which means it blocks ads and malicious content at the network level, before it even reaches your device. It runs on your home network and can be easily configured and managed through a web-based interface. It provides detailed statistics and logs, allowing you to see which websites are being blocked, and why. AdGuard Home is designed to be fast, lightweight, and easy to use, making it an ideal solution for home users who want to block ads, protect their privacy, and improve the speed and security of their online experience.",
"install_methods": [
{
"type": "default",
"script": "ct/adguard.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 2,
"os": "debian",
"version": "13"
}
},
{
"type": "alpine",
"script": "ct/alpine-adguard.sh",
"resources": {
"cpu": 1,
"ram": 256,
"hdd": 1,
"os": "alpine",
"version": "3.23"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "AdGuard Home can only be updated via the user interface.",
"type": "info"
}
]
}

View File

@@ -1,59 +0,0 @@
{
"name": "AdGuardHome-Sync",
"slug": "adguardhome-sync",
"categories": [
5
],
"date_created": "2025-12-13",
"type": "addon",
"updateable": true,
"privileged": false,
"interface_port": 8080,
"documentation": "https://github.com/bakito/adguardhome-sync",
"website": "https://github.com/bakito/adguardhome-sync",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/adguardhome-sync.webp",
"config_path": "/opt/adguardhome-sync/adguardhome-sync.yaml",
"description": "Synchronize AdGuardHome config to one or multiple replica instances. Syncs General Settings, Filters, Rewrites, Services, Clients, DNS Config, DHCP Config and Theme.",
"install_methods": [
{
"type": "default",
"script": "tools/addon/adguardhome-sync.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
},
{
"type": "alpine",
"script": "tools/addon/adguardhome-sync.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Edit /opt/adguardhome-sync/adguardhome-sync.yaml to configure your AdGuardHome instances",
"type": "info"
},
{
"text": "Origin = Primary instance, Replicas = Instances to sync to",
"type": "info"
},
{
"text": "Update with: update_adguardhome-sync",
"type": "info"
}
]
}

View File

@@ -1,44 +0,0 @@
{
"name": "AdventureLog",
"slug": "adventurelog",
"categories": [
24
],
"date_created": "2024-10-26",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3000,
"documentation": "https://adventurelog.app/docs/intro/adventurelog_overview.html",
"website": "https://adventurelog.app/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/adventurelog.webp",
"config_path": "/opt/adventurelog/backend/server/.env",
"description": "Adventure Log is an app designed to track outdoor activities and personal achievements, allowing users to log their adventures with photos, notes, and location data. It focuses on enhancing outdoor experiences by preserving memories and sharing them with others.",
"install_methods": [
{
"type": "default",
"script": "ct/adventurelog.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 7,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "AdventureLog uses an initial local IP, if you change your LXC-IP, you need to change the IP here: `/opt/adventurelog/backend/server/.env` and here: `/opt/adventurelog/frontend/.env`",
"type": "warning"
},
{
"text": "Use `cat ~/adventurelog.creds` to see login credentials.",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "AgentDVR",
"slug": "agentdvr",
"categories": [
15
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": true,
"interface_port": 8090,
"documentation": "https://www.ispyconnect.com/docs/agent/about",
"website": "https://www.ispyconnect.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/agent-dvr.webp",
"config_path": "/opt/agentdvr/agent/Media/XML/config.json",
"description": "AgentDVR a new video surveillance solution for the Internet Of Things.",
"install_methods": [
{
"type": "default",
"script": "ct/agentdvr.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "ubuntu",
"version": "24.04"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "All Templates",
"slug": "all-templates",
"categories": [
1
],
"date_created": "2024-05-02",
"type": "addon",
"updateable": false,
"privileged": false,
"interface_port": null,
"documentation": null,
"website": null,
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/proxmox.webp",
"config_path": "",
"description": "A script designed to allow for the creation of one of the many free LXC templates. Great for creating system LXCs.\r\nThe script creates a `*.creds` file in the Proxmox root directory with the password of the newly created LXC.\r\nPlease take note that if you plan to use this script for creating TurnKey LXCs, you'll need to modify the hostname after creation.",
"install_methods": [
{
"type": "default",
"script": "tools/addon/all-templates.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Resource and network settings are adjustable post LXC creation.",
"type": "info"
}
]
}

View File

@@ -1,46 +0,0 @@
{
"name": "Alpine-IT-Tools",
"slug": "alpine-it-tools",
"categories": [
20
],
"date_created": "2025-01-30",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": null,
"website": "https://sharevb-it-tools.vercel.app/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/it-tools.webp",
"config_path": "",
"description": "IT-Tools is a web-based suite of utilities designed to streamline and simplify various IT tasks, providing tools for developers and system administrators to manage their workflows efficiently.",
"install_methods": [
{
"type": "default",
"script": "ct/alpine-it-tools.sh",
"resources": {
"cpu": 1,
"ram": 256,
"hdd": 1,
"os": "alpine",
"version": "3.23"
}
},
{
"type": "alpine",
"script": "ct/alpine-it-tools.sh",
"resources": {
"cpu": 1,
"ram": 256,
"hdd": 1,
"os": "alpine",
"version": "3.23"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Alpine",
"slug": "alpine",
"categories": [
2
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": null,
"website": "https://www.alpinelinux.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/alpine-linux.webp",
"config_path": "",
"description": "A security-oriented, lightweight Linux distribution based on musl and BusyBox.\r\nBy default, the root password is set to alpine. If you choose to use advanced settings, you will need to define a password, autologin is currently unavailable.",
"install_methods": [
{
"type": "default",
"script": "ct/alpine.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 1,
"os": "alpine",
"version": "3.23"
}
}
],
"default_credentials": {
"username": null,
"password": "alpine"
},
"notes": [
{
"text": "To Update Alpine: `apk -U upgrade`",
"type": "info"
}
]
}

View File

@@ -1,48 +0,0 @@
{
"name": "Ampache",
"slug": "ampache",
"categories": [
13
],
"date_created": "2026-01-30",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://github.com/ampache/ampache/wiki",
"website": "https://ampache.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/ampache.webp",
"config_path": "/opt/ampache/config/ampache.cfg.php",
"description": "Ampache is a web-based audio streaming application and file manager that allows you to access your music & videos from anywhere. It features a powerful music catalog, multiple user support, transcoding, streaming, and more.",
"install_methods": [
{
"type": "default",
"script": "ct/ampache.sh",
"resources": {
"cpu": 4,
"ram": 2048,
"hdd": 5,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Complete the web-based setup at http://IP/install.php",
"type": "info"
},
{
"text": "Database credentials are stored in `~/ampache.creds` - use only the MySQL username and password from this file",
"type": "info"
},
{
"text": "During installation, only check 'Create Tables' - leave 'Create Database' and 'Create Database User' unchecked",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Apache-Cassandra",
"slug": "apache-cassandra",
"categories": [
8
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://cassandra.apache.org/doc/latest/",
"website": "https://cassandra.apache.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/apache-cassandra.webp",
"config_path": "/etc/cassandra/cassandra.yaml",
"description": "Apache-Cassandra is an open source NoSQL distributed database trusted by thousands of companies for scalability and high availability without compromising performance.",
"install_methods": [
{
"type": "default",
"script": "ct/apache-cassandra.sh",
"resources": {
"cpu": 1,
"ram": 2048,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Apache CouchDB",
"slug": "apache-couchdb",
"categories": [
8
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 5984,
"documentation": "https://docs.couchdb.org/en/stable/",
"website": "https://couchdb.apache.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/couchdb.webp",
"config_path": "etc/default.ini",
"description": "Apache CouchDB Seamless multi-master sync, that scales from Big Data to Mobile, with an Intuitive HTTP/JSON API and designed for Reliability.",
"install_methods": [
{
"type": "default",
"script": "ct/apache-couchdb.sh",
"resources": {
"cpu": 2,
"ram": 4096,
"hdd": 10,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Login Credentials: `cat ~/couchdb.creds`",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Apache Guacamole",
"slug": "apache-guacamole",
"categories": [
0
],
"date_created": "2024-12-19",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8080,
"documentation": "https://guacamole.apache.org/doc/gug/",
"website": "https://guacamole.apache.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/apache-guacamole.webp",
"config_path": "/etc/guacamole/guacd.conf",
"description": "Apache Guacamole is a clientless remote desktop gateway. It supports standard protocols like VNC, RDP, and SSH.",
"install_methods": [
{
"type": "default",
"script": "ct/apache-guacamole.sh",
"resources": {
"cpu": 1,
"ram": 2048,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "guacadmin",
"password": "guacadmin"
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Apache Tika",
"slug": "apache-tika",
"categories": [
12
],
"date_created": "2025-02-05",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 9998,
"documentation": "https://cwiki.apache.org/confluence/display/tika",
"website": "https://tika.apache.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/apache-tika.webp",
"config_path": "/opt/apache-tika/tika-config.xml",
"description": "The Apache Tika™ toolkit detects and extracts metadata and text from over a thousand different file types (such as PPT, XLS, and PDF). All of these file types can be parsed through a single interface, making Tika useful for search engine indexing, content analysis, translation, and much more.",
"install_methods": [
{
"type": "default",
"script": "ct/apache-tika.sh",
"resources": {
"cpu": 1,
"ram": 2024,
"hdd": 10,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Configuration file is not created at install time. Example is at: `https://cwiki.apache.org/confluence/display/TIKA/TikaServer+in+Tika+2.x`",
"type": "info"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "Apache Tomcat",
"slug": "apache-tomcat",
"categories": [
10
],
"date_created": "2025-03-04",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8080,
"documentation": "https://cwiki.apache.org/confluence/display/TOMCAT",
"website": "https://tomcat.apache.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/apache-tomcat.webp",
"config_path": "",
"description": "Apache Tomcat is an open-source application server that runs Java Servlets and JavaServer Pages (JSP). It allows developers to deploy and manage Java web applications by handling HTTP requests and serving dynamic content. Tomcat is widely used for lightweight web applications and supports various Java EE features like WebSockets and JNDI.",
"install_methods": [
{
"type": "default",
"script": "ct/apache-tomcat.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 5,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "User can select which Adoptium JDK should be used for the selected Tomcat version (9, 10.1 or 11). ",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Apt-Cacher-NG",
"slug": "apt-cacher-ng",
"categories": [
4
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3142,
"documentation": "https://www.unix-ag.uni-kl.de/~bloch/acng/html/index.html",
"website": "https://www.unix-ag.uni-kl.de/~bloch/acng/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/linux.webp",
"config_path": "/etc/apt-cacher-ng/acng.conf",
"description": "Apt-Cacher-NG is a caching proxy. Specialized for package files from Linux distributors, primarily for Debian (and Debian based) distributions.",
"install_methods": [
{
"type": "default",
"script": "ct/apt-cacher-ng.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 10,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Arcane",
"slug": "arcane",
"categories": [
3
],
"date_created": "2026-02-24",
"type": "addon",
"updateable": true,
"privileged": false,
"interface_port": 3552,
"documentation": "https://getarcane.app/docs",
"website": "https://getarcane.app/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/arcane.webp",
"config_path": "/opt/arcane/.env",
"description": "Arcane is designed to be an easy and modern Docker management platform, built with everybody in mind. The goal of Arcane is to be built for and by the community to make sure nobody feels left out or behind with their specific features or processes. ",
"install_methods": [
{
"type": "default",
"script": "tools/addon/arcane.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": "arcane",
"password": "arcane-admin"
},
"notes": [
{
"text": "This is an addon script intended to be used on top of an existing Docker container.",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "ArchiveBox",
"slug": "archivebox",
"categories": [
12
],
"date_created": "2024-10-19",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8000,
"documentation": "https://github.com/ArchiveBox/ArchiveBox/wiki",
"website": "https://archivebox.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/archivebox.webp",
"config_path": "/opt/archivebox/data/ArchiveBox.conf",
"description": "ArchiveBox is an open source tool that lets organizations & individuals archive both public & private web content while retaining control over their data. It can be used to save copies of bookmarks, preserve evidence for legal cases, backup photos from FB/Insta/Flickr or media from YT/Soundcloud/etc., save research papers, and more...",
"install_methods": [
{
"type": "default",
"script": "ct/archivebox.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 8,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": "archivebox",
"password": "helper-scripts.com"
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Arch Linux",
"slug": "archlinux-vm",
"categories": [
2
],
"date_created": "2025-01-27",
"type": "vm",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://wiki.archlinux.org/title/Main_page",
"website": "https://archlinux.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/arch-linux.webp",
"config_path": "",
"description": "Arch Linux is a highly customizable, independent Linux distribution that gives users complete control over their system. Known for its rolling release model, Arch Linux is always up-to-date with the latest software. It's favored by experienced users who appreciate its minimalist approach, demanding a hands-on installation and configuration process. This level of control and flexibility makes it a popular choice for those who want to tailor their Linux system to their exact needs.",
"install_methods": [
{
"type": "default",
"script": "vm/archlinux-vm.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 4,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "doesnt work with lvm and lvmthin disks!",
"type": "warning"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Argus",
"slug": "argus",
"categories": [
11
],
"date_created": "2025-05-26",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8080,
"documentation": "https://release-argus.io/docs/overview/",
"website": "https://release-argus.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/argus.webp",
"config_path": "/opt/argus/config.yml",
"description": "Argus will query websites at a user defined interval for new software releases and then trigger Gotify/Slack/Other notification(s) and/or WebHook(s) when one has been found. For example, you could set it to monitor the Argus repo (release-argus/argus). This will query the GitHub API and track the tag_name variable. When this variable changes from what it was on a previous query, a GitHub-style WebHook could be sent that triggers something (like AWX) to update Argus on your server.",
"install_methods": [
{
"type": "default",
"script": "ct/argus.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 3,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Aria2",
"slug": "aria2",
"categories": [
11
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 6880,
"documentation": "https://aria2.github.io/manual/en/html/index.html",
"website": "https://aria2.github.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/aria2.webp",
"config_path": "/root/aria2.daemon",
"description": "Aria2 is a lightweight multi-protocol & multi-source, cross platform download utility operated in command-line. It supports HTTP/HTTPS, FTP, SFTP, BitTorrent and Metalink.",
"install_methods": [
{
"type": "default",
"script": "ct/aria2.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 8,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Within the LXC console, run `cat rpc.secret` to display the rpc-secret. Copy this token and paste it into the Aria2 RPC Secret Token box within the AriaNG Settings. Then, click the reload AriaNG button.",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Asterisk",
"slug": "asterisk",
"categories": [
0
],
"date_created": "2025-05-14",
"type": "ct",
"updateable": false,
"privileged": false,
"interface_port": null,
"documentation": "https://docs.asterisk.org/",
"config_path": "/etc/asterisk",
"website": "https://asterisk.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/asterisk.webp",
"description": "Asterisk is an open-source framework for building communications applications, most commonly used as a phone system (PBX). Developed by Digium (now part of Sangoma), it turns a standard computer into a powerful telephony server.",
"install_methods": [
{
"type": "default",
"script": "ct/asterisk.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 4,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,35 +0,0 @@
{
"name": "Audiobookshelf",
"slug": "audiobookshelf",
"categories": [
13
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 13378,
"documentation": "https://www.audiobookshelf.org/guides/",
"website": "https://www.audiobookshelf.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/audiobookshelf.webp",
"config_path": "/usr/share/audiobookshelf/config",
"description": "Audiobookshelf is a Self-hosted audiobook and podcast server.",
"install_methods": [
{
"type": "default",
"script": "ct/audiobookshelf.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 5,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Authelia",
"slug": "authelia",
"categories": [
6
],
"date_created": "2025-02-24",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 443,
"documentation": "https://www.authelia.com/integration/deployment/bare-metal/",
"website": "https://www.authelia.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/authelia.webp",
"config_path": "/etc/authelia/configuration.yml",
"description": "Authelia is an open-source authentication and authorization server and portal fulfilling the identity and access management (IAM) role of information security in providing multi-factor authentication and single sign-on (SSO) for your applications via a web portal. It acts as a companion for common reverse proxies.",
"install_methods": [
{
"type": "default",
"script": "ct/authelia.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 2,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "authelia",
"password": "authelia"
},
"notes": [
{
"text": "During installation, you will have to input your domain (ex. domain.com). Authelia will use auth.domain.com",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Autobrr",
"slug": "autobrr",
"categories": [
14
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 7474,
"documentation": "https://autobrr.com/configuration/autobrr",
"website": "https://autobrr.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/autobrr.webp",
"config_path": "/root/.config/autobrr/config.toml",
"description": "Autobrr is a torrent downloading tool that automates the process of downloading torrents. It is designed to be modern and user-friendly, providing users with a convenient and efficient way to download torrent files. With Autobrr, you can schedule and manage your torrent downloads, and have the ability to automatically download torrents based on certain conditions, such as time of day or availability of seeds. This can save you time and effort, allowing you to focus on other tasks while your torrents are being downloaded in the background.",
"install_methods": [
{
"type": "default",
"script": "ct/autobrr.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,35 +0,0 @@
{
"name": "Autocaliweb",
"slug": "autocaliweb",
"categories": [
13
],
"date_created": "2025-09-10",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8083,
"documentation": "https://codeberg.org/gelbphoenix/autocaliweb/wiki",
"config_path": "/etc/autocaliweb",
"website": "https://codeberg.org/gelbphoenix/autocaliweb",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/autocaliweb.webp",
"description": "A modern web management system for eBooks, eComics and PDFs",
"install_methods": [
{
"type": "default",
"script": "ct/autocaliweb.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 6,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "admin",
"password": "admin123"
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Baby Buddy",
"slug": "babybuddy",
"categories": [
23
],
"date_created": "2025-05-21",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://docs.baby-buddy.net/",
"website": "https://github.com/babybuddy/babybuddy",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/baby-buddy.webp",
"config_path": "/opt/babybuddy/babybuddy/settings/production.py",
"description": "Baby Buddy is an open-source web application designed to assist caregivers in tracking various aspects of a baby's daily routine, including sleep, feedings, diaper changes, tummy time, and more. By recording this data, caregivers can better understand and anticipate their baby's needs, reducing guesswork in daily care. The application offers a user-friendly dashboard for data entry and visualization, supports multiple users, and provides features like timers and reminders. Additionally, Baby Buddy can be integrated with platforms like Home Assistant and Grafana for enhanced functionality.",
"install_methods": [
{
"type": "default",
"script": "ct/babybuddy.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 5,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": "admin",
"password": "admin"
},
"notes": [
{
"text": "for private SSL setup visit: `https://github.com/babybuddy/babybuddy/blob/master/docs/setup/ssl.md`",
"type": "info"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "Backrest",
"slug": "backrest",
"categories": [
7
],
"date_created": "2025-05-27",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 9898,
"documentation": "https://garethgeorge.github.io/backrest/introduction/getting-started",
"website": "https://garethgeorge.github.io/backrest",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/backrest.webp",
"config_path": "/opt/backrest/config/config.json | /opt/backrest/.env",
"description": "Backrest is a web-accessible backup solution built on top of restic and providing a WebUI which wraps the restic CLI and makes it easy to create repos, browse snapshots, and restore files. Additionally, Backrest can run in the background and take an opinionated approach to scheduling snapshots and orchestrating repo health operations.",
"install_methods": [
{
"type": "default",
"script": "ct/backrest.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 8,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"type": "info",
"text": "`cat ~/.ssh/id_ed25519.pub` to view ssh public key. This key is used to authenticate with sftp targets. You can add this key on the sftp server."
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Baïkal",
"slug": "baikal",
"categories": [
0
],
"date_created": "2025-01-31",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://sabre.io/dav/",
"website": "https://sabre.io/baikal/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/baikal.webp",
"config_path": "/opt/baikal/config/baikal.yaml",
"description": "Baïkal is a lightweight CalDAV+CardDAV server. It offers an extensive web interface with easy management of users, address books and calendars.",
"install_methods": [
{
"type": "default",
"script": "ct/baikal.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "Admin",
"password": null
},
"notes": []
}

View File

@@ -1,35 +0,0 @@
{
"name": "Bar-Assistant",
"slug": "bar-assistant",
"categories": [
24
],
"date_created": "2025-07-14",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://docs.barassistant.app/",
"website": "https://barassistant.app/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/bar-assistant.webp",
"config_path": "/opt/bar-assistant",
"description": "Bar Assistant is all-in-one solution for managing your home bar. Compared to other recipe management software that usually tries to be more for general use, Bar Assistant is made specifically for managing cocktail recipes. This means that there are a lot of cocktail-oriented features, like ingredient substitutes, first-class ingredients, ABV calculations, unit switching and more..",
"install_methods": [
{
"type": "default",
"script": "ct/bar-assistant.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,35 +0,0 @@
{
"name": "Bazarr",
"slug": "bazarr",
"categories": [
14
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 6767,
"documentation": "https://wiki.bazarr.media/",
"website": "https://www.bazarr.media/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/bazarr.webp",
"config_path": "/opt/bazarr/data/config/config.yaml",
"description": "Bazarr is a companion application to Sonarr and Radarr that manages and downloads subtitles based on your requirements.",
"install_methods": [
{
"type": "default",
"script": "ct/bazarr.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,35 +0,0 @@
{
"name": "BentoPDF",
"slug": "bentopdf",
"categories": [
12
],
"date_created": "2025-10-30",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8080,
"documentation": "https://github.com/alam00000/bentopdf",
"website": "https://www.bentopdf.com",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/bentopdf.webp",
"config_path": "",
"description": "A privacy-first, 100% client-side PDF Toolkit. No signups/accounts, works in the browser, online or offline.",
"install_methods": [
{
"type": "default",
"script": "ct/bentopdf.sh",
"resources": {
"cpu": 2,
"ram": 4096,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,35 +0,0 @@
{
"name": "Beszel",
"slug": "beszel",
"categories": [
9
],
"date_created": "2025-01-20",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8090,
"documentation": "https://beszel.dev/guide/what-is-beszel",
"website": "https://beszel.dev/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/beszel.webp",
"config_path": "",
"description": "A lightweight server monitoring platform that provides Docker statistics, historical data, and alert functions\n ",
"install_methods": [
{
"type": "default",
"script": "ct/beszel.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 5,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,44 +0,0 @@
{
"name": "Bichon",
"slug": "bichon",
"categories": [
7
],
"date_created": "2026-02-07",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 15630,
"documentation": "https://github.com/rustmailer/bichon/wiki",
"config_path": "/opt/bichon/bichon.env",
"website": "https://github.com/rustmailer/bichon",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/bichon.webp",
"description": "Bichon is an open-source email archiving system that synchronizes emails from IMAP servers, indexes them for full-text search, and provides a REST API for programmatic access. Unlike email clients, Bichon is designed for archiving and searching rather than sending/receiving emails. It runs as a standalone server application that continuously synchronizes configured email accounts and maintains a searchable local archive.",
"install_methods": [
{
"type": "default",
"script": "ct/bichon.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 4,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "admin",
"password": "admin@bichon"
},
"notes": [
{
"text": "The Disk space initially allocated by the script is only a placeholder, as we can't know how much space you will ever need. You should increase it to match your workload.",
"type": "info"
},
{
"text": "Please copy your `BICHON_ENCRYPT_PASSWORD` from `/opt/bichon/bichon.env` to a safe place.",
"type": "warning"
}
]
}

View File

@@ -1,51 +0,0 @@
{
"name": "Bitmagnet",
"slug": "bitmagnet",
"categories": [
11
],
"date_created": "2025-05-15",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3333,
"documentation": "https://bitmagnet.io/setup.html",
"website": "https://bitmagnet.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/bitmagnet.webp",
"config_path": "`/opt/bitmagnet/config.yml` or `/opt/bitmagnet/.env`",
"description": "A self-hosted BitTorrent indexer, DHT crawler, content classifier and torrent search engine with web UI, GraphQL API and Servarr stack integration.",
"install_methods": [
{
"type": "default",
"script": "ct/bitmagnet.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "13"
}
},
{
"type": "alpine",
"script": "ct/alpine-bitmagnet.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 3,
"os": "alpine",
"version": "3.23"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "During installation you will be asked to enter your TMDB API key, if you wanna use it. Make sure you have it ready.",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Blocky",
"slug": "blocky",
"categories": [
5
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 4000,
"documentation": "https://0xerr0r.github.io/blocky/latest/configuration/",
"website": "https://0xerr0r.github.io/blocky/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/blocky.webp",
"config_path": "/opt/blocky/config.yml",
"description": "Blocky is a software tool designed for blocking unwanted ads and trackers on local networks. It functions as a DNS proxy and runs on the Go programming language. Blocky intercepts requests to advertisements and other unwanted content and blocks them before they reach the end user. This results in a cleaner, faster, and more secure online experience for users connected to the local network. Blocky is open-source, easy to configure and can be run on a variety of devices, making it a versatile solution for small to medium-sized local networks.",
"install_methods": [
{
"type": "default",
"script": "ct/blocky.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 2,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "BookLore",
"slug": "booklore",
"categories": [
13
],
"date_created": "2025-06-27",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 6060,
"documentation": "https://booklore-app.github.io/booklore-docs/docs/getting-started",
"website": "https://github.com/booklore-app/booklore",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/booklore.webp",
"config_path": "/opt/booklore_storage/.env",
"description": "BookLore is a self-hosted digital library for managing and reading books, offering a beautiful interface and support for metadata management. Built with a modern tech stack, it provides support for importing, organizing, and reading EPUBs and PDFs, while also managing cover images and book metadata.",
"install_methods": [
{
"type": "default",
"script": "ct/booklore.sh",
"resources": {
"cpu": 3,
"ram": 3072,
"hdd": 7,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Starting Booklore (Web UI) may take up to 2 minutes after a restart or fresh installation.",
"type": "info"
}
]
}

View File

@@ -1,44 +0,0 @@
{
"name": "BookStack",
"slug": "bookstack",
"categories": [
12
],
"date_created": "2024-11-05",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://www.bookstackapp.com/docs/",
"website": "https://www.bookstackapp.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/bookstack.webp",
"config_path": "/opt/bookstack/.env",
"description": "BookStack is a user-friendly documentation platform that offers a simple and intuitive experience. New users should be able to create content with basic word-processing skills. While the platform provides advanced features, they do not interfere with the core simplicity of the user experience.",
"install_methods": [
{
"type": "default",
"script": "ct/bookstack.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "admin@admin.com",
"password": "password"
},
"notes": [
{
"text": "Bookstack works only with static IP. If you change the IP of your LXC, you need to edit the .env file",
"type": "warning"
},
{
"text": "To see database credentials, type `cat ~/bookstack.creds` in LXC console",
"type": "info"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "BunkerWeb",
"slug": "bunkerweb",
"categories": [
6
],
"date_created": "2024-06-12",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://docs.bunkerweb.io/latest/",
"website": "https://www.bunkerweb.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/bunkerweb.webp",
"config_path": "/etc/bunkerweb/variables.env",
"description": "BunkerWeb is a security-focused web server that enhances web application protection. It guards against common web vulnerabilities like SQL injection, XSS, and CSRF. It features simple setup and configuration using a YAML file, customizable security rules, and provides detailed logs for traffic monitoring and threat detection.",
"install_methods": [
{
"type": "default",
"script": "ct/bunkerweb.sh",
"resources": {
"cpu": 2,
"ram": 8192,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.",
"type": "warning"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Byparr",
"slug": "byparr",
"categories": [
14
],
"date_created": "2026-01-21",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8191,
"documentation": "https://github.com/ThePhaseless/Byparr/blob/master/README.md",
"website": "https://github.com/ThePhaseless/Byparr",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/byparr.webp",
"config_path": "/etc/systemd/system/byparr.service",
"description": "Byparr is a proxy server to bypass Cloudflare and DDoS-GUARD protection.",
"install_methods": [
{
"type": "default",
"script": "ct/byparr.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,35 +0,0 @@
{
"name": "ByteStash",
"slug": "bytestash",
"categories": [
20
],
"date_created": "2025-02-27",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3000,
"documentation": "https://github.com/jordan-dalby/ByteStash/wiki",
"website": "https://github.com/jordan-dalby/ByteStash",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/bytestash.webp",
"config_path": "",
"description": "ByteStash is a self-hosted web application designed to store, organise, and manage your code snippets efficiently. With support for creating, editing, and filtering snippets, ByteStash helps you keep track of your code in one secure place.",
"install_methods": [
{
"type": "default",
"script": "ct/bytestash.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,59 +0,0 @@
{
"name": "Caddy",
"slug": "caddy",
"categories": [
21
],
"date_created": "2025-09-17",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://caddyserver.com/docs/",
"website": "https://caddyserver.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/caddy.webp",
"config_path": "/etc/caddy/Caddyfile",
"description": "Caddy is a powerful, extensible platform to serve your sites, services, and apps, written in Go.",
"install_methods": [
{
"type": "default",
"script": "ct/caddy.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 6,
"os": "debian",
"version": "13"
}
},
{
"type": "alpine",
"script": "ct/alpine-caddy.sh",
"resources": {
"cpu": 1,
"ram": 256,
"hdd": 3,
"os": "alpine",
"version": "3.23"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "xcaddy needs to be updated manually after a caddy update!",
"type": "warning"
},
{
"text": "if you need an internal module run: `caddy add-package PACKAGENAME`",
"type": "info"
},
{
"text": "if you need an external module run: `xcaddy build --with github.com/caddy-dns/cloudflare`",
"type": "info"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "Calibre-Web",
"slug": "calibre-web",
"categories": [
4
],
"date_created": "2026-02-20",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8083,
"documentation": "https://github.com/janeczku/calibre-web/wiki",
"website": "https://github.com/janeczku/calibre-web",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/calibre-web.webp",
"config_path": "/opt/calibre-web/app.db",
"description": "Web app for browsing, reading and downloading eBooks from a Calibre database. Provides an attractive interface with mobile support, user management, and eBook conversion capabilities.",
"install_methods": [
{
"type": "default",
"script": "ct/calibre-web.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "admin",
"password": "admin123"
},
"notes": [
{
"text": "Upload your Calibre library metadata.db during first setup wizard.",
"type": "info"
}
]
}

View File

@@ -1,44 +0,0 @@
{
"name": "CasaOS",
"slug": "casaos",
"categories": [
2
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://wiki.casaos.io/en/home",
"website": "https://www.casaos.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/casaos.webp",
"config_path": "",
"description": "CasaOS is a software that aims to make it easy for users to create a personal cloud system at home. It uses the Docker ecosystem to provide a simple, user-friendly experience for managing various applications and services.",
"install_methods": [
{
"type": "default",
"script": "ct/casaos.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "If the LXC is created Privileged, the script will automatically set up USB passthrough.",
"type": "warning"
},
{
"text": "WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.",
"type": "warning"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Change Detection",
"slug": "changedetection",
"categories": [
24
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 5000,
"documentation": "https://changedetection.io/tutorials",
"website": "https://changedetection.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/changedetection.webp",
"config_path": "/opt/changedetection/url-watches.json",
"description": "Change Detection is a service that allows you to monitor changes to web pages and receive notifications when changes occur. It can be used for a variety of purposes such as keeping track of online price changes, monitoring news websites for updates, or tracking changes to online forums.",
"install_methods": [
{
"type": "default",
"script": "ct/changedetection.sh",
"resources": {
"cpu": 4,
"ram": 4096,
"hdd": 10,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Channels DVR Server",
"slug": "channels",
"categories": [
13
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"privileged": true,
"interface_port": 8089,
"documentation": "https://getchannels.com/docs/getting-started/quick-start-guide/",
"website": "https://getchannels.com/dvr-server/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/channels-dvr.webp",
"config_path": "",
"description": "Channels DVR Server runs on your computer or NAS device at home. There's no cloud to worry about. Your tv shows and movies will always be available.",
"install_methods": [
{
"type": "default",
"script": "ct/channels.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 8,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.",
"type": "warning"
}
]
}

View File

@@ -1,48 +0,0 @@
{
"name": "Checkmate",
"slug": "checkmate",
"categories": [
9
],
"date_created": "2026-02-07",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 5173,
"documentation": "https://github.com/bluewave-labs/Checkmate#readme",
"website": "https://github.com/bluewave-labs/Checkmate",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/checkmate.webp",
"config_path": "/opt/checkmate/server/.env",
"description": "Checkmate is an open source uptime and infrastructure monitoring application that helps you track the availability and performance of your services.",
"install_methods": [
{
"type": "default",
"script": "ct/checkmate.sh",
"resources": {
"cpu": 2,
"ram": 4096,
"hdd": 10,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Create your admin account on first login via the web interface.",
"type": "info"
},
{
"text": "Server API runs on port 52345, Client UI on port 5173.",
"type": "info"
},
{
"text": "For PageSpeed monitoring, add a Google PageSpeed API key to the server .env file.",
"type": "info"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "Checkmk",
"slug": "checkmk",
"categories": [
9
],
"date_created": "2024-12-19",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://docs.checkmk.com/",
"website": "https://checkmk.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/checkmk.webp",
"config_path": "",
"description": "Checkmk is an IT monitoring software that tracks the health and performance of your systems, networks, servers, applications, and cloud services. It provides real-time insights, alerts for issues, and tools for troubleshooting, helping ensure smooth operations across your infrastructure.",
"install_methods": [
{
"type": "default",
"script": "ct/checkmk.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 4,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Login Credentials : `cat ~/checkmk.creds`",
"type": "info"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "PVE LXC Cleaner",
"slug": "clean-lxcs",
"categories": [
1
],
"date_created": "2024-04-29",
"type": "pve",
"updateable": false,
"privileged": false,
"interface_port": null,
"documentation": null,
"website": null,
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/linuxcontainers.webp",
"config_path": "",
"description": "This script provides options to delete logs and cache, and repopulate apt lists for Ubuntu and Debian systems.",
"install_methods": [
{
"type": "default",
"script": "tools/pve/clean-lxcs.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Execute within the Proxmox shell",
"type": "info"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "PVE Clean Orphaned LVM",
"slug": "clean-orphaned-lvm",
"categories": [
1
],
"date_created": "2025-01-29",
"type": "pve",
"updateable": false,
"privileged": false,
"interface_port": null,
"documentation": null,
"website": null,
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/proxmox.webp",
"config_path": "",
"description": "This script helps Proxmox users identify and remove orphaned LVM volumes that are no longer associated with any VM or LXC container. It scans all LVM volumes, detects unused ones, and provides an interactive prompt to delete them safely. System-critical volumes like root, swap, and data are excluded to prevent accidental deletion.",
"install_methods": [
{
"type": "default",
"script": "tools/pve/clean-orphaned-lvm.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Execute within the Proxmox shell",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Cleanuparr",
"slug": "cleanuparr",
"categories": [
14
],
"date_created": "2025-07-25",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 11011,
"documentation": "https://cleanuparr.github.io/Cleanuparr/docs/",
"website": "https://github.com/Cleanuparr/Cleanuparr",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/cleanuparr.webp",
"config_path": "/opt/cleanuparr/config",
"description": "Cleanuparr is a tool for automating the cleanup of unwanted or blocked files in Sonarr, Radarr, and supported download clients like qBittorrent, Transmission, and Deluge. It removes incomplete, blocked, or malicious downloads and can trigger replacement searches to ensure your media library stays complete and up-to-date.",
"install_methods": [
{
"type": "default",
"script": "ct/cleanuparr.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -1,44 +0,0 @@
{
"name": "Cloudflare-DDNS",
"slug": "cloudflare-ddns",
"categories": [
4
],
"date_created": "2025-05-22",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://github.com/favonia/cloudflare-ddns/blob/main/README.markdown",
"config_path": "/etc/systemd/system/cloudflare-ddns.service",
"website": "https://github.com/favonia/cloudflare-ddns",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/cloudflare.webp",
"description": "A feature-rich and robust Cloudflare DDNS updater with a small footprint. The program will detect your machines public IP addresses and update DNS records using the Cloudflare API",
"install_methods": [
{
"type": "default",
"script": "ct/cloudflare-ddns.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 2,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "To setup the updater you must have the Cloudflare Token and the domains, please read the Github documentation at `https://github.com/favonia/cloudflare-ddns?tab=readme-ov-file#-step-1-updating-the-compose-file` (only the expandable section)",
"type": "warning"
},
{
"text": "To update the configuration edit `/etc/systemd/system/cloudflare-ddns.service`. After edit please restart with `systemctl restart cloudflare-ddns`",
"type": "info"
}
]
}

View File

@@ -1,44 +0,0 @@
{
"name": "Cloudflared",
"slug": "cloudflared",
"categories": [
4
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/",
"website": "https://www.cloudflare.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/cloudflare.webp",
"config_path": "/usr/local/etc/cloudflared/config.yml",
"description": "Cloudflared is a command-line tool that allows you to securely access resources on the Cloudflare network, such as websites and APIs, from your local computer. It works by creating a secure tunnel between your computer and the Cloudflare network, allowing you to access resources as if they were on your local network.",
"install_methods": [
{
"type": "default",
"script": "ct/cloudflared.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 2,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "After install, run: cloudflared tunnel login && cloudflared tunnel create <NAME>",
"type": "info"
},
{
"text": "Or create tunnel via Cloudflare Zero Trust Dashboard",
"type": "info"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "Cloudreve",
"slug": "cloudreve",
"categories": [
12
],
"date_created": "2025-07-17",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 5212,
"documentation": "https://docs.cloudreve.org/en/",
"website": "https://cloudreve.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/cloudreve.webp",
"config_path": "/opt/cloudreve/data/conf.ini",
"description": "Cloudreve is an open-source, community-driven cloud storage system that provides file sharing, synchronization, and management features. It supports a wide range of storage backends and integrates with various notification and logging platforms.",
"install_methods": [
{
"type": "default",
"script": "ct/cloudreve.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 10,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "After Installation: Register your user -> Login -> Dashboard -> Accept Primary URL.",
"type": "warn"
}
]
}

View File

@@ -1,44 +0,0 @@
{
"name": "Cockpit",
"slug": "cockpit",
"categories": [
10
],
"date_created": "2024-10-20",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 9090,
"documentation": "https://cockpit-project.org/documentation.html",
"website": "https://cockpit-project.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/cockpit.webp",
"config_path": "/etc/cockpit/cockpit.conf",
"description": "Cockpit is a web-based graphical interface for managing Linux servers. It allows users to perform tasks like configuring networks, managing storage, and monitoring system performance directly through a web browser. It integrates with existing system tools, making it suitable for both beginners and experienced admins.",
"install_methods": [
{
"type": "default",
"script": "ct/cockpit.sh",
"resources": {
"cpu": 2,
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Set a root password if using autologin. This will be the Cockpit password. To set root password run `sudo passwd root`",
"type": "info"
},
{
"text": "If you plan on using 45Drives extension with NFS, you must setup LXC as privileged. Some features of 45Drives don't work on Debian 13, so Debian 12 must be used.",
"type": "warning"
}
]
}

View File

@@ -1,42 +0,0 @@
{
"name": "Coder Code Server",
"slug": "coder-code-server",
"categories": [
1,
20,
11
],
"date_created": "2024-05-02",
"type": "addon",
"updateable": false,
"privileged": false,
"interface_port": 8680,
"documentation": "https://coder.com/docs/code-server",
"website": "https://coder.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/coder.webp",
"config_path": "",
"description": "Coder Code Server is an open-source project that enables you to run Visual Studio Code (VS Code) on a remote machine, such as a desktop PC or virtual server. It serves a web-based version of VS Code that you can access from any browser via a URL, allowing remote development without needing an SSH connection. Unlike the official VS Code Server used by vscode.dev for Remote Tunnels, code-server is developed by Coder and operates independently, providing similar capabilities through a self-hosted solution.",
"install_methods": [
{
"type": "default",
"script": "tools/addon/coder-code-server.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Execute within an existing LXC Console",
"type": "warning"
}
]
}

View File

@@ -1,44 +0,0 @@
{
"name": "ComfyUI",
"slug": "comfyui",
"categories": [
20
],
"date_created": "2025-10-26",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt",
"interface_port": 8188,
"documentation": "https://github.com/comfyanonymous/ComfyUI",
"website": "https://www.comfy.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/comfyui.webp",
"description": "ComfyUI is a node-based interface and inference engine for generative AI. Users can combine various AI models and operations through nodes to achieve highly customizable and controllable content generation.",
"install_methods": [
{
"type": "default",
"script": "ct/comfyui.sh",
"resources": {
"cpu": 4,
"ram": 8192,
"hdd": 25,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Application takes long time to install. Please be patient!",
"type": "warning"
},
{
"text": "Please check that you have installed the drivers for your GPU.",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "CommaFeed",
"slug": "commafeed",
"categories": [
12
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8082,
"documentation": "https://athou.github.io/commafeed/documentation/",
"website": "https://www.commafeed.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/commafeed.webp",
"config_path": "",
"description": "CommaFeed is a Google Reader inspired self-hosted RSS reader.",
"install_methods": [
{
"type": "default",
"script": "ct/commafeed.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "admin",
"password": "admin"
},
"notes": []
}

View File

@@ -1,40 +0,0 @@
{
"name": "Configarr",
"slug": "configarr",
"categories": [
14
],
"date_created": "2025-05-21",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8989,
"documentation": "https://configarr.raydak.de/docs/intro",
"config_path": "/opt/configarr/config.yml",
"website": "https://configarr.raydak.de/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/configarr.webp",
"description": "Configarr is an open-source tool designed to simplify configuration and synchronization for Sonarr and Radarr (and other experimental). It integrates with TRaSH Guides to automate updates of custom formats, quality profiles, and other settings, while also supporting user-defined configurations.",
"install_methods": [
{
"type": "default",
"script": "ct/configarr.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 4,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "change secrets file /opt/configarr/secrets.yml",
"type": "info"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "ConvertX",
"slug": "convertx",
"categories": [
9
],
"date_created": "2025-06-26",
"type": "ct",
"updateable": true,
"privileged": false,
"config_path": "/opt/convertx/.env",
"interface_port": 3000,
"documentation": "https://github.com/C4illin/ConvertX",
"website": "https://github.com/C4illin/ConvertX",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/convertx.webp",
"description": "ConvertX is a self-hosted online file converter supporting over 1000 formats, including images, audio, video, documents, and more, powered by FFmpeg, GraphicsMagick, and other libraries.",
"install_methods": [
{
"type": "default",
"script": "ct/convertx.sh",
"resources": {
"cpu": 2,
"ram": 4096,
"hdd": 20,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Complete setup via the web interface at http://<container-ip>:3000. Create and secure the admin account immediately.",
"type": "info"
}
]
}

View File

@@ -1,56 +0,0 @@
{
"name": "Coolify",
"slug": "coolify",
"categories": [
3
],
"date_created": "2025-12-09",
"type": "addon",
"updateable": true,
"privileged": false,
"interface_port": 8000,
"documentation": "https://coolify.io/docs",
"website": "https://coolify.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/coolify.webp",
"config_path": "/data/coolify",
"description": "Coolify is an open-source & self-hostable alternative to Heroku, Netlify, and Vercel. It helps you manage your servers, applications, and databases on your own hardware with Docker. Deploy any application from Git repositories, Docker images, or use pre-built templates.",
"install_methods": [
{
"type": "default",
"script": "tools/addon/coolify.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "This is an addon script intended to be used on top of an existing Docker container.",
"type": "info"
},
{
"text": "Execute within an existing LXC console (Debian / Ubuntu / Alpine supported)",
"type": "info"
},
{
"text": "Initial setup will be done via the web interface on first access.",
"type": "info"
},
{
"text": "Coolify has built-in auto-updates. You can configure update frequency in Settings.",
"type": "info"
},
{
"text": "To update via CLI, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coolify.sh)",
"type": "info"
}
]
}

Some files were not shown because too many files have changed in this diff Show More