Compare commits

..

1 Commits

Author SHA1 Message Date
CanbiZ (MickLesk)
de0199107b refactor(forgejo,readeck): use fetch_and_deploy_codeberg_release function 2026-02-02 10:31:08 +01:00
50 changed files with 572 additions and 536 deletions

View File

@@ -776,37 +776,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
### 🆕 New Scripts ### 🆕 New Scripts
- rustypaste | Alpine-rustypaste ([#11457](https://github.com/community-scripts/ProxmoxVE/pull/11457))
- KitchenOwl ([#11453](https://github.com/community-scripts/ProxmoxVE/pull/11453)) - KitchenOwl ([#11453](https://github.com/community-scripts/ProxmoxVE/pull/11453))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Allow "downgrade" of libigdgmm12 [@vhsdream](https://github.com/vhsdream) ([#11478](https://github.com/community-scripts/ProxmoxVE/pull/11478))
- Disable NPM install and update due to OpenResty SHA-1 signature issues [@MickLesk](https://github.com/MickLesk) ([#11471](https://github.com/community-scripts/ProxmoxVE/pull/11471))
- #### ✨ New Features
- Refactor: Forgejo & readeck - migrate to codeberg functions [@MickLesk](https://github.com/MickLesk) ([#11460](https://github.com/community-scripts/ProxmoxVE/pull/11460))
- #### 💥 Breaking Changes
- [FIX] Scanopy: remove daemon build [@vhsdream](https://github.com/vhsdream) ([#11444](https://github.com/community-scripts/ProxmoxVE/pull/11444))
- #### 🔧 Refactor
- Refactor: Vaultwarden [@MickLesk](https://github.com/MickLesk) ([#11445](https://github.com/community-scripts/ProxmoxVE/pull/11445))
- various scripts: use ensure_dependencies instead of apt [@MickLesk](https://github.com/MickLesk) ([#11463](https://github.com/community-scripts/ProxmoxVE/pull/11463))
### 🌐 Website
- cleanup(frontend): remove unused /category-view route [@ls-root](https://github.com/ls-root) ([#11461](https://github.com/community-scripts/ProxmoxVE/pull/11461))
- #### ✨ New Features
- feat(frontend): preview tab [@ls-root](https://github.com/ls-root) ([#11475](https://github.com/community-scripts/ProxmoxVE/pull/11475))
## 2026-02-01 ## 2026-02-01
### 🚀 Updated Scripts ### 🚀 Updated Scripts

View File

@@ -27,7 +27,10 @@ function update_script() {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
ensure_dependencies memcached libmemcached-tools if ! command -v memcached >/dev/null 2>&1; then
$STD apt update
$STD apt install -y memcached libmemcached-tools
fi
if check_for_gh_release "adventurelog" "seanmorley15/adventurelog"; then if check_for_gh_release "adventurelog" "seanmorley15/adventurelog"; then
msg_info "Stopping Services" msg_info "Stopping Services"
systemctl stop adventurelog-backend systemctl stop adventurelog-backend

View File

@@ -1,51 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/orhun/rustypaste
APP="Alpine-RustyPaste"
var_tags="${var_tags:-alpine;pastebin;storage}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}"
var_disk="${var_disk:-4}"
var_os="${var_os:-alpine}"
var_version="${var_version:-3.23}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if ! apk info -e rustypaste >/dev/null 2>&1; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating RustyPaste"
$STD apk update
$STD apk upgrade rustypaste --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community
msg_ok "Updated RustyPaste"
msg_info "Restarting Services"
$STD rc-service rustypaste restart
msg_ok "Restarted Services"
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8000${CL}"

View File

@@ -31,7 +31,11 @@ function update_script() {
NODE_VERSION="22" NODE_MODULE="@postlight/parser@latest,single-file-cli@latest" setup_nodejs NODE_VERSION="22" NODE_MODULE="@postlight/parser@latest,single-file-cli@latest" setup_nodejs
PYTHON_VERSION="3.13" setup_uv PYTHON_VERSION="3.13" setup_uv
ensure_dependencies chromium if ! dpkg -l | grep -q "^ii chromium "; then
msg_info "Installing System Dependencies"
$STD apt-get install -y chromium
msg_ok "Installed System Dependencies"
fi
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop archivebox systemctl stop archivebox

View File

@@ -29,7 +29,12 @@ function update_script() {
exit exit
fi fi
ensure_dependencies libjpeg-dev if ! dpkg -s libjpeg-dev >/dev/null 2>&1; then
msg_info "Installing Dependencies"
$STD apt-get update
$STD apt-get install -y libjpeg-dev
msg_ok "Updated Dependencies"
fi
NODE_VERSION="24" setup_nodejs NODE_VERSION="24" setup_nodejs

View File

@@ -34,7 +34,12 @@ function update_script() {
systemctl stop commafeed systemctl stop commafeed
msg_ok "Stopped Service" msg_ok "Stopped Service"
ensure_dependencies rsync if ! [[ $(dpkg -s rsync 2>/dev/null) ]]; then
msg_info "Installing Dependencies"
$STD apt update
$STD apt install -y rsync
msg_ok "Installed Dependencies"
fi
if [ -d /opt/commafeed/data ] && [ "$(ls -A /opt/commafeed/data)" ]; then if [ -d /opt/commafeed/data ] && [ "$(ls -A /opt/commafeed/data)" ]; then
msg_info "Backing up existing data" msg_info "Backing up existing data"

View File

@@ -44,7 +44,10 @@ function update_script() {
NODE_VERSION="22" setup_nodejs NODE_VERSION="22" setup_nodejs
if check_for_gh_release "cronicle" "jhuckaby/Cronicle"; then if check_for_gh_release "cronicle" "jhuckaby/Cronicle"; then
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
ensure_dependencies git build-essential ca-certificates $STD apt install -y \
git \
build-essential \
ca-certificates
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
NODE_VERSION="22" setup_nodejs NODE_VERSION="22" setup_nodejs

View File

@@ -38,7 +38,9 @@ function update_script() {
systemctl reload nginx systemctl reload nginx
fi fi
ensure_dependencies vlc-bin vlc-plugin-base if ! dpkg -s vlc-bin vlc-plugin-base &>/dev/null; then
$STD apt update && $STD apt install -y vlc-bin vlc-plugin-base
fi
if check_for_gh_release "Dispatcharr" "Dispatcharr/Dispatcharr"; then if check_for_gh_release "Dispatcharr" "Dispatcharr/Dispatcharr"; then
msg_info "Stopping Services" msg_info "Stopping Services"

View File

@@ -43,7 +43,9 @@ function update_script() {
msg_error "Project directory does not exist: $PROJECT_DIR" msg_error "Project directory does not exist: $PROJECT_DIR"
exit exit
fi fi
ensure_dependencies git if ! command -v git &>/dev/null; then
$STD apt install -y git
fi
msg_info "Stopping service $SERVICE_NAME" msg_info "Stopping service $SERVICE_NAME"
systemctl stop "$SERVICE_NAME" systemctl stop "$SERVICE_NAME"

View File

@@ -45,7 +45,7 @@ function update_script() {
curl -fsSL "https://packages.graylog2.org/repo/packages/graylog-7.0-repository_latest.deb" -o "graylog-7.0-repository_latest.deb" curl -fsSL "https://packages.graylog2.org/repo/packages/graylog-7.0-repository_latest.deb" -o "graylog-7.0-repository_latest.deb"
$STD dpkg -i graylog-7.0-repository_latest.deb $STD dpkg -i graylog-7.0-repository_latest.deb
$STD apt update $STD apt update
ensure_dependencies graylog-server graylog-datanode $STD apt install -y graylog-server graylog-datanode
rm -f graylog-7.0-repository_latest.deb rm -f graylog-7.0-repository_latest.deb
msg_ok "Updated Graylog" msg_ok "Updated Graylog"
elif dpkg --compare-versions "$CURRENT_VERSION" ge "7.0"; then elif dpkg --compare-versions "$CURRENT_VERSION" ge "7.0"; then

View File

@@ -1,6 +0,0 @@
___ __ _ ____ __ ____ __
/ | / /___ (_)___ ___ / __ \__ _______/ /___ __/ __ \____ ______/ /____
/ /| | / / __ \/ / __ \/ _ \______/ /_/ / / / / ___/ __/ / / / /_/ / __ `/ ___/ __/ _ \
/ ___ |/ / /_/ / / / / / __/_____/ _, _/ /_/ (__ ) /_/ /_/ / ____/ /_/ (__ ) /_/ __/
/_/ |_/_/ .___/_/_/ /_/\___/ /_/ |_|\__,_/____/\__/\__, /_/ \__,_/____/\__/\___/
/_/ /____/

View File

@@ -1,6 +0,0 @@
__ __
_______ _______/ /___ ______ ____ ______/ /____
/ ___/ / / / ___/ __/ / / / __ \/ __ `/ ___/ __/ _ \
/ / / /_/ (__ ) /_/ /_/ / /_/ / /_/ (__ ) /_/ __/
/_/ \__,_/____/\__/\__, / .___/\__,_/____/\__/\___/
/____/_/

View File

@@ -30,7 +30,14 @@ function update_script() {
get_lxc_ip get_lxc_ip
NODE_VERSION="22" NODE_MODULE="pnpm@latest" setup_nodejs NODE_VERSION="22" NODE_MODULE="pnpm@latest" setup_nodejs
ensure_dependencies jq if ! command -v jq &>/dev/null; then
$STD msg_info "Installing jq..."
$STD apt-get update -qq &>/dev/null
$STD apt-get install -y jq &>/dev/null || {
msg_error "Failed to install jq"
exit
}
fi
if check_for_gh_release "homepage" "gethomepage/homepage"; then if check_for_gh_release "homepage" "gethomepage/homepage"; then
msg_info "Stopping service" msg_info "Stopping service"

View File

@@ -67,7 +67,8 @@ EOF
msg_info "Installing Mise" msg_info "Installing Mise"
curl -fSs https://mise.jdx.dev/gpg-key.pub | tee /etc/apt/keyrings/mise-archive-keyring.pub 1>/dev/null curl -fSs https://mise.jdx.dev/gpg-key.pub | tee /etc/apt/keyrings/mise-archive-keyring.pub 1>/dev/null
echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.pub arch=amd64] https://mise.jdx.dev/deb stable main" >/etc/apt/sources.list.d/mise.list echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.pub arch=amd64] https://mise.jdx.dev/deb stable main" >/etc/apt/sources.list.d/mise.list
ensure_dependencies mise $STD apt update
$STD apt install -y mise
msg_ok "Installed Mise" msg_ok "Installed Mise"
fi fi
@@ -88,7 +89,7 @@ EOF
curl -fsSLO "$url" curl -fsSLO "$url"
done done
$STD apt-mark unhold libigdgmm12 $STD apt-mark unhold libigdgmm12
$STD apt install -y --allow-downgrades ./libigdgmm12*.deb $STD apt install -y ./libigdgmm12*.deb
rm ./libigdgmm12*.deb rm ./libigdgmm12*.deb
$STD apt install -y ./*.deb $STD apt install -y ./*.deb
rm ./*.deb rm ./*.deb
@@ -133,7 +134,9 @@ EOF
$STD sudo -u postgres psql -d immich -c "REINDEX INDEX face_index;" $STD sudo -u postgres psql -d immich -c "REINDEX INDEX face_index;"
$STD sudo -u postgres psql -d immich -c "REINDEX INDEX clip_index;" $STD sudo -u postgres psql -d immich -c "REINDEX INDEX clip_index;"
fi fi
ensure_dependencies ccache if ! dpkg -l | grep -q ccache; then
$STD apt install -yqq ccache
fi
INSTALL_DIR="/opt/${APP}" INSTALL_DIR="/opt/${APP}"
UPLOAD_DIR="$(sed -n '/^IMMICH_MEDIA_LOCATION/s/[^=]*=//p' /opt/immich/.env)" UPLOAD_DIR="$(sed -n '/^IMMICH_MEDIA_LOCATION/s/[^=]*=//p' /opt/immich/.env)"
@@ -301,7 +304,10 @@ function compile_libjxl() {
function compile_libheif() { function compile_libheif() {
SOURCE=${SOURCE_DIR}/libheif SOURCE=${SOURCE_DIR}/libheif
ensure_dependencies libaom-dev if ! dpkg -l | grep -q libaom; then
$STD apt install -y libaom-dev
local update="required"
fi
: "${LIBHEIF_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libheif.json)}" : "${LIBHEIF_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libheif.json)}"
if [[ "${update:-}" ]] || [[ "$LIBHEIF_REVISION" != "$(grep 'libheif' ~/.immich_library_revisions | awk '{print $2}')" ]]; then if [[ "${update:-}" ]] || [[ "$LIBHEIF_REVISION" != "$(grep 'libheif' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
msg_info "Recompiling libheif" msg_info "Recompiling libheif"

View File

@@ -40,7 +40,9 @@ function update_script() {
fi fi
msg_info "Updating Jellyfin" msg_info "Updating Jellyfin"
ensure_dependencies libjemalloc2 if ! dpkg -s libjemalloc2 >/dev/null 2>&1; then
$STD apt install -y libjemalloc2
fi
if [[ ! -f /usr/lib/libjemalloc.so ]]; then if [[ ! -f /usr/lib/libjemalloc.so ]]; then
ln -sf /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 /usr/lib/libjemalloc.so ln -sf /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 /usr/lib/libjemalloc.so
fi fi

View File

@@ -38,7 +38,7 @@ function update_script() {
msg_ok "Updated yt-dlp" msg_ok "Updated yt-dlp"
msg_info "Prepare update" msg_info "Prepare update"
ensure_dependencies graphicsmagick ghostscript $STD apt install -y graphicsmagick ghostscript
if [[ -f /opt/karakeep/.env ]] && [[ ! -f /etc/karakeep/karakeep.env ]]; then if [[ -f /opt/karakeep/.env ]] && [[ ! -f /etc/karakeep/karakeep.env ]]; then
mkdir -p /etc/karakeep mkdir -p /etc/karakeep
mv /opt/karakeep/.env /etc/karakeep/karakeep.env mv /opt/karakeep/.env /etc/karakeep/karakeep.env

View File

@@ -23,7 +23,9 @@ function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
ensure_dependencies lsb-release if ! command -v lsb_release; then
apt install -y lsb-release
fi
if [[ ! -d /opt/kimai ]]; then if [[ ! -d /opt/kimai ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit

View File

@@ -27,8 +27,9 @@ function update_script() {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
if ! dpkg -l | grep -q temurin-21-jre; then
JAVA_VERSION="21" setup_java JAVA_VERSION="21" setup_java
fi
msg_info "Updating ${APP}" msg_info "Updating ${APP}"
$STD apt update $STD apt update
$STD apt -y upgrade $STD apt -y upgrade

View File

@@ -36,7 +36,12 @@ function update_script() {
NODE_VERSION="24" setup_nodejs NODE_VERSION="24" setup_nodejs
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "scanopy" "scanopy/scanopy" "tarball" "latest" "/opt/scanopy" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "scanopy" "scanopy/scanopy" "tarball" "latest" "/opt/scanopy"
ensure_dependencies pkg-config libssl-dev if ! dpkg -l | grep -q "pkg-config"; then
$STD apt install -y pkg-config
fi
if ! dpkg -l | grep -q "libssl-dev"; then
$STD apt install -y libssl-dev
fi
TOOLCHAIN="$(grep "channel" /opt/scanopy/backend/rust-toolchain.toml | awk -F\" '{print $2}')" TOOLCHAIN="$(grep "channel" /opt/scanopy/backend/rust-toolchain.toml | awk -F\" '{print $2}')"
RUST_TOOLCHAIN=$TOOLCHAIN setup_rust RUST_TOOLCHAIN=$TOOLCHAIN setup_rust

View File

@@ -28,12 +28,6 @@ function update_script() {
exit exit
fi fi
msg_error "This script is currently disabled due to an external issue with the OpenResty APT repository."
msg_error "The repository's GPG key uses SHA-1 signatures, which are no longer accepted by Debian as of February 1, 2026."
msg_error "The issue is tracked in openresty/openresty#1097"
msg_error "For more details, see: https://github.com/community-scripts/ProxmoxVE/issues/11406"
exit 1
if [[ $(grep -E '^VERSION_ID=' /etc/os-release) == *"12"* ]]; then if [[ $(grep -E '^VERSION_ID=' /etc/os-release) == *"12"* ]]; then
msg_error "Wrong Debian version detected!" msg_error "Wrong Debian version detected!"
msg_error "Please create a snapshot first. You must upgrade your LXC to Debian Trixie before updating. Visit: https://github.com/community-scripts/ProxmoxVE/discussions/7489" msg_error "Please create a snapshot first. You must upgrade your LXC to Debian Trixie before updating. Visit: https://github.com/community-scripts/ProxmoxVE/discussions/7489"

View File

@@ -28,8 +28,8 @@ function update_script() {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
ensure_dependencies python3-lxml
if ! [[ $(dpkg -s python3-lxml-html-clean 2>/dev/null) ]]; then if ! [[ $(dpkg -s python3-lxml-html-clean 2>/dev/null) ]]; then
$STD apt install python3-lxml
curl -fsSL "http://archive.ubuntu.com/ubuntu/pool/universe/l/lxml-html-clean/python3-lxml-html-clean_0.1.1-1_all.deb" -o /opt/python3-lxml-html-clean.deb curl -fsSL "http://archive.ubuntu.com/ubuntu/pool/universe/l/lxml-html-clean/python3-lxml-html-clean_0.1.1-1_all.deb" -o /opt/python3-lxml-html-clean.deb
$STD dpkg -i /opt/python3-lxml-html-clean.deb $STD dpkg -i /opt/python3-lxml-html-clean.deb
rm -f /opt/python3-lxml-html-clean.deb rm -f /opt/python3-lxml-html-clean.deb

View File

@@ -32,7 +32,11 @@ function update_script() {
if [[ ! -f /opt/Ollama_version.txt ]]; then if [[ ! -f /opt/Ollama_version.txt ]]; then
touch /opt/Ollama_version.txt touch /opt/Ollama_version.txt
fi fi
ensure_dependencies zstd if ! command -v zstd &>/dev/null; then
msg_info "Installing zstd"
$STD apt install -y zstd
msg_ok "Installed zstd"
fi
msg_info "Stopping Services" msg_info "Stopping Services"
systemctl stop ollama systemctl stop ollama
msg_ok "Services Stopped" msg_ok "Services Stopped"

View File

@@ -92,7 +92,11 @@ EOF
OLLAMA_VERSION=$(ollama -v | awk '{print $NF}') OLLAMA_VERSION=$(ollama -v | awk '{print $NF}')
RELEASE=$(curl -s https://api.github.com/repos/ollama/ollama/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4)}') RELEASE=$(curl -s https://api.github.com/repos/ollama/ollama/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4)}')
if [ "$OLLAMA_VERSION" != "$RELEASE" ]; then if [ "$OLLAMA_VERSION" != "$RELEASE" ]; then
ensure_dependencies zstd if ! command -v zstd &>/dev/null; then
msg_info "Installing zstd"
$STD apt install -y zstd
msg_ok "Installed zstd"
fi
msg_info "Ollama update available: v$OLLAMA_VERSION -> v$RELEASE" msg_info "Ollama update available: v$OLLAMA_VERSION -> v$RELEASE"
msg_info "Downloading Ollama v$RELEASE \n" msg_info "Downloading Ollama v$RELEASE \n"
curl -fS#LO https://github.com/ollama/ollama/releases/download/v${RELEASE}/ollama-linux-amd64.tar.zst curl -fS#LO https://github.com/ollama/ollama/releases/download/v${RELEASE}/ollama-linux-amd64.tar.zst

View File

@@ -69,7 +69,7 @@ function update_script() {
if [ "$VERSION_CODENAME" = "bookworm" ]; then if [ "$VERSION_CODENAME" = "bookworm" ]; then
setup_gs setup_gs
else else
ensure_dependencies ghostscript $STD apt install -y ghostscript
fi fi
msg_info "Updating Paperless-ngx" msg_info "Updating Paperless-ngx"
@@ -145,7 +145,7 @@ function update_script() {
setup_gs setup_gs
else else
msg_info "Installing Ghostscript" msg_info "Installing Ghostscript"
ensure_dependencies ghostscript $STD apt install -y ghostscript
msg_ok "Installed Ghostscript" msg_ok "Installed Ghostscript"
fi fi

View File

@@ -45,7 +45,7 @@ function update_script() {
LIBHEIF_URL=$(curl -fsSL "https://dl.photoprism.app/dist/libheif/" | grep -oP "libheif-bookworm-amd64-v[0-9\.]+\.tar\.gz" | sort -V | tail -n 1) LIBHEIF_URL=$(curl -fsSL "https://dl.photoprism.app/dist/libheif/" | grep -oP "libheif-bookworm-amd64-v[0-9\.]+\.tar\.gz" | sort -V | tail -n 1)
if [[ "${LIBHEIF_URL}" != "$(cat ~/.photoprism_libheif 2>/dev/null)" ]] || [[ ! -f ~/.photoprism_libheif ]]; then if [[ "${LIBHEIF_URL}" != "$(cat ~/.photoprism_libheif 2>/dev/null)" ]] || [[ ! -f ~/.photoprism_libheif ]]; then
msg_info "Updating PhotoPrism LibHeif" msg_info "Updating PhotoPrism LibHeif"
ensure_dependencies libvips42 $STD apt install -y libvips42
curl -fsSL "https://dl.photoprism.app/dist/libheif/$LIBHEIF_URL" -o /tmp/libheif.tar.gz curl -fsSL "https://dl.photoprism.app/dist/libheif/$LIBHEIF_URL" -o /tmp/libheif.tar.gz
tar -xzf /tmp/libheif.tar.gz -C /usr/local tar -xzf /tmp/libheif.tar.gz -C /usr/local
ldconfig ldconfig

View File

@@ -41,7 +41,7 @@ function update_script() {
cp -R /opt/rdtc-backup/appsettings.json /opt/rdtc/ cp -R /opt/rdtc-backup/appsettings.json /opt/rdtc/
if dpkg-query -W dotnet-sdk-8.0 >/dev/null 2>&1; then if dpkg-query -W dotnet-sdk-8.0 >/dev/null 2>&1; then
$STD apt remove --purge -y dotnet-sdk-8.0 $STD apt remove --purge -y dotnet-sdk-8.0
ensure_dependencies aspnetcore-runtime-9.0 $STD apt install -y aspnetcore-runtime-9.0
fi fi
rm -rf /opt/rdtc-backup rm -rf /opt/rdtc-backup

View File

@@ -1,69 +0,0 @@
#!/usr/bin/env bash
source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: GoldenSpringness
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/orhun/rustypaste
APP="rustypaste"
var_tags="${var_tags:-pastebin;storage}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-20}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /opt/rustypaste/rustypaste ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "rustypaste" "orhun/rustypaste"; then
msg_info "Stopping Services"
systemctl stop rustypaste
msg_ok "Stopped Services"
msg_info "Creating Backup"
tar -czf "/opt/rustypaste_backup_$(date +%F).tar.gz" /opt/rustypaste/upload 2>/dev/null || true
cp /opt/rustypaste/config.toml /tmp/rustypaste_config.toml.bak
msg_ok "Backup Created"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "rustypaste" "orhun/rustypaste" "prebuild" "latest" "/opt/rustypaste" "*x86_64-unknown-linux-gnu.tar.gz"
msg_info "Restoring Data"
mv /tmp/rustypaste_config.toml.bak /opt/rustypaste/config.toml
tar -xzf "/opt/rustypaste_backup_$(date +%F).tar.gz" -C /opt/rustypaste/upload 2>/dev/null || true
rm -rf /opt/rustypaste_backup_$(date +%F).tar.gz
msg_ok "Restored Data"
msg_info "Starting Services"
systemctl start rustypaste
msg_ok "Started Services"
msg_ok "Updated successfully!"
fi
if check_for_gh_release "rustypaste-cli" "orhun/rustypaste-cli"; then
fetch_and_deploy_gh_release "rustypaste-cli" "orhun/rustypaste-cli" "prebuild" "latest" "/usr/local/bin" "*x86_64-unknown-linux-gnu.tar.gz"
fi
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}rustypaste setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8000${CL}"

View File

@@ -42,7 +42,12 @@ function update_script() {
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "scanopy" "scanopy/scanopy" "tarball" "latest" "/opt/scanopy" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "scanopy" "scanopy/scanopy" "tarball" "latest" "/opt/scanopy"
ensure_dependencies pkg-config libssl-dev if ! dpkg -l | grep -q "pkg-config"; then
$STD apt install -y pkg-config
fi
if ! dpkg -l | grep -q "libssl-dev"; then
$STD apt install -y libssl-dev
fi
TOOLCHAIN="$(grep "channel" /opt/scanopy/backend/rust-toolchain.toml | awk -F\" '{print $2}')" TOOLCHAIN="$(grep "channel" /opt/scanopy/backend/rust-toolchain.toml | awk -F\" '{print $2}')"
RUST_TOOLCHAIN=$TOOLCHAIN setup_rust RUST_TOOLCHAIN=$TOOLCHAIN setup_rust
@@ -67,11 +72,15 @@ function update_script() {
mv ./target/release/server /usr/bin/scanopy-server mv ./target/release/server /usr/bin/scanopy-server
msg_ok "Built scanopy-server" msg_ok "Built scanopy-server"
msg_info "Building scanopy-daemon"
$STD cargo build --release --bin daemon
cp ./target/release/daemon /usr/bin/scanopy-daemon
msg_ok "Built scanopy-daemon"
msg_info "Starting services" msg_info "Starting services"
systemctl start scanopy-server systemctl start scanopy-server
[[ -f /etc/systemd/system/scanopy-daemon.service ]] && systemctl start scanopy-daemon [[ -f /etc/systemd/system/scanopy-daemon.service ]] && systemctl start scanopy-daemon
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
msg_warn "Update your integrated daemon via the UI"
fi fi
exit exit
} }

View File

@@ -30,7 +30,8 @@ function update_script() {
fi fi
msg_info "Updating ${APP}" msg_info "Updating ${APP}"
ensure_dependencies twingate-connector $STD apt update
$STD apt install -yq twingate-connector
$STD systemctl restart twingate-connector $STD systemctl restart twingate-connector
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit

View File

@@ -32,7 +32,7 @@ function update_script() {
msg_info "Updating ${APP}" msg_info "Updating ${APP}"
$STD apt update --allow-releaseinfo-change $STD apt update --allow-releaseinfo-change
ensure_dependencies unifi $STD apt install -y unifi
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
} }

View File

@@ -30,9 +30,12 @@ function update_script() {
NODE_VERSION="22" setup_nodejs NODE_VERSION="22" setup_nodejs
ensure_dependencies chromium if ! dpkg -s chromium >/dev/null 2>&1; then
if [[ ! -L /opt/uptime-kuma/chromium ]]; then msg_info "Installing Chromium"
$STD apt update
$STD apt install -y chromium
ln -s /usr/bin/chromium /opt/uptime-kuma/chromium ln -s /usr/bin/chromium /opt/uptime-kuma/chromium
msg_ok "Installed Chromium"
fi fi
if check_for_gh_release "uptime-kuma" "louislam/uptime-kuma"; then if check_for_gh_release "uptime-kuma" "louislam/uptime-kuma"; then

View File

@@ -28,8 +28,12 @@ function update_script() {
exit exit
fi fi
VAULT=$(get_latest_github_release "dani-garcia/vaultwarden") VAULT=$(curl -fsSL https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest |
WVRELEASE=$(get_latest_github_release "dani-garcia/bw_web_builds") grep "tag_name" |
awk '{print substr($2, 2, length($2)-3) }')
WVRELEASE=$(curl -fsSL https://api.github.com/repos/dani-garcia/bw_web_builds/releases/latest |
grep "tag_name" |
awk '{print substr($2, 2, length($2)-3) }')
UPD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SUPPORT" --radiolist --cancel-button Exit-Script "Spacebar = Select" 11 58 3 \ UPD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SUPPORT" --radiolist --cancel-button Exit-Script "Spacebar = Select" 11 58 3 \
"1" "VaultWarden $VAULT" ON \ "1" "VaultWarden $VAULT" ON \
@@ -38,68 +42,57 @@ function update_script() {
3>&1 1>&2 2>&3) 3>&1 1>&2 2>&3)
if [ "$UPD" == "1" ]; then if [ "$UPD" == "1" ]; then
if check_for_gh_release "vaultwarden" "dani-garcia/vaultwarden"; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop vaultwarden systemctl stop vaultwarden
msg_ok "Stopped Service" msg_ok "Stopped Service"
fetch_and_deploy_gh_release "vaultwarden" "dani-garcia/vaultwarden" "tarball" "latest" "/tmp/vaultwarden-src"
msg_info "Updating VaultWarden to $VAULT (Patience)" msg_info "Updating VaultWarden to $VAULT (Patience)"
cd /tmp/vaultwarden-src cd ~ && rm -rf vaultwarden
$STD git clone https://github.com/dani-garcia/vaultwarden
cd vaultwarden
$STD cargo build --features "sqlite,mysql,postgresql" --release $STD cargo build --features "sqlite,mysql,postgresql" --release
if [[ -f /usr/bin/vaultwarden ]]; then DIR=/usr/bin/vaultwarden
if [ -d "$DIR" ]; then
cp target/release/vaultwarden /usr/bin/ cp target/release/vaultwarden /usr/bin/
else else
cp target/release/vaultwarden /opt/vaultwarden/bin/ cp target/release/vaultwarden /opt/vaultwarden/bin/
fi fi
cd ~ && rm -rf /tmp/vaultwarden-src cd ~ && rm -rf vaultwarden
msg_ok "Updated VaultWarden to ${VAULT}" msg_ok "Updated VaultWarden"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start vaultwarden systemctl start vaultwarden
msg_ok "Started Service" msg_ok "Started Service"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else
msg_ok "VaultWarden is already up-to-date"
fi
exit exit
fi fi
if [ "$UPD" == "2" ]; then if [ "$UPD" == "2" ]; then
if check_for_gh_release "vaultwarden_webvault" "dani-garcia/bw_web_builds"; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop vaultwarden systemctl stop vaultwarden
msg_ok "Stopped Service" msg_ok "Stopped Service"
fetch_and_deploy_gh_release "vaultwarden_webvault" "dani-garcia/bw_web_builds" "prebuild" "latest" "/opt/vaultwarden" "bw_web_*.tar.gz"
msg_info "Updating Web-Vault to $WVRELEASE" msg_info "Updating Web-Vault to $WVRELEASE"
rm -rf /opt/vaultwarden/web-vault $STD curl -fsSLO https://github.com/dani-garcia/bw_web_builds/releases/download/"$WVRELEASE"/bw_web_"$WVRELEASE".tar.gz
chown -R root:root /opt/vaultwarden/web-vault/ $STD tar -zxf bw_web_"$WVRELEASE".tar.gz -C /opt/vaultwarden/
msg_ok "Updated Web-Vault to ${WVRELEASE}" rm bw_web_"$WVRELEASE".tar.gz
msg_ok "Updated Web-Vault"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start vaultwarden systemctl start vaultwarden
msg_ok "Started Service" msg_ok "Started Service"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else
msg_ok "Web-Vault is already up-to-date"
fi
exit exit
fi fi
if [ "$UPD" == "3" ]; then if [ "$UPD" == "3" ]; then
if NEWTOKEN=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "Set the ADMIN_TOKEN" 10 58 3>&1 1>&2 2>&3); then if NEWTOKEN=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "Set the ADMIN_TOKEN" 10 58 3>&1 1>&2 2>&3); then
if [[ -z "$NEWTOKEN" ]]; then exit; fi if [[ -z "$NEWTOKEN" ]]; then exit; fi
ensure_dependencies argon2 if ! command -v argon2 >/dev/null 2>&1; then $STD apt-get install -y argon2; fi
TOKEN=$(echo -n "${NEWTOKEN}" | argon2 "$(openssl rand -base64 32)" -t 2 -m 16 -p 4 -l 64 -e) TOKEN=$(echo -n "${NEWTOKEN}" | argon2 "$(openssl rand -base64 32)" -t 2 -m 16 -p 4 -l 64 -e)
sed -i "s|ADMIN_TOKEN=.*|ADMIN_TOKEN='${TOKEN}'|" /opt/vaultwarden/.env sed -i "s|ADMIN_TOKEN=.*|ADMIN_TOKEN='${TOKEN}'|" /opt/vaultwarden/.env
if [[ -f /opt/vaultwarden/data/config.json ]]; then if [[ -f /opt/vaultwarden/data/config.json ]]; then
sed -i "s|\"admin_token\":.*|\"admin_token\": \"${TOKEN}\"|" /opt/vaultwarden/data/config.json sed -i "s|\"admin_token\":.*|\"admin_token\": \"${TOKEN}\"|" /opt/vaultwarden/data/config.json
fi fi
systemctl restart vaultwarden systemctl restart vaultwarden
msg_ok "Admin token updated"
fi fi
exit exit
fi fi

View File

@@ -27,7 +27,10 @@ function update_script() {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
ensure_dependencies zstd if ! [[ $(dpkg -s zstd 2>/dev/null) ]]; then
$STD apt update
$STD apt install -y zstd
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/matze/wastebin/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') RELEASE=$(curl -fsSL https://api.github.com/repos/matze/wastebin/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
# Dirty-Fix 03/2025 for missing APP_version.txt on old installations, set to pre-latest release # Dirty-Fix 03/2025 for missing APP_version.txt on old installations, set to pre-latest release
msg_info "Running Migration" msg_info "Running Migration"

View File

@@ -1,5 +1,5 @@
{ {
"generated": "2026-02-02T12:12:15Z", "generated": "2026-02-02T06:25:10Z",
"versions": [ "versions": [
{ {
"slug": "2fauth", "slug": "2fauth",
@@ -543,9 +543,9 @@
{ {
"slug": "jackett", "slug": "jackett",
"repo": "Jackett/Jackett", "repo": "Jackett/Jackett",
"version": "v0.24.1012", "version": "v0.24.1008",
"pinned": false, "pinned": false,
"date": "2026-02-02T11:05:14Z" "date": "2026-02-02T05:55:21Z"
}, },
{ {
"slug": "joplin-server", "slug": "joplin-server",
@@ -596,13 +596,6 @@
"pinned": false, "pinned": false,
"date": "2026-01-31T18:10:59Z" "date": "2026-01-31T18:10:59Z"
}, },
{
"slug": "kitchenowl",
"repo": "TomBursch/kitchenowl",
"version": "v0.7.6",
"pinned": false,
"date": "2026-01-24T01:21:14Z"
},
{ {
"slug": "koel", "slug": "koel",
"repo": "koel/koel", "repo": "koel/koel",
@@ -1184,13 +1177,6 @@
"pinned": false, "pinned": false,
"date": "2026-01-12T05:38:30Z" "date": "2026-01-12T05:38:30Z"
}, },
{
"slug": "rustypaste",
"repo": "orhun/rustypaste",
"version": "v0.16.1",
"pinned": false,
"date": "2025-03-21T20:44:47Z"
},
{ {
"slug": "sabnzbd", "slug": "sabnzbd",
"repo": "sabnzbd/sabnzbd", "repo": "sabnzbd/sabnzbd",
@@ -1502,9 +1488,9 @@
{ {
"slug": "wanderer", "slug": "wanderer",
"repo": "meilisearch/meilisearch", "repo": "meilisearch/meilisearch",
"version": "v1.35.0", "version": "v1.34.3",
"pinned": false, "pinned": false,
"date": "2026-02-02T09:57:03Z" "date": "2026-01-28T17:52:24Z"
}, },
{ {
"slug": "warracker", "slug": "warracker",

View File

@@ -13,8 +13,6 @@
"website": "https://nginxproxymanager.com/", "website": "https://nginxproxymanager.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/nginx-proxy-manager.webp", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/nginx-proxy-manager.webp",
"config_path": "", "config_path": "",
"disable": true,
"disable_description": "This script is temporarily disabled due to an external issue with the OpenResty APT repository. The repository's GPG key uses SHA-1 signatures, which are no longer accepted by Debian as of February 1, 2026. This causes installation to fail with APT errors. The issue is tracked in openresty/openresty#1097. A workaround exists but requires manual configuration. The script will be re-enabled once OpenResty updates their repository signing key. For more details, see: https://github.com/community-scripts/ProxmoxVE/issues/11406",
"description": "Nginx Proxy Manager is a tool that provides a web-based interface to manage Nginx reverse proxies. It enables users to easily and securely expose their services to the internet by providing features such as HTTPS encryption, domain mapping, and access control. It eliminates the need for manual configuration of Nginx reverse proxies, making it easy for users to quickly and securely expose their services to the public.", "description": "Nginx Proxy Manager is a tool that provides a web-based interface to manage Nginx reverse proxies. It enables users to easily and securely expose their services to the internet by providing features such as HTTPS encryption, domain mapping, and access control. It eliminates the need for manual configuration of Nginx reverse proxies, making it easy for users to quickly and securely expose their services to the public.",
"install_methods": [ "install_methods": [
{ {

View File

@@ -1,51 +0,0 @@
{
"name": "RustyPaste",
"slug": "rustypaste",
"categories": [
11
],
"date_created": "2026-02-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8000,
"documentation": "https://github.com/orhun/rustypaste",
"config_path": "/opt/rustypaste/config.toml",
"website": "https://github.com/orhun/rustypaste",
"logo": "https://github.com/orhun/rustypaste/raw/master/img/rustypaste_logo.png",
"description": "Rustypaste is a minimal file upload/pastebin service.",
"install_methods": [
{
"type": "default",
"script": "ct/rustypaste.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 20,
"os": "Debian",
"version": "13"
}
},
{
"type": "alpine",
"script": "ct/alpine-rustypaste.sh",
"resources": {
"cpu": 1,
"ram": 256,
"hdd": 4,
"os": "Alpine",
"version": "3.23"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "When updating the script it will backup the whole project including all the uploaded files, make sure to extract it to a safe location or remove",
"type": "info"
}
]
}

View File

@@ -37,7 +37,7 @@
"type": "info" "type": "info"
}, },
{ {
"text": "The integrated daemon config is located at `/root/.config/daemon/`", "text": "The integrated daemon config is located at `/root/.config/daemon/config.json`",
"type": "info" "type": "info"
} }
] ]

View File

@@ -0,0 +1,320 @@
"use client";
import { ChevronLeft, ChevronRight } from "lucide-react";
import React, { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import type { Category } from "@/lib/types";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
const defaultLogo = "/default-logo.png"; // Fallback logo path
const MAX_DESCRIPTION_LENGTH = 100; // Set max length for description
const MAX_LOGOS = 5; // Max logos to display at once
function formattedBadge(type: string) {
switch (type) {
case "vm":
return <Badge className="text-blue-500/75 border-blue-500/75 badge">VM</Badge>;
case "ct":
return <Badge className="text-yellow-500/75 border-yellow-500/75 badge">LXC</Badge>;
case "pve":
return <Badge className="text-orange-500/75 border-orange-500/75 badge">PVE</Badge>;
case "addon":
return <Badge className="text-green-500/75 border-green-500/75 badge">ADDON</Badge>;
}
return null;
}
function CategoryView() {
const [categories, setCategories] = useState<Category[]>([]);
const [selectedCategoryIndex, setSelectedCategoryIndex] = useState<number | null>(null);
const [currentScripts, setCurrentScripts] = useState<any[]>([]);
const [logoIndices, setLogoIndices] = useState<{ [key: string]: number }>({});
const router = useRouter();
useEffect(() => {
const fetchCategories = async () => {
try {
// eslint-disable-next-line node/no-process-env
const basePath = process.env.NODE_ENV === "production" ? "/ProxmoxVE" : "";
const response = await fetch(`${basePath}/api/categories`);
if (!response.ok) {
throw new Error("Failed to fetch categories");
}
const data = await response.json();
setCategories(data);
// Initialize logo indices
const initialLogoIndices: { [key: string]: number } = {};
data.forEach((category: any) => {
initialLogoIndices[category.name] = 0;
});
setLogoIndices(initialLogoIndices);
}
catch (error) {
console.error("Error fetching categories:", error);
}
};
fetchCategories();
}, []);
const handleCategoryClick = (index: number) => {
setSelectedCategoryIndex(index);
setCurrentScripts(categories[index]?.scripts || []); // Update scripts for the selected category
};
const handleBackClick = () => {
setSelectedCategoryIndex(null);
setCurrentScripts([]); // Clear scripts when going back
};
const handleScriptClick = (scriptSlug: string) => {
// Include category context when navigating to scripts
const categoryName = selectedCategoryIndex !== null ? categories[selectedCategoryIndex]?.name : null;
const queryParams = new URLSearchParams({ id: scriptSlug });
if (categoryName) {
queryParams.append("category", categoryName);
}
router.push(`/scripts?${queryParams.toString()}`);
};
const navigateCategory = (direction: "prev" | "next") => {
if (selectedCategoryIndex !== null) {
const newIndex
= direction === "prev"
? (selectedCategoryIndex - 1 + categories.length) % categories.length
: (selectedCategoryIndex + 1) % categories.length;
setSelectedCategoryIndex(newIndex);
setCurrentScripts(categories[newIndex]?.scripts || []); // Update scripts for the new category
}
};
const switchLogos = (categoryName: string, direction: "prev" | "next") => {
setLogoIndices((prev) => {
const currentIndex = prev[categoryName] || 0;
const category = categories.find(cat => cat.name === categoryName);
if (!category || !category.scripts)
return prev;
const totalLogos = category.scripts.length;
const newIndex
= direction === "prev"
? (currentIndex - MAX_LOGOS + totalLogos) % totalLogos
: (currentIndex + MAX_LOGOS) % totalLogos;
return { ...prev, [categoryName]: newIndex };
});
};
const truncateDescription = (text: string) => {
return text.length > MAX_DESCRIPTION_LENGTH ? `${text.slice(0, MAX_DESCRIPTION_LENGTH)}...` : text;
};
const renderResources = (script: any) => {
const cpu = script.install_methods[0]?.resources.cpu;
const ram = script.install_methods[0]?.resources.ram;
const hdd = script.install_methods[0]?.resources.hdd;
const resourceParts = [];
if (cpu) {
resourceParts.push(
<span key="cpu">
<b>CPU:</b>
{" "}
{cpu}
vCPU
</span>,
);
}
if (ram) {
resourceParts.push(
<span key="ram">
<b>RAM:</b>
{" "}
{ram}
MB
</span>,
);
}
if (hdd) {
resourceParts.push(
<span key="hdd">
<b>HDD:</b>
{" "}
{hdd}
GB
</span>,
);
}
return resourceParts.length > 0
? (
<div className="text-sm text-gray-400">
{resourceParts.map((part, index) => (
<React.Fragment key={index}>
{part}
{index < resourceParts.length - 1 && " | "}
</React.Fragment>
))}
</div>
)
: null;
};
return (
<div className="p-6 mt-20">
{categories.length === 0 && (
<p className="text-center text-gray-500">No categories available. Please check the API endpoint.</p>
)}
{selectedCategoryIndex !== null
? (
<div>
{/* Header with Navigation */}
<div className="flex items-center justify-between mb-6">
<Button
variant="ghost"
onClick={() => navigateCategory("prev")}
className="p-2 transition-transform duration-300 hover:scale-105"
>
<ChevronLeft className="h-6 w-6" />
</Button>
<h2 className="text-3xl font-semibold transition-opacity duration-300 hover:opacity-90">
{categories[selectedCategoryIndex].name}
</h2>
<Button
variant="ghost"
onClick={() => navigateCategory("next")}
className="p-2 transition-transform duration-300 hover:scale-105"
>
<ChevronRight className="h-6 w-6" />
</Button>
</div>
{/* Scripts Grid */}
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
{currentScripts
.sort((a, b) => a.name.localeCompare(b.name))
.map(script => (
<Card
key={script.name}
className="p-4 cursor-pointer hover:shadow-md transition-shadow duration-300"
onClick={() => handleScriptClick(script.slug)}
>
<CardContent className="flex flex-col gap-4">
<h3 className="text-lg font-bold script-text text-center hover:text-blue-600 transition-colors duration-300">
{script.name}
</h3>
<img
src={script.logo || defaultLogo}
alt={script.name || "Script logo"}
className="h-12 w-12 object-contain mx-auto"
/>
<p className="text-sm text-gray-500 text-center">
<b>Created at:</b>
{" "}
{script.date_created || "No date available"}
</p>
<p
className="text-sm text-gray-700 hover:text-gray-900 text-center transition-colors duration-300"
title={script.description || "No description available."}
>
{truncateDescription(script.description || "No description available.")}
</p>
{renderResources(script)}
</CardContent>
</Card>
))}
</div>
{/* Back to Categories Button */}
<div className="mt-8 text-center">
<Button
variant="default"
onClick={handleBackClick}
className="px-6 py-2 text-white bg-blue-600 hover:bg-blue-700 rounded-lg shadow-md transition-transform duration-300 hover:scale-105"
>
Back to Categories
</Button>
</div>
</div>
)
: (
<div>
{/* Categories Grid */}
<div className="flex justify-between items-center mb-8">
<h1 className="text-3xl font-semibold mb-4">Categories</h1>
<p className="text-sm text-gray-500">
{categories.reduce((total, category) => total + (category.scripts?.length || 0), 0)}
{" "}
Total scripts
</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-8">
{categories.map((category, index) => (
<Card
key={category.name}
onClick={() => handleCategoryClick(index)}
className="cursor-pointer hover:shadow-lg flex flex-col items-center justify-center py-6 transition-shadow duration-300"
>
<CardContent className="flex flex-col items-center">
<h3 className="text-xl font-bold mb-4 category-title transition-colors duration-300 hover:text-blue-600">
{category.name}
</h3>
<div className="flex justify-center items-center gap-2 mb-4">
<Button
variant="ghost"
onClick={(e) => {
e.stopPropagation();
switchLogos(category.name, "prev");
}}
className="p-1 transition-transform duration-300 hover:scale-110"
>
<ChevronLeft className="h-4 w-4" />
</Button>
{category.scripts
&& category.scripts
.slice(logoIndices[category.name] || 0, (logoIndices[category.name] || 0) + MAX_LOGOS)
.map((script, i) => (
<div key={i} className="flex flex-col items-center">
<img
src={script.logo || defaultLogo}
alt={script.name || "Script logo"}
title={script.name}
className="h-8 w-8 object-contain cursor-pointer"
onClick={(e) => {
e.stopPropagation();
handleScriptClick(script.slug);
}}
/>
{formattedBadge(script.type)}
</div>
))}
<Button
variant="ghost"
onClick={(e) => {
e.stopPropagation();
switchLogos(category.name, "next");
}}
className="p-1 transition-transform duration-300 hover:scale-110"
>
<ChevronRight className="h-4 w-4" />
</Button>
</div>
<p className="text-sm text-gray-400 text-center">
{(category as any).description || "No description available."}
</p>
</CardContent>
</Card>
))}
</div>
</div>
)}
</div>
);
}
export default CategoryView;

View File

@@ -105,7 +105,7 @@ function Note({
const addNote = useCallback(() => { const addNote = useCallback(() => {
setScript({ setScript({
...script, ...script,
notes: [...script.notes, { text: "", type: "info" }], notes: [...script.notes, { text: "", type: "" }],
}); });
}, [script, setScript]); }, [script, setScript]);

View File

@@ -1,5 +1,4 @@
import { z } from "zod"; import { z } from "zod";
import { AlertColors } from "@/config/site-config";
export const InstallMethodSchema = z.object({ export const InstallMethodSchema = z.object({
type: z.enum(["default", "alpine"], { type: z.enum(["default", "alpine"], {
@@ -17,9 +16,7 @@ export const InstallMethodSchema = z.object({
const NoteSchema = z.object({ const NoteSchema = z.object({
text: z.string().min(1, "Note text cannot be empty"), text: z.string().min(1, "Note text cannot be empty"),
type: z.enum(Object.keys(AlertColors) as [keyof typeof AlertColors, ...(keyof typeof AlertColors)[]], { type: z.string().min(1, "Note type cannot be empty"),
message: `Type must be one of: ${Object.keys(AlertColors).join(", ")}`,
}),
}); });
export const ScriptSchema = z.object({ export const ScriptSchema = z.object({
@@ -45,7 +42,7 @@ export const ScriptSchema = z.object({
username: z.string().nullable(), username: z.string().nullable(),
password: z.string().nullable(), password: z.string().nullable(),
}), }),
notes: z.array(NoteSchema).optional().default([]), notes: z.array(NoteSchema),
}).refine((data) => { }).refine((data) => {
if (data.disable === true && !data.disable_description) { if (data.disable === true && !data.disable_description) {
return false; return false;

View File

@@ -18,7 +18,6 @@ import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { fetchCategories } from "@/lib/data"; import { fetchCategories } from "@/lib/data";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@@ -31,7 +30,6 @@ import Note from "./_components/note";
import { nord } from "react-syntax-highlighter/dist/esm/styles/hljs"; import { nord } from "react-syntax-highlighter/dist/esm/styles/hljs";
import SyntaxHighlighter from "react-syntax-highlighter"; import SyntaxHighlighter from "react-syntax-highlighter";
import { ScriptItem } from "../scripts/_components/script-item";
const initialScript: Script = { const initialScript: Script = {
name: "", name: "",
@@ -62,7 +60,6 @@ export default function JSONGenerator() {
const [isCopied, setIsCopied] = useState(false); const [isCopied, setIsCopied] = useState(false);
const [isValid, setIsValid] = useState(false); const [isValid, setIsValid] = useState(false);
const [categories, setCategories] = useState<Category[]>([]); const [categories, setCategories] = useState<Category[]>([]);
const [currentTab, setCurrentTab] = useState<"json" | "preview">("json");
const [zodErrors, setZodErrors] = useState<z.ZodError | null>(null); const [zodErrors, setZodErrors] = useState<z.ZodError | null>(null);
useEffect(() => { useEffect(() => {
@@ -71,13 +68,6 @@ export default function JSONGenerator() {
.catch((error) => console.error("Error fetching categories:", error)); .catch((error) => console.error("Error fetching categories:", error));
}, []); }, []);
useEffect(() => {
if (!isValid && currentTab === "preview") {
setCurrentTab("json");
toast.error("Switched to JSON tab due to invalid configuration.");
}
}, [isValid, currentTab]);
const updateScript = useCallback((key: keyof Script, value: Script[keyof Script]) => { const updateScript = useCallback((key: keyof Script, value: Script[keyof Script]) => {
setScript((prev) => { setScript((prev) => {
const updated = { ...prev, [key]: value }; const updated = { ...prev, [key]: value };
@@ -206,7 +196,7 @@ export default function JSONGenerator() {
<Input <Input
placeholder="Path to config file" placeholder="Path to config file"
value={script.config_path || ""} value={script.config_path || ""}
onChange={(e) => updateScript("config_path", e.target.value || "")} onChange={(e) => updateScript("config_path", e.target.value || null)}
/> />
</div> </div>
<div> <div>
@@ -333,17 +323,6 @@ export default function JSONGenerator() {
</form> </form>
</div> </div>
<div className="w-1/2 p-4 bg-background overflow-y-auto"> <div className="w-1/2 p-4 bg-background overflow-y-auto">
<Tabs
defaultValue="json"
className="w-full"
onValueChange={(value) => setCurrentTab(value as "json" | "preview")}
value={currentTab}
>
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="json">JSON</TabsTrigger>
<TabsTrigger disabled={!isValid} value="preview">Preview</TabsTrigger>
</TabsList>
<TabsContent value="json" className="h-full w-full">
{validationAlert} {validationAlert}
<div className="relative"> <div className="relative">
<div className="absolute right-2 top-2 flex gap-1"> <div className="absolute right-2 top-2 flex gap-1">
@@ -363,11 +342,6 @@ export default function JSONGenerator() {
{JSON.stringify(script, null, 2)} {JSON.stringify(script, null, 2)}
</SyntaxHighlighter> </SyntaxHighlighter>
</div> </div>
</TabsContent>
<TabsContent value="preview" className="h-full w-full">
<ScriptItem item={script} />
</TabsContent>
</Tabs>
</div> </div>
</div> </div>
); );

View File

@@ -4,8 +4,7 @@ import { X, HelpCircle } from "lucide-react";
import { Suspense } from "react"; import { Suspense } from "react";
import Image from "next/image"; import Image from "next/image";
import type { AppVersion } from "@/lib/types"; import type { AppVersion, Script } from "@/lib/types";
import type { Script } from "@/app/json-editor/_schemas/schemas";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
@@ -27,6 +26,7 @@ import Alerts from "./script-items/alerts";
type ScriptItemProps = { type ScriptItemProps = {
item: Script; item: Script;
setSelectedScript: (script: string | null) => void;
}; };
function ScriptHeader({ item }: { item: Script }) { function ScriptHeader({ item }: { item: Script }) {
@@ -135,10 +135,25 @@ function VersionInfo({ item }: { item: Script }) {
); );
} }
export function ScriptItem({ item }: ScriptItemProps) { export function ScriptItem({ item, setSelectedScript }: ScriptItemProps) {
const closeScript = () => {
window.history.pushState({}, document.title, window.location.pathname);
setSelectedScript(null);
};
return ( return (
<div className="w-full mx-auto"> <div className="w-full mx-auto">
<div className="flex w-full flex-col"> <div className="flex w-full flex-col">
<div className="mb-3 flex items-center justify-between">
<h2 className="text-2xl font-semibold tracking-tight text-foreground/90">Selected Script</h2>
<button
onClick={closeScript}
className="rounded-full p-2 text-muted-foreground hover:bg-card/50 transition-colors"
>
<X className="h-5 w-5" />
</button>
</div>
<div className="rounded-xl border border-border bg-accent/30 backdrop-blur-sm shadow-sm"> <div className="rounded-xl border border-border bg-accent/30 backdrop-blur-sm shadow-sm">
<div className="p-6 space-y-6"> <div className="p-6 space-y-6">
<Suspense fallback={<div className="animate-pulse h-32 bg-accent/20 rounded-xl" />}> <Suspense fallback={<div className="animate-pulse h-32 bg-accent/20 rounded-xl" />}>

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { Suspense, useEffect, useState } from "react"; import { Suspense, useEffect, useState } from "react";
import { Loader2, X } from "lucide-react"; import { Loader2 } from "lucide-react";
import { useQueryState } from "nuqs"; import { useQueryState } from "nuqs";
import type { Category, Script } from "@/lib/types"; import type { Category, Script } from "@/lib/types";
@@ -20,11 +20,6 @@ function ScriptContent() {
const [item, setItem] = useState<Script>(); const [item, setItem] = useState<Script>();
const [latestPage, setLatestPage] = useState(1); const [latestPage, setLatestPage] = useState(1);
const closeScript = () => {
window.history.pushState({}, document.title, window.location.pathname);
setSelectedScript(null);
};
useEffect(() => { useEffect(() => {
if (selectedScript && links.length > 0) { if (selectedScript && links.length > 0) {
const script = links const script = links
@@ -58,18 +53,7 @@ function ScriptContent() {
<div className="px-4 w-full sm:max-w-[calc(100%-350px-16px)]"> <div className="px-4 w-full sm:max-w-[calc(100%-350px-16px)]">
{selectedScript && item {selectedScript && item
? ( ? (
<div className="flex w-full flex-col"> <ScriptItem item={item} setSelectedScript={setSelectedScript} />
<div className="mb-3 flex items-center justify-between">
<h2 className="text-2xl font-semibold tracking-tight text-foreground/90">Selected Script</h2>
<button
onClick={closeScript}
className="rounded-full p-2 text-muted-foreground hover:bg-card/50 transition-colors"
>
<X className="h-5 w-5" />
</button>
</div>
<ScriptItem item={item} />
</div>
) )
: ( : (
<div className="flex w-full flex-col gap-5"> <div className="flex w-full flex-col gap-5">

View File

@@ -119,6 +119,7 @@ function MobileSidebar() {
<p className="text-sm font-medium">Last Viewed</p> <p className="text-sm font-medium">Last Viewed</p>
<ScriptItem <ScriptItem
item={lastViewedScript} item={lastViewedScript}
setSelectedScript={isOnScriptsPage ? setSelectedScript : setTempSelectedScript}
/> />
</div> </div>
) )
@@ -130,4 +131,3 @@ function MobileSidebar() {
} }
export default MobileSidebar; export default MobileSidebar;

View File

@@ -5,7 +5,7 @@ export type Script = {
slug: string; slug: string;
categories: number[]; categories: number[];
date_created: string; date_created: string;
type: "vm" | "ct" | "pve" | "addon" | "turnkey"; type: "vm" | "ct" | "pve" | "addon";
updateable: boolean; updateable: boolean;
privileged: boolean; privileged: boolean;
interface_port: number | null; interface_port: number | null;
@@ -31,10 +31,12 @@ export type Script = {
username: string | null; username: string | null;
password: string | null; password: string | null;
}; };
notes: { notes: [
{
text: string; text: string;
type: keyof typeof AlertColors; type: keyof typeof AlertColors;
}[]; },
];
}; };
export type Category = { export type Category = {

View File

@@ -1,55 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/orhun/rustypaste
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing RustyPaste"
$STD apk add --no-cache rustypaste --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community
msg_ok "Installed RustyPaste"
msg_info "Configuring RustyPaste"
mkdir -p /var/lib/rustypaste
sed -i 's|^address = ".*"|address = "0.0.0.0:8000"|' /etc/rustypaste/config.toml
msg_ok "Configured RustyPaste"
msg_info "Creating Service"
cat <<'EOF' >/etc/init.d/rustypaste
#!/sbin/openrc-run
name="rustypaste"
description="RustyPaste - A minimal file upload/pastebin service"
command="/usr/bin/rustypaste"
command_args=""
command_user="root"
command_background=true
pidfile="/run/${RC_SVCNAME}.pid"
directory="/var/lib/rustypaste"
depend() {
need net
after firewall
}
start_pre() {
export CONFIG=/etc/rustypaste/config.toml
checkpath --directory --owner root:root --mode 0755 /var/lib/rustypaste
}
EOF
chmod +x /etc/init.d/rustypaste
$STD rc-update add rustypaste default
$STD rc-service rustypaste start
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -1,43 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: GoldenSpringness | MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/orhun/rustypaste
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
fetch_and_deploy_gh_release "rustypaste" "orhun/rustypaste" "prebuild" "latest" "/opt/rustypaste" "*x86_64-unknown-linux-gnu.tar.gz"
fetch_and_deploy_gh_release "rustypaste-cli" "orhun/rustypaste-cli" "prebuild" "latest" "/usr/local/bin" "*x86_64-unknown-linux-gnu.tar.gz"
msg_info "Setting up RustyPaste"
cd /opt/rustypaste
sed -i 's|^address = ".*"|address = "0.0.0.0:8000"|' config.toml
msg_ok "Set up RustyPaste"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/rustypaste.service
[Unit]
Description=rustypaste Service
After=network.target
[Service]
WorkingDirectory=/opt/rustypaste
ExecStart=/opt/rustypaste/rustypaste
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now rustypaste
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -41,34 +41,39 @@ $STD cargo build --release --bin server
mv ./target/release/server /usr/bin/scanopy-server mv ./target/release/server /usr/bin/scanopy-server
msg_ok "Built scanopy-server" msg_ok "Built scanopy-server"
msg_info "Building scanopy-daemon"
$STD cargo build --release --bin daemon
cp ./target/release/daemon /usr/bin/scanopy-daemon
msg_ok "Built scanopy-daemon"
msg_info "Configuring server for first-run" msg_info "Configuring server for first-run"
cat <<EOF >/opt/scanopy/.env cat <<EOF >/opt/scanopy/.env
### - SERVER ### - SERVER
SCANOPY_DATABASE_URL=postgresql://$PG_DB_USER:$PG_DB_PASS@localhost:5432/$PG_DB_NAME scanopy_DATABASE_URL=postgresql://$PG_DB_USER:$PG_DB_PASS@localhost:5432/$PG_DB_NAME
SCANOPY_WEB_EXTERNAL_PATH="/opt/scanopy/ui/build" scanopy_WEB_EXTERNAL_PATH="/opt/scanopy/ui/build"
SCANOPY_PUBLIC_URL=http://${LOCAL_IP}:60072 scanopy_PUBLIC_URL=http://${LOCAL_IP}:60072
SCANOPY_SERVER_PORT=60072 scanopy_SERVER_PORT=60072
SCANOPY_LOG_LEVEL=info scanopy_LOG_LEVEL=info
SCANOPY_INTEGRATED_DAEMON_URL=http://127.0.0.1:60073 scanopy_INTEGRATED_DAEMON_URL=http://127.0.0.1:60073
## - uncomment to disable signups ## - uncomment to disable signups
# SCANOPY_DISABLE_REGISTRATION=true # scanopy_DISABLE_REGISTRATION=true
## - uncomment when using TLS ## - uncomment when using TLS
# SCANOPY_USE_SECURE_SESSION_COOKIES=true # scanopy_USE_SECURE_SESSION_COOKIES=true
## - see https://github.com/imbolc/axum-client-ip?tab=readme-ov-file#configurable-vs-specific-extractors ## - see https://github.com/imbolc/axum-client-ip?tab=readme-ov-file#configurable-vs-specific-extractors
## - before uncommenting the below ## - before uncommenting the below
# SCANOPY_CLIENT_IP_SOURCE= # scanopy_CLIENT_IP_SOURCE=
### - SMTP (password reset and notifications - optional) ### - SMTP (password reset and notifications - optional)
# SCANOPY_SMTP_RELAY=smtp.gmail.com:587 # scanopy_SMTP_RELAY=smtp.gmail.com:587
# SCANOPY_SMTP_USERNAME=your-email@gmail.com # scanopy_SMTP_USERNAME=your-email@gmail.com
# SCANOPY_SMTP_PASSWORD=your-app-password # scanopy_SMTP_PASSWORD=your-app-password
# SCANOPY_SMTP_EMAIL=scanopy@yourdomain.tld # scanopy_SMTP_EMAIL=scanopy@yourdomain.tld
### - INTEGRATED DAEMON ### - INTEGRATED DAEMON
SCANOPY_SERVER_URL=http://127.0.0.1:60072 scanopy_SERVER_URL=http://127.0.0.1:60072
SCANOPY_BIND_ADDRESS=0.0.0.0 scanopy_BIND_ADDRESS=0.0.0.0
SCANOPY_NAME="scanopy-daemon" scanopy_NAME="scanopy-daemon"
SCANOPY_HEARTBEAT_INTERVAL=30 scanopy_HEARTBEAT_INTERVAL=30
### - see https://github.com/scanopy/scanopy/blob/main/docs/CONFIGURATION.md for more options ### - see https://github.com/scanopy/scanopy/blob/main/docs/CONFIGURATION.md for more options
EOF EOF

View File

@@ -14,7 +14,7 @@ network_check
update_os update_os
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y git \
build-essential \ build-essential \
pkgconf \ pkgconf \
libssl-dev \ libssl-dev \
@@ -24,25 +24,34 @@ $STD apt install -y \
ssl-cert ssl-cert
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
setup_rust WEBVAULT=$(curl -fsSL https://api.github.com/repos/dani-garcia/bw_web_builds/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
fetch_and_deploy_gh_release "vaultwarden" "dani-garcia/vaultwarden" "tarball" "latest" "/tmp/vaultwarden-src" VAULT=$(curl -fsSL https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
msg_info "Building Vaultwarden (Patience)" msg_info "Installing Rust"
cd /tmp/vaultwarden-src curl -fsSL https://sh.rustup.rs -o rustup-init.sh
$STD bash rustup-init.sh -y --profile minimal
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >>~/.bashrc
export PATH="$HOME/.cargo/bin:$PATH"
rm rustup-init.sh
msg_ok "Installed Rust"
msg_info "Building Vaultwarden ${VAULT} (Patience)"
$STD git clone https://github.com/dani-garcia/vaultwarden
cd vaultwarden
$STD cargo build --features "sqlite,mysql,postgresql" --release $STD cargo build --features "sqlite,mysql,postgresql" --release
msg_ok "Built Vaultwarden" msg_ok "Built Vaultwarden ${VAULT}"
msg_info "Setting up Vaultwarden"
$STD addgroup --system vaultwarden $STD addgroup --system vaultwarden
$STD adduser --system --home /opt/vaultwarden --shell /usr/sbin/nologin --no-create-home --gecos 'vaultwarden' --ingroup vaultwarden --disabled-login --disabled-password vaultwarden $STD adduser --system --home /opt/vaultwarden --shell /usr/sbin/nologin --no-create-home --gecos 'vaultwarden' --ingroup vaultwarden --disabled-login --disabled-password vaultwarden
mkdir -p /opt/vaultwarden/{bin,data,web-vault} mkdir -p /opt/vaultwarden/bin
mkdir -p /opt/vaultwarden/data
cp target/release/vaultwarden /opt/vaultwarden/bin/ cp target/release/vaultwarden /opt/vaultwarden/bin/
cd ~ && rm -rf /tmp/vaultwarden-src
msg_ok "Set up Vaultwarden"
fetch_and_deploy_gh_release "vaultwarden_webvault" "dani-garcia/bw_web_builds" "prebuild" "latest" "/opt/vaultwarden/web-vault" "bw_web_*.tar.gz" msg_info "Downloading Web-Vault ${WEBVAULT}"
$STD curl -fsSLO https://github.com/dani-garcia/bw_web_builds/releases/download/"$WEBVAULT"/bw_web_"$WEBVAULT".tar.gz
$STD tar -xzf bw_web_"$WEBVAULT".tar.gz -C /opt/vaultwarden/
msg_ok "Downloaded Web-Vault ${WEBVAULT}"
msg_info "Configuring Vaultwarden"
cat <<EOF >/opt/vaultwarden/.env cat <<EOF >/opt/vaultwarden/.env
ADMIN_TOKEN='' ADMIN_TOKEN=''
ROCKET_ADDRESS=0.0.0.0 ROCKET_ADDRESS=0.0.0.0
@@ -52,23 +61,22 @@ DATABASE_MAX_CONNS=10
WEB_VAULT_FOLDER=/opt/vaultwarden/web-vault WEB_VAULT_FOLDER=/opt/vaultwarden/web-vault
WEB_VAULT_ENABLED=true WEB_VAULT_ENABLED=true
EOF EOF
mv /etc/ssl/certs/ssl-cert-snakeoil.pem /opt/vaultwarden/ mv /etc/ssl/certs/ssl-cert-snakeoil.pem /opt/vaultwarden/
mv /etc/ssl/private/ssl-cert-snakeoil.key /opt/vaultwarden/ mv /etc/ssl/private/ssl-cert-snakeoil.key /opt/vaultwarden/
msg_info "Creating Service"
chown -R vaultwarden:vaultwarden /opt/vaultwarden/ chown -R vaultwarden:vaultwarden /opt/vaultwarden/
chown root:root /opt/vaultwarden/bin/vaultwarden chown root:root /opt/vaultwarden/bin/vaultwarden
chmod +x /opt/vaultwarden/bin/vaultwarden chmod +x /opt/vaultwarden/bin/vaultwarden
chown -R root:root /opt/vaultwarden/web-vault/ chown -R root:root /opt/vaultwarden/web-vault/
chmod +r /opt/vaultwarden/.env chmod +r /opt/vaultwarden/.env
msg_ok "Configured Vaultwarden"
msg_info "Creating Service" service_path="/etc/systemd/system/vaultwarden.service"
cat <<EOF >/etc/systemd/system/vaultwarden.service echo "[Unit]
[Unit]
Description=Bitwarden Server (Powered by Vaultwarden) Description=Bitwarden Server (Powered by Vaultwarden)
Documentation=https://github.com/dani-garcia/vaultwarden Documentation=https://github.com/dani-garcia/vaultwarden
After=network.target After=network.target
[Service] [Service]
User=vaultwarden User=vaultwarden
Group=vaultwarden Group=vaultwarden
@@ -91,11 +99,10 @@ LockPersonality=yes
WorkingDirectory=/opt/vaultwarden WorkingDirectory=/opt/vaultwarden
ReadWriteDirectories=/opt/vaultwarden/data ReadWriteDirectories=/opt/vaultwarden/data
AmbientCapabilities=CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target" >$service_path
EOF systemctl daemon-reload
systemctl enable -q --now vaultwarden $STD systemctl enable --now vaultwarden
msg_ok "Created Service" msg_ok "Created Service"
motd_ssh motd_ssh

View File

@@ -1890,7 +1890,7 @@ function fetch_and_deploy_codeberg_release() {
local app="$1" local app="$1"
local repo="$2" local repo="$2"
local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile | tag local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile | tag
local version="${var_appversion:-${4:-latest}}" local version="${4:-latest}"
local target="${5:-/opt/$app}" local target="${5:-/opt/$app}"
local asset_pattern="${6:-}" local asset_pattern="${6:-}"
@@ -2322,7 +2322,7 @@ function fetch_and_deploy_gh_release() {
local app="$1" local app="$1"
local repo="$2" local repo="$2"
local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile
local version="${var_appversion:-${4:-latest}}" local version="${4:-latest}"
local target="${5:-/opt/$app}" local target="${5:-/opt/$app}"
local asset_pattern="${6:-}" local asset_pattern="${6:-}"