diff --git a/ct/grist.sh b/ct/grist.sh new file mode 100644 index 00000000..75b098bf --- /dev/null +++ b/ct/grist.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: cfurrow | Co-Author: Slaviša Arežina (tremor021) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/gristlabs/grist-core + +APP="Grist" +var_tags="${var_tags:-database;spreadsheet}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-3072}" +var_disk="${var_disk:-6}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-no}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/grist ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + ensure_dependencies git + + if check_for_gh_release "grist" "gristlabs/grist-core"; then + msg_info "Stopping Service" + systemctl stop grist + msg_ok "Stopped Service" + + msg_info "Creating backup" + rm -rf /opt/grist_bak + mv /opt/grist /opt/grist_bak + msg_ok "Backup created" + + fetch_and_deploy_gh_release "grist" "gristlabs/grist-core" "tarball" + + msg_info "Updating Grist" + mkdir -p /opt/grist/docs + cp -n /opt/grist_bak/.env /opt/grist/.env + if ls /opt/grist_bak/docs/* &>/dev/null; then + cp -r /opt/grist_bak/docs/* /opt/grist/docs/ + fi + [[ -f /opt/grist_bak/grist-sessions.db ]] && cp /opt/grist_bak/grist-sessions.db /opt/grist/grist-sessions.db + [[ -f /opt/grist_bak/landing.db ]] && cp /opt/grist_bak/landing.db /opt/grist/landing.db + cd /opt/grist + $STD yarn install + # install:ee stalls probing the private grist-ee repo (a dev-only path it + # tries before falling back to the public tarball); GIT_TERMINAL_PROMPT=0 + # makes that probe fail fast instead of waiting at a git login prompt. + export GIT_TERMINAL_PROMPT=0 + $STD yarn run install:ee -y + $STD yarn run build:prod + $STD yarn run install:python + msg_ok "Updated Grist" + + msg_info "Starting Service" + systemctl start grist + msg_ok "Started Service" + + msg_ok "Updated successfully!" + fi + 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}Grist: http://${IP}:8484${CL}" diff --git a/ct/headers/grist b/ct/headers/grist new file mode 100644 index 00000000..f82ced4f --- /dev/null +++ b/ct/headers/grist @@ -0,0 +1,6 @@ + ______ _ __ + / ____/____(_)____/ /_ + / / __/ ___/ / ___/ __/ +/ /_/ / / / (__ ) /_ +\____/_/ /_/____/\__/ + diff --git a/ct/headers/koffan b/ct/headers/koffan new file mode 100644 index 00000000..f0b44a58 --- /dev/null +++ b/ct/headers/koffan @@ -0,0 +1,6 @@ + __ __ ________ + / //_/___ / __/ __/___ _____ + / ,< / __ \/ /_/ /_/ __ `/ __ \ + / /| / /_/ / __/ __/ /_/ / / / / +/_/ |_\____/_/ /_/ \__,_/_/ /_/ + diff --git a/ct/headers/nexterm b/ct/headers/nexterm new file mode 100644 index 00000000..7d52bc56 --- /dev/null +++ b/ct/headers/nexterm @@ -0,0 +1,6 @@ + _ __ __ + / | / /__ _ __/ /____ _________ ___ + / |/ / _ \| |/_/ __/ _ \/ ___/ __ `__ \ + / /| / __/> = \([0-9.]*\)'.*/\1/p" /opt/onetimesecret/Gemfile) + RUBY_VERSION="${RUBY_VERSION:-3.4.7}" setup_ruby + + PNPM_VERSION=$(sed -n 's/.*"packageManager": "pnpm@\([^"]*\)".*/\1/p' /opt/onetimesecret/package.json) + NODE_VERSION=$(tr -d ' \n' /dev/null) + NODE_VERSION="${NODE_VERSION:-25}" NODE_MODULE="pnpm@${PNPM_VERSION:-11.1.2}" setup_nodejs + + msg_info "Restoring Configuration" + cp /opt/onetimesecret.env.bak /opt/onetimesecret/.env + mkdir -p /opt/onetimesecret/etc + for FILE in auth.yaml config.yaml logging.yaml puma.rb; do + [[ -f /opt/onetimesecret_etc_backup/${FILE} ]] && cp "/opt/onetimesecret_etc_backup/${FILE}" "/opt/onetimesecret/etc/${FILE}" + done + if [[ -n "${OTS_HOST:-}" ]]; then + sed -i "s|^HOST=.*|HOST=${OTS_HOST//&/\\&}|" /opt/onetimesecret/.env + fi + if [[ -n "${SSL_VALUE}" ]]; then + sed -i "s|^SSL=.*|SSL=${SSL_VALUE}|" /opt/onetimesecret/.env + fi + if grep -q '^RACK_ENV=' /opt/onetimesecret/.env; then + sed -i 's|^RACK_ENV=.*|RACK_ENV=production|' /opt/onetimesecret/.env + else + echo "RACK_ENV=production" >>/opt/onetimesecret/.env + fi + if grep -q '^AUTHENTICATION_MODE=' /opt/onetimesecret/.env; then + sed -i 's|^AUTHENTICATION_MODE=.*|AUTHENTICATION_MODE=simple|' /opt/onetimesecret/.env + else + echo "AUTHENTICATION_MODE=simple" >>/opt/onetimesecret/.env + fi + if ! grep -q '^PORT=' /opt/onetimesecret/.env; then + echo "PORT=3000" >>/opt/onetimesecret/.env + fi + chmod 600 /opt/onetimesecret/.env + rm -f /opt/onetimesecret.env.bak + rm -rf /opt/onetimesecret_etc_backup + msg_ok "Restored Configuration" + + msg_info "Reconciling Application" + systemctl enable -q --now redis-server + cd /opt/onetimesecret + mkdir -p tmp/pids log + $STD bash ./install.sh reconcile + msg_ok "Reconciled Application" + + msg_info "Building Frontend" + cd /opt/onetimesecret + $STD pnpm run build + msg_ok "Built Frontend" + + msg_info "Starting Service" + systemctl start onetimesecret + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +DISPLAY_HOST="${OTS_HOST:-$IP}" +case "${OTS_SSL:-false,,}" in +1 | true | yes | on) + DISPLAY_SCHEME="https" + ;; +*) + DISPLAY_SCHEME="http" + ;; +esac + +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}${DISPLAY_SCHEME}://${DISPLAY_HOST}${CL}" +echo -e "${INFO}${YW} Configure hostname, TLS, and SMTP settings in:${CL}" +echo -e "${TAB}${BGN}/opt/onetimesecret/.env${CL}" diff --git a/ct/pinchflat.sh b/ct/pinchflat.sh new file mode 100644 index 00000000..7eb8dc95 --- /dev/null +++ b/ct/pinchflat.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: nnsense +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/kieraneglin/pinchflat + +APP="Pinchflat" +var_tags="${var_tags:-media;youtube;downloader}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_unprivileged="${var_unprivileged:-1}" +var_gpu="${var_gpu:-yes}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/pinchflat/app ]]; then + msg_error "No ${APP} installation found." + exit 1 + fi + + if check_for_gh_release "pinchflat" "kieraneglin/pinchflat"; then + msg_info "Stopping Service" + systemctl stop pinchflat + msg_ok "Stopped Service" + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "pinchflat" "kieraneglin/pinchflat" "tarball" "latest" "/opt/pinchflat-src" + + msg_info "Building Pinchflat" + cd /opt/pinchflat-src + export MIX_ENV=prod + export ERL_FLAGS="+JPperf true" + $STD mix deps.get --only prod + $STD mix deps.compile + $STD yarn --cwd assets install + $STD mix assets.deploy + $STD mix compile + $STD mix release --overwrite + rm -rf /opt/pinchflat/app + cp -r _build/prod/rel/pinchflat /opt/pinchflat/app + msg_ok "Built Pinchflat" + + msg_info "Starting Service" + systemctl start pinchflat + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + 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}:8945${CL}" diff --git a/ct/shlink.sh b/ct/shlink.sh deleted file mode 100644 index 76e99fd4..00000000 --- a/ct/shlink.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) -# Copyright (c) 2021-2026 community-scripts ORG -# Author: MickLesk (CanbiZ) -# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE -# Source: https://shlink.io/ - -APP="Shlink" -var_tags="${var_tags:-url-shortener;analytics;php}" -var_cpu="${var_cpu:-2}" -var_ram="${var_ram:-2048}" -var_disk="${var_disk:-4}" -var_os="${var_os:-debian}" -var_version="${var_version:-13}" -var_arm64="${var_arm64:-no}" -var_unprivileged="${var_unprivileged:-1}" - -header_info "$APP" -variables -color -catch_errors - -function update_script() { - header_info - check_container_storage - check_container_resources - - if [[ ! -d /opt/shlink ]]; then - msg_error "No ${APP} Installation Found!" - exit - fi - - if check_for_gh_release "shlink" "shlinkio/shlink"; then - msg_info "Stopping Service" - systemctl stop shlink - msg_ok "Stopped Service" - - msg_info "Backing up Data" - cp /opt/shlink/.env /opt/shlink.env.bak - cp -r /opt/shlink/data /opt/shlink_data_backup - msg_ok "Backed up Data" - - CLEAN_INSTALL=1 fetch_and_deploy_gh_release "shlink" "shlinkio/shlink" "prebuild" "latest" "/opt/shlink" "shlink*_php8.5_dist.zip" - - msg_info "Restoring Data" - cp /opt/shlink.env.bak /opt/shlink/.env - rm -f /opt/shlink.env.bak - cp -r /opt/shlink_data_backup/. /opt/shlink/data - rm -rf /opt/shlink_data_backup - msg_ok "Restored Data" - - msg_info "Updating Application" - cd /opt/shlink - $STD php ./vendor/bin/rr get --no-interaction --location bin/ - chmod +x bin/rr - set -a - source /opt/shlink/.env - set +a - $STD php vendor/bin/shlink-installer init --no-interaction --clear-db-cache --skip-download-geolite - msg_ok "Updated Application" - - msg_info "Starting Service" - systemctl start shlink - msg_ok "Started Service" - msg_ok "Updated successfully!" - fi - - if [[ -d /opt/shlink-web-client ]]; then - if check_for_gh_release "shlink-web-client" "shlinkio/shlink-web-client"; then - CLEAN_INSTALL=1 fetch_and_deploy_gh_release "shlink-web-client" "shlinkio/shlink-web-client" "prebuild" "latest" "/opt/shlink-web-client" "shlink-web-client_*_dist.zip" - msg_ok "Updated Web Client" - fi - fi - 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 Shlink Web Client using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}" -echo -e "${INFO}${YW} Shlink HTTP API:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/ct/umbraco.sh b/ct/umbraco.sh new file mode 100644 index 00000000..bbd9b8aa --- /dev/null +++ b/ct/umbraco.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/montagneid/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Joost van den Berg +# License: MIT | https://github.com/montagneid/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/umbraco/Umbraco-CMS + +APP="Umbraco" +var_tags="${var_tags:-website}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-512}" +var_disk="${var_disk:-8}" +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 [[ ! -d /var/www ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + msg_info "Updating ${APP} LXC" + $STD apt update + $STD apt -y upgrade + msg_ok "Updated ${APP} LXC" + + msg_info "Updating Umbraco Templates" + $STD dotnet new update + msg_ok "Updated Umbraco Templates" + 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}https://${IP}" \ No newline at end of file diff --git a/install/grist-install.sh b/install/grist-install.sh new file mode 100644 index 00000000..f185127d --- /dev/null +++ b/install/grist-install.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: cfurrow | Co-Author: Slaviša Arežina (tremor021) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/gristlabs/grist-core + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + make \ + ca-certificates \ + python3-venv \ + git +msg_ok "Installed Dependencies" +NODE_VERSION="22" NODE_MODULE="yarn@latest" setup_nodejs +fetch_and_deploy_gh_release "grist" "gristlabs/grist-core" "tarball" + +msg_info "Installing Grist" +export CYPRESS_INSTALL_BINARY=0 +export NODE_OPTIONS="--max-old-space-size=2048" +# install:ee stalls probing the private grist-ee repo (a dev-only path it +# tries before falling back to the public tarball); GIT_TERMINAL_PROMPT=0 +# makes that probe fail fast instead of waiting at a git login prompt. +export GIT_TERMINAL_PROMPT=0 +cd /opt/grist +$STD yarn install +$STD yarn run install:ee -y +$STD yarn run build:prod +$STD yarn run install:python +cat </opt/grist/.env +NODE_ENV=production +GRIST_HOST=0.0.0.0 +EOF +msg_ok "Installed Grist" + +msg_info "Create Service" +cat </etc/systemd/system/grist.service +[Unit] +Description=Grist +After=network.target + +[Service] +Type=simple +WorkingDirectory=/opt/grist +ExecStart=/usr/bin/yarn run start:prod +EnvironmentFile=-/opt/grist/.env + +[Install] +WantedBy=multi-user.target +EOF + +systemctl enable -q --now grist +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc diff --git a/install/koffan-install.sh b/install/koffan-install.sh new file mode 100644 index 00000000..2b79fddd --- /dev/null +++ b/install/koffan-install.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: (AminGholizad) +# License: MIT | https://github.com/AminGholizad/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/PanSalut/Koffan + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +ensure_dependencies build-essential +setup_go +msg_ok "Installed Dependencies" + +fetch_and_deploy_gh_release "koffan" "PanSalut/Koffan" "tarball" + +msg_info "Building Koffan" +cd /opt/koffan +go build -o koffan main.go +msg_ok "Built Koffan" + +msg_info "Configuring Koffan" +PASSWORD=$(openssl rand -base64 12) +mkdir /opt/koffan/data +cat </opt/koffan/data/.env +APP_ENV=production +APP_PASSWORD=${PASSWORD} +PORT=3000 +DB_PATH=/opt/koffan/data/shopping.db +EOF + +cat <~/koffan.creds +Password: ${PASSWORD} +EOF +msg_ok "Configured Koffan" + +msg_info "Creating systemd service" +cat </etc/systemd/system/koffan.service +[Unit] +Description=Koffan Service +After=network.target + +[Service] +EnvironmentFile=/opt/koffan/data/.env +WorkingDirectory=/opt/koffan +ExecStart=/opt/koffan/koffan +Restart=always + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now koffan +msg_ok "Created systemd service" + +motd_ssh +customize +cleanup_lxc diff --git a/install/matterjs-server-install.sh b/install/matterjs-server-install.sh index 4cd6c0a6..16cbdcb5 100644 --- a/install/matterjs-server-install.sh +++ b/install/matterjs-server-install.sh @@ -24,10 +24,12 @@ msg_ok "Installed MatterJS-Server" msg_info "Configuring Network" cat </etc/sysctl.d/60-ipv6-ra-rio.conf +net.ipv6.conf.default.accept_ra=1 net.ipv6.conf.default.accept_ra_rtr_pref=1 -net.ipv6.conf.default.accept_ra_rt_info_max_plen=128 +net.ipv6.conf.default.accept_ra_rt_info_max_plen=64 +net.ipv6.conf.eth0.accept_ra=1 net.ipv6.conf.eth0.accept_ra_rtr_pref=1 -net.ipv6.conf.eth0.accept_ra_rt_info_max_plen=128 +net.ipv6.conf.eth0.accept_ra_rt_info_max_plen=64 EOF $STD sysctl -p /etc/sysctl.d/60-ipv6-ra-rio.conf msg_ok "Configured Network" diff --git a/install/nexterm-install.sh b/install/nexterm-install.sh new file mode 100644 index 00000000..068a744f --- /dev/null +++ b/install/nexterm-install.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Mathias Wagner (gnmyt) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://nexterm.dev/ + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +case "$(dpkg --print-architecture)" in + amd64) NX_ARCH="x64" ;; + arm64) NX_ARCH="arm64" ;; + *) + msg_error "Unsupported architecture: $(dpkg --print-architecture)" + exit 1 + ;; +esac + +fetch_and_deploy_gh_release "nexterm-engine" "gnmyt/Nexterm" "prebuild" "latest" "/opt/nexterm/engine" "nexterm-engine-linux-${NX_ARCH}.tar.gz" +fetch_and_deploy_gh_release "nexterm-server" "gnmyt/Nexterm" "singlefile" "latest" "/opt/nexterm/server" "nexterm-server-linux-${NX_ARCH}" + +msg_info "Configuring Nexterm" +LOCAL_ENGINE_TOKEN=$(tr -d '-' /etc/nexterm-engine/config.yaml +server_host: "127.0.0.1" +server_port: 7800 +registration_token: "${LOCAL_ENGINE_TOKEN}" +tls: false +EOF + +cat </etc/nexterm-server/server.env +NODE_ENV=production +SERVER_PORT=6989 +LOCAL_ENGINE_TOKEN=${LOCAL_ENGINE_TOKEN} +ENCRYPTION_KEY=${ENCRYPTION_KEY} +EOF +chmod 0640 /etc/nexterm-engine/config.yaml /etc/nexterm-server/server.env +msg_ok "Configured Nexterm" + +msg_info "Creating Server Service" +cat </etc/systemd/system/nexterm-server.service +[Unit] +Description=Nexterm Server +Documentation=https://docs.nexterm.dev/ +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/nexterm/data +EnvironmentFile=/etc/nexterm-server/server.env +ExecStart=/opt/nexterm/server/nexterm-server +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now nexterm-server +msg_ok "Created Server Service" + +msg_info "Creating Engine Service" +cat </etc/systemd/system/nexterm-engine.service +[Unit] +Description=Nexterm Engine +Documentation=https://docs.nexterm.dev/ +After=network-online.target nexterm-server.service +Wants=network-online.target + +[Service] +Type=simple +User=root +WorkingDirectory=/etc/nexterm-engine +Environment=FREERDP_EXTENSION_PATH=/opt/nexterm/engine/lib/freerdp2 +Environment=LD_LIBRARY_PATH=/opt/nexterm/engine/lib +ExecStart=/opt/nexterm/engine/nexterm-engine +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now nexterm-engine +msg_ok "Created Engine Service" + +motd_ssh +customize +cleanup_lxc diff --git a/install/onetimesecret-install.sh b/install/onetimesecret-install.sh new file mode 100644 index 00000000..dbfa03e0 --- /dev/null +++ b/install/onetimesecret-install.sh @@ -0,0 +1,142 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Hai Tran (epiHATR) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://onetimesecret.com/ | Github: https://github.com/onetimesecret/onetimesecret + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + build-essential \ + git \ + libffi-dev \ + libgmp-dev \ + libpq-dev \ + libreadline-dev \ + libsqlite3-dev \ + libssl-dev \ + libxml2-dev \ + libxslt1-dev \ + libyaml-dev \ + nginx \ + pkg-config \ + python3 \ + redis-server \ + zlib1g-dev +msg_ok "Installed Dependencies" + +fetch_and_deploy_gh_release "onetimesecret" "onetimesecret/onetimesecret" "tarball" + +RUBY_VERSION=$(sed -n "s/^ruby '>= \([0-9.]*\)'.*/\1/p" /opt/onetimesecret/Gemfile) +RUBY_VERSION="${RUBY_VERSION:-3.4.7}" setup_ruby + +PNPM_VERSION=$(sed -n 's/.*"packageManager": "pnpm@\([^"]*\)".*/\1/p' /opt/onetimesecret/package.json) +NODE_VERSION=$(tr -d ' \n' /dev/null) +NODE_VERSION="${NODE_VERSION:-25}" NODE_MODULE="pnpm@${PNPM_VERSION:-11.1.2}" setup_nodejs + +HOST_VALUE="${OTS_HOST:-$LOCAL_IP}" +SSL_VALUE="${OTS_SSL:-false}" +case "${SSL_VALUE,,}" in +1 | true | yes | on) SSL_VALUE="true" ;; +0 | false | no | off | "") SSL_VALUE="false" ;; +*) + msg_error "Invalid OTS_SSL value '${OTS_SSL}' (use true/false)" + exit 1 + ;; +esac + +msg_info "Configuring Application" +systemctl enable -q --now redis-server +cd /opt/onetimesecret +$STD bash ./install.sh init +sed -i \ + -e "s|^REDIS_URL=.*|REDIS_URL=redis://127.0.0.1:6379/0|" \ + -e "s|^HOST=.*|HOST=${HOST_VALUE//&/\\&}|" \ + -e "s|^SSL=.*|SSL=${SSL_VALUE}|" \ + /opt/onetimesecret/.env +if grep -q '^RACK_ENV=' /opt/onetimesecret/.env; then + sed -i 's|^RACK_ENV=.*|RACK_ENV=production|' /opt/onetimesecret/.env +else + echo "RACK_ENV=production" >>/opt/onetimesecret/.env +fi +if grep -q '^AUTHENTICATION_MODE=' /opt/onetimesecret/.env; then + sed -i 's|^AUTHENTICATION_MODE=.*|AUTHENTICATION_MODE=simple|' /opt/onetimesecret/.env +else + echo "AUTHENTICATION_MODE=simple" >>/opt/onetimesecret/.env +fi +if ! grep -q '^PORT=' /opt/onetimesecret/.env; then + echo "PORT=3000" >>/opt/onetimesecret/.env +fi +chmod 600 /opt/onetimesecret/.env +mkdir -p /opt/onetimesecret/tmp/pids /opt/onetimesecret/log +msg_ok "Configured Application" + +msg_info "Reconciling Application" +cd /opt/onetimesecret +$STD bash ./install.sh reconcile +msg_ok "Reconciled Application" + +msg_info "Building Frontend" +cd /opt/onetimesecret +$STD pnpm run build +msg_ok "Built Frontend" + +msg_info "Creating Service" +cat <<'EOF' >/etc/systemd/system/onetimesecret.service +[Unit] +Description=Onetime Secret Service +After=network.target redis-server.service +Requires=redis-server.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/onetimesecret +Environment=HOME=/root +Environment=PATH=/root/.rbenv/shims:/root/.rbenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ExecStart=/bin/bash -lc 'source .env.sh && exec bundle exec puma -C etc/puma.rb' +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now onetimesecret +msg_ok "Created Service" + +msg_info "Configuring Nginx" +cat <<'EOF' >/etc/nginx/sites-available/onetimesecret +server { + listen 80 default_server; + server_name _; + + location / { + proxy_pass http://127.0.0.1:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +EOF +ln -sf /etc/nginx/sites-available/onetimesecret /etc/nginx/sites-enabled/onetimesecret +rm -f /etc/nginx/sites-enabled/default +$STD nginx -t +systemctl enable -q --now nginx +systemctl reload nginx +msg_ok "Configured Nginx" + +motd_ssh +customize +cleanup_lxc diff --git a/install/oxicloud-install.sh b/install/oxicloud-install.sh index 00fc0005..9a8cb616 100644 --- a/install/oxicloud-install.sh +++ b/install/oxicloud-install.sh @@ -18,7 +18,7 @@ $STD apt install -y \ build-essential msg_ok "Installed Dependencies" -PG_VERSION="17" setup_postgresql +PG_VERSION="17" PG_MODULES="pg_trgm,ltree" setup_postgresql PG_DB_NAME="oxicloud" PG_DB_USER="oxicloud" setup_postgresql_db fetch_and_deploy_gh_release "OxiCloud" "DioCrafts/OxiCloud" "tarball" "latest" "/opt/oxicloud" TOOLCHAIN="$(sed -n '2s/[^:]*://p' /opt/oxicloud/Dockerfile | awk -F- '{print $1}')" diff --git a/install/paperclip-install.sh b/install/paperclip-install.sh index 1b642648..066b3202 100644 --- a/install/paperclip-install.sh +++ b/install/paperclip-install.sh @@ -17,7 +17,6 @@ msg_info "Installing Dependencies" $STD apt install -y \ build-essential \ git \ - python3 \ ripgrep msg_ok "Installed Dependencies" @@ -28,7 +27,7 @@ PG_DB_NAME="paperclip" PG_DB_USER="paperclip" setup_postgresql_db fetch_and_deploy_gh_release "paperclip-ai" "paperclipai/paperclip" "tarball" msg_info "Building Paperclip" -cd /opt/paperclip +cd /opt/paperclip-ai export HUSKY=0 export NODE_OPTIONS="--max-old-space-size=8192" $STD pnpm install --frozen-lockfile @@ -43,15 +42,19 @@ $STD npm install -g \ msg_ok "Installed Agent CLIs" msg_info "Configuring Paperclip" +PAPERCLIP_HOME="/opt/paperclip-data" +PAPERCLIP_CONFIG="${PAPERCLIP_HOME}/instances/default/config.json" + mkdir -p /opt/paperclip-data mkdir -p /root/.claude /root/.codex BETTER_AUTH_SECRET=$(openssl rand -hex 32) -cat </opt/paperclip/.env +cat </opt/paperclip-ai/.env DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME} HOST=0.0.0.0 PORT=3100 SERVE_UI=true -PAPERCLIP_HOME=/opt/paperclip-data +PAPERCLIP_HOME=${PAPERCLIP_HOME} +PAPERCLIP_CONFIG=${PAPERCLIP_CONFIG} PAPERCLIP_INSTANCE_ID=default PAPERCLIP_DEPLOYMENT_MODE=authenticated PAPERCLIP_DEPLOYMENT_EXPOSURE=private @@ -61,22 +64,26 @@ EOF msg_ok "Configured Paperclip" msg_info "Running Database Migrations" -set -a && source /opt/paperclip/.env && set +a +set -a && source /opt/paperclip-ai/.env && set +a $STD pnpm db:migrate msg_ok "Ran Database Migrations" msg_info "Bootstrapping Paperclip" -PAPERCLIP_ONBOARD_LOG=/opt/paperclip/paperclip-onboard.log -PAPERCLIP_BOOTSTRAP_LOG=/opt/paperclip/paperclip-bootstrap.log +PAPERCLIP_ONBOARD_LOG=/opt/paperclip-ai/paperclip-onboard.log +PAPERCLIP_BOOTSTRAP_LOG=/opt/paperclip-ai/paperclip-bootstrap.log for PAPERCLIP_ONBOARD_CMD in \ "pnpm paperclipai onboard --yes --bind lan" \ "pnpm paperclipai onboard --yes"; do rm -f "$PAPERCLIP_ONBOARD_LOG" - setsid bash -c "cd /opt/paperclip && ${PAPERCLIP_ONBOARD_CMD}" >"$PAPERCLIP_ONBOARD_LOG" 2>&1 & + setsid env \ + PAPERCLIP_HOME="$PAPERCLIP_HOME" \ + PAPERCLIP_CONFIG="$PAPERCLIP_CONFIG" \ + bash -c 'cd /opt/paperclip-ai && exec "$@"' _ $PAPERCLIP_ONBOARD_CMD \ + >"$PAPERCLIP_ONBOARD_LOG" 2>&1 & PAPERCLIP_ONBOARD_PID=$! for _ in {1..60}; do - if [[ -f /opt/paperclip-data/instances/default/config.json ]]; then + if [[ -f "$PAPERCLIP_CONFIG" ]]; then break fi if ! kill -0 "$PAPERCLIP_ONBOARD_PID" 2>/dev/null; then @@ -88,19 +95,19 @@ for PAPERCLIP_ONBOARD_CMD in \ kill -- -"${PAPERCLIP_ONBOARD_PID}" >/dev/null 2>&1 || true wait "$PAPERCLIP_ONBOARD_PID" 2>/dev/null || true fi - [[ -f /opt/paperclip-data/instances/default/config.json ]] && break + [[ -f "$PAPERCLIP_CONFIG" ]] && break if ! grep -q "unknown option '--bind'" "$PAPERCLIP_ONBOARD_LOG"; then break fi msg_info "Retrying Paperclip Onboarding" done -if [[ ! -f /opt/paperclip-data/instances/default/config.json ]]; then +if [[ ! -f "$PAPERCLIP_CONFIG" ]]; then msg_error "Failed to bootstrap Paperclip" exit 1 fi -if grep -q 'authenticated' /opt/paperclip-data/instances/default/config.json; then +if grep -q 'authenticated' $PAPERCLIP_CONFIG; then pnpm paperclipai auth bootstrap-ceo >"$PAPERCLIP_BOOTSTRAP_LOG" 2>&1 || true PAPERCLIP_INVITE_URL=$(awk -F'Invite URL: ' '/Invite URL:/ {print $2; exit}' "$PAPERCLIP_BOOTSTRAP_LOG") PAPERCLIP_INVITE_EXPIRY=$(awk -F'Expires: ' '/Expires:/ {print $2; exit}' "$PAPERCLIP_BOOTSTRAP_LOG") @@ -134,8 +141,8 @@ Requires=postgresql.service [Service] Type=simple User=root -WorkingDirectory=/opt/paperclip -EnvironmentFile=/opt/paperclip/.env +WorkingDirectory=/opt/paperclip-ai +EnvironmentFile=/opt/paperclip-ai/.env Environment=HOME=/root Environment=CODEX_HOME=/root/.codex Environment=PATH=/root/.local/bin:/usr/local/bin:/usr/bin:/bin diff --git a/install/pinchflat-install.sh b/install/pinchflat-install.sh new file mode 100644 index 00000000..c8c5db1f --- /dev/null +++ b/install/pinchflat-install.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: nnsense +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/kieraneglin/pinchflat + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" + +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + build-essential \ + elixir \ + erlang-dev \ + erlang-inets \ + erlang-os-mon \ + erlang-runtime-tools \ + erlang-syntax-tools \ + erlang-xmerl \ + git \ + libsqlite3-dev \ + locales \ + openssh-client \ + openssl \ + pipx \ + pkg-config \ + procps \ + python3-mutagen \ + zip +msg_ok "Installed Dependencies" + +NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs +FFMPEG_TYPE="binary" setup_ffmpeg +setup_hwaccel +fetch_and_deploy_gh_release "deno" "denoland/deno" "prebuild" "latest" "/usr/local/bin" "deno-x86_64-unknown-linux-gnu.zip" +fetch_and_deploy_gh_release "yt-dlp" "yt-dlp/yt-dlp" "singlefile" "latest" "/usr/local/bin" "yt-dlp_linux" + +msg_info "Installing Apprise" +export PIPX_HOME=/opt/pipx +export PIPX_BIN_DIR=/usr/local/bin +$STD pipx install apprise +msg_ok "Installed Apprise" + +fetch_and_deploy_gh_release "pinchflat" "kieraneglin/pinchflat" "tarball" "latest" "/opt/pinchflat-src" + +msg_info "Configuring Pinchflat" +CONFIG_PATH="/opt/pinchflat/config" +DOWNLOADS_PATH="/opt/pinchflat/downloads" +mkdir -p \ + /etc/elixir_tzdata_data \ + /etc/yt-dlp/plugins \ + /opt/pinchflat/app \ + "$CONFIG_PATH/db" \ + "$CONFIG_PATH/extras" \ + "$CONFIG_PATH/logs" \ + "$CONFIG_PATH/metadata" \ + "$DOWNLOADS_PATH" +ln -sfn "$CONFIG_PATH" /config +ln -sfn "$DOWNLOADS_PATH" /downloads +chmod ugo+rw /etc/elixir_tzdata_data /etc/yt-dlp /etc/yt-dlp/plugins + +cat </opt/pinchflat/.env +LANG=en_US.UTF-8 +LANGUAGE=en_US:en +LC_ALL=en_US.UTF-8 +MIX_ENV=prod +PHX_SERVER=true +PORT=8945 +RUN_CONTEXT=selfhosted +CONFIG_PATH=${CONFIG_PATH} +MEDIA_PATH=${DOWNLOADS_PATH} +TZ_DATA_PATH=/etc/elixir_tzdata_data +SECRET_KEY_BASE=$(openssl rand -base64 48) +EOF +msg_ok "Configured Pinchflat" + +msg_info "Building Pinchflat" +cd /opt/pinchflat-src +export MIX_ENV=prod +export ERL_FLAGS="+JPperf true" +$STD mix local.hex --force +$STD mix local.rebar --force +$STD mix deps.get --only prod +$STD mix deps.compile +$STD yarn --cwd assets install +$STD mix assets.deploy +$STD mix compile +$STD mix release --overwrite +rm -rf /opt/pinchflat/app +cp -r _build/prod/rel/pinchflat /opt/pinchflat/app +msg_ok "Built Pinchflat" + +msg_info "Creating Service" +cat </etc/systemd/system/pinchflat.service +[Unit] +Description=Pinchflat +After=network.target + +[Service] +Type=simple +EnvironmentFile=/opt/pinchflat/.env +WorkingDirectory=/opt/pinchflat/app +UMask=0022 +ExecStartPre=/opt/pinchflat/app/bin/check_file_permissions +ExecStartPre=/opt/pinchflat/app/bin/migrate +ExecStart=/opt/pinchflat/app/bin/pinchflat start +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now pinchflat +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc diff --git a/install/shlink-install.sh b/install/shlink-install.sh deleted file mode 100644 index a40714bd..00000000 --- a/install/shlink-install.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2021-2026 community-scripts ORG -# Author: MickLesk (CanbiZ) -# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE -# Source: https://shlink.io/ - -source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" -color -verb_ip6 -catch_errors -setting_up_container -network_check -update_os - -PHP_VERSION="8.5" setup_php -setup_mariadb -MARIADB_DB_NAME="shlink" MARIADB_DB_USER="shlink" setup_mariadb_db - -fetch_and_deploy_gh_release "shlink" "shlinkio/shlink" "prebuild" "latest" "/opt/shlink" "shlink*_php8.5_dist.zip" - -msg_info "Setting up Application" -cd /opt/shlink -$STD php ./vendor/bin/rr get --no-interaction --location bin/ -chmod +x bin/rr -mkdir -p data/cache data/locks data/log data/proxies data/temp-geolite -chmod -R 775 data -cat </opt/shlink/.env -DEFAULT_DOMAIN=${LOCAL_IP}:8080 -IS_HTTPS_ENABLED=false -DB_DRIVER=maria -DB_NAME=${MARIADB_DB_NAME} -DB_USER=${MARIADB_DB_USER} -DB_PASSWORD=${MARIADB_DB_PASS} -DB_HOST=127.0.0.1 -DB_PORT=3306 -EOF -set -a -source /opt/shlink/.env -set +a -$STD php vendor/bin/shlink-installer init --no-interaction --clear-db-cache --skip-download-geolite -API_OUTPUT=$(php bin/cli api-key:generate --name=default 2>&1) -INITIAL_API_KEY=$(echo "$API_OUTPUT" | sed -n 's/.*Generated API key: "\([^"]*\)".*/\1/p') -if [[ -n "$INITIAL_API_KEY" ]]; then - echo "INITIAL_API_KEY=${INITIAL_API_KEY}" >>/opt/shlink/.env -fi -msg_ok "Set up Application" - -if prompt_confirm "Install Shlink Web Client?" "y" 60; then - msg_info "Installing Dependencies" - $STD apt install -y nginx - msg_ok "Installed Dependencies" - - fetch_and_deploy_gh_release "shlink-web-client" "shlinkio/shlink-web-client" "prebuild" "latest" "/opt/shlink-web-client" "shlink-web-client_*_dist.zip" - - msg_info "Setting up Web Client" - cat </opt/shlink-web-client/servers.json -[ - { - "name": "Shlink", - "url": "http://${LOCAL_IP}:8080", - "apiKey": "${INITIAL_API_KEY}" - } -] -EOF - cat <<'EOF' >/etc/nginx/sites-available/shlink-web-client -server { - listen 3000 default_server; - charset utf-8; - root /opt/shlink-web-client; - index index.html; - - location ~* \.(?:manifest|appcache|html?|xml|json)$ { - expires -1; - } - - location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { - expires 1M; - add_header Cache-Control "public"; - } - - location ~* \.(?:css|js)$ { - expires 1y; - add_header Cache-Control "public"; - } - - location = /servers.json { - try_files /servers.json /conf.d/servers.json; - } - - location / { - try_files $uri $uri/ /index.html$is_args$args; - } -} -EOF - ln -sf /etc/nginx/sites-available/shlink-web-client /etc/nginx/sites-enabled/shlink-web-client - rm -f /etc/nginx/sites-enabled/default - systemctl enable -q nginx - $STD systemctl restart nginx - msg_ok "Set up Web Client" -fi - -msg_info "Creating Service" -cat </etc/systemd/system/shlink.service -[Unit] -Description=Shlink URL Shortener -After=network.target mariadb.service - -[Service] -Type=simple -User=root -WorkingDirectory=/opt/shlink -EnvironmentFile=/opt/shlink/.env -ExecStart=/opt/shlink/bin/rr serve -c config/roadrunner/.rr.yml -Restart=on-failure -RestartSec=5 - -[Install] -WantedBy=multi-user.target -EOF -systemctl enable -q --now shlink -msg_ok "Created Service" - -motd_ssh -customize -cleanup_lxc diff --git a/install/umbraco-install.sh b/install/umbraco-install.sh new file mode 100644 index 00000000..d77e8564 --- /dev/null +++ b/install/umbraco-install.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Joost van den Berg +# License: MIT | https://github.com/montagneid/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/umbraco/Umbraco-CMS + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +var_project_name="cms" + +msg_info "Installing Dependencies" +$STD apt install -y \ + ca-certificates \ + uuid-runtime \ + nginx \ + vsftpd +msg_ok "Installed Dependencies" + +msg_info "Installing .NET SDK 10.0" +setup_deb822_repo \ + "microsoft" \ + "https://packages.microsoft.com/keys/microsoft-2025.asc" \ + "https://packages.microsoft.com/debian/13/prod/" \ + "trixie" +$STD apt install -y dotnet-sdk-10.0 +msg_ok "Installed .NET SDK 10.0" + +msg_info "Installing dotnet Umbraco templates and create project (Patience)" +cd /var/www/html +$STD dotnet new install Umbraco.Templates +$STD dotnet new umbraco --force -n "$var_project_name" +msg_ok "Umbraco templates installed and project created" + +msg_info "Configuring database connection and unattended setup" +cd /var/www/html/$var_project_name +UMBRACO_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) +jq --arg umbracopass "$UMBRACO_PASS" '. + { + "ConnectionStrings": { + "umbracoDbDSN": "Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", + "umbracoDbDSN_ProviderName": "Microsoft.Data.Sqlite" + }, + "Umbraco": { + "CMS": { + "_Comment": "Remove the Unattended section after first run", + "Unattended": { + "InstallUnattended": true, + "UnattendedUserName": "admin", + "UnattendedUserEmail": "admin@umbraco.local", + "UnattendedUserPassword": $umbracopass + } + } + } +}' /var/www/html/$var_project_name/appsettings.json > /tmp/appsettings.tmp && mv /tmp/appsettings.tmp /var/www/html/$var_project_name/appsettings.json +ln -sf /var/www/html/$var_project_name/appsettings.json ~/umbraco.creds +msg_ok "Database connection and unattended setup configured" + +msg_info "Setting up Nginx Server" +rm -f /var/www/html/index.nginx-debian.html +cat </etc/nginx/sites-available/default +map \$http_connection \$connection_upgrade { + "~*Upgrade" \$http_connection; + default keep-alive; +} +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + ssl_certificate /etc/ssl/umbraco/umbraco.crt; + ssl_certificate_key /etc/ssl/umbraco/umbraco.key; + location / { + proxy_pass https://127.0.0.1:7000/; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection \$connection_upgrade; + proxy_set_header Host \$host; + proxy_cache_bypass \$http_upgrade; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_buffering on; + proxy_buffer_size 16k; + proxy_buffers 8 32k; + proxy_busy_buffers_size 64k; + } +} +EOF +create_self_signed_cert +systemctl reload nginx +msg_ok "Nginx Server created" + +msg_info "Creating Kestrel Umbraco Service" +cat </usr/local/bin/umbraco-start.sh +#!/usr/bin/env bash +/usr/bin/dotnet /var/www/html/$var_project_name-publish/$var_project_name.dll --urls "https://0.0.0.0:7000" & +EOF +chmod +x /usr/local/bin/umbraco-start.sh + +cat </etc/systemd/system/umbraco-kestrel.service +[Unit] +Description=Umbraco CMS running on Linux + +[Service] +WorkingDirectory=/var/www/html/$var_project_name-publish +ExecStart=/usr/local/bin/umbraco-start.sh +Restart=always +RestartSec=10 +KillSignal=SIGINT +SyslogIdentifier=umbraco +User=root +Environment=ASPNETCORE_ENVIRONMENT=Production +Environment=DOTNET_NOLOGO=true +Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now umbraco-kestrel +msg_ok "Umbraco Kestrel Service created" + +msg_info "Creating dotnet publish script" +cat </var/www/html/$var_project_name/publish.sh +#!/usr/bin/env bash +cd /var/www/html/$var_project_name +systemctl stop umbraco-kestrel.service +dotnet publish -c Release -o /var/www/html/$var_project_name-publish +systemctl start umbraco-kestrel.service +EOF +chmod +x /var/www/html/$var_project_name/publish.sh +msg_ok "Dotnet publish script created" + +msg_info "Building and publishing project (Patience)" +$STD /var/www/html/$var_project_name/publish.sh +msg_ok "Umbraco published successfully to /var/www/html/$var_project_name-publish" + +msg_info "Setting up FTP Server" +useradd ftpuser +FTP_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) +usermod --password $(echo ${FTP_PASS} | openssl passwd -1 -stdin) ftpuser +mkdir -p /var/www/html +usermod -d /var/www/html ftp +usermod -d /var/www/html ftpuser +chown -R ftpuser:ftpuser /var/www/html +sed -i "s|#write_enable=YES|write_enable=YES|g" /etc/vsftpd.conf +sed -i "s|#chroot_local_user=YES|chroot_local_user=NO|g" /etc/vsftpd.conf +systemctl restart -q vsftpd.service +{ + echo "FTP Credentials" + echo "Username: ftpuser" + echo "Password: $FTP_PASS" +} >>~/ftp.creds +msg_ok "FTP server setup completed" + +msg_info "Creating Visual Studio FTP Publish Profile" +PROJECT_GUID=$(uuidgen | tr '[:upper:]' '[:lower:]') +CONTAINER_IP=$(hostname -I | awk '{print $1}') +PUBLISH_PROFILE_DIR="/var/www/html/${var_project_name}/Properties/PublishProfiles" +mkdir -p "$PUBLISH_PROFILE_DIR" +cat >"$PUBLISH_PROFILE_DIR/FTPProfile.pubxml" < + + + FTP + true + Release + Any CPU + https://${CONTAINER_IP} + false + ${PROJECT_GUID} + ${CONTAINER_IP} + false + true + ${var_project_name}-publish + ftpuser + <_SavePWD>true + <_TargetId>FTP + + +EOF +msg_ok "Publish Profile created" + +motd_ssh +customize +cleanup_lxc diff --git a/json/koffan.json b/json/koffan.json new file mode 100644 index 00000000..7a1b2dbb --- /dev/null +++ b/json/koffan.json @@ -0,0 +1,40 @@ +{ + "name": "Koffan", + "slug": "koffan", + "categories": [ + 12 + ], + "date_created": "2026-05-25", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 3000, + "documentation": null, + "website": null, + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/koffan.webp", + "description": "Koffan is a lightweight web application for managing shopping lists, designed for couples and families. It allows real-time synchronization between multiple devices, so everyone knows what to buy and what's already in the cart.\n\nThe app works in any browser on both mobile and desktop. Just one password to log in - no complicated registration required.", + "install_methods": [ + { + "type": "default", + "script": "ct/koffan.sh", + "config_path": "/opt/koffan/data/.env", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 4, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": "shopping123" + }, + "notes": [ + { + "text": "Credentials are saved to `~/koffan.creds`.", + "type": "info" + } + ] +} diff --git a/json/nexterm.json b/json/nexterm.json new file mode 100644 index 00000000..cda838de --- /dev/null +++ b/json/nexterm.json @@ -0,0 +1,36 @@ +{ + "name": "Nexterm", + "slug": "nexterm", + "categories": [ + 10 + ], + "date_created": "2026-05-25", + "type": "ct", + "updateable": true, + "privileged": false, + "has_arm": false, + "interface_port": 6989, + "documentation": "https://docs.nexterm.dev/", + "website": "https://nexterm.dev/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/nexterm.webp", + "description": "Nexterm is an open-source server management software for SSH, VNC & RDP. It bundles a web interface, file management, monitoring, and team collaboration with two-factor authentication, OIDC SSO, and encrypted credential storage.", + "install_methods": [ + { + "type": "default", + "script": "ct/nexterm.sh", + "config_path": "/etc/nexterm-server/server.env", + "resources": { + "cpu": 2, + "ram": 2048, + "hdd": 6, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} diff --git a/json/onetimesecret.json b/json/onetimesecret.json new file mode 100644 index 00000000..e1cf7910 --- /dev/null +++ b/json/onetimesecret.json @@ -0,0 +1,47 @@ +{ + "name": "Onetime Secret", + "slug": "onetimesecret", + "categories": [6], + "date_created": "2026-05-26", + "type": "ct", + "updateable": true, + "privileged": false, + "has_arm": false, + "interface_port": 80, + "documentation": "https://docs.onetimesecret.com/en/self-hosting/installation/", + "website": "https://onetimesecret.com/", + "logo": "https://onetimesecret.com/favicon.svg", + "description": "Onetime Secret is a self-hosted secret sharing app that creates self-destructing links for passwords, API keys, and other sensitive text.", + "install_methods": [ + { + "type": "default", + "script": "ct/onetimesecret.sh", + "config_path": "/opt/onetimesecret/.env", + "resources": { + "cpu": 2, + "ram": 4096, + "hdd": 10, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "Update HOST and set SSL=true in /opt/onetimesecret/.env when using a domain or TLS-terminating reverse proxy.", + "type": "warning" + }, + { + "text": "Configure SMTP settings in /opt/onetimesecret/.env if you want email notifications or account verification features.", + "type": "info" + }, + { + "text": "Back up /opt/onetimesecret/.env because it contains the root SECRET used to derive the app's other cryptographic keys.", + "type": "warning" + } + ] +} diff --git a/json/pinchflat.json b/json/pinchflat.json new file mode 100644 index 00000000..45d46ff4 --- /dev/null +++ b/json/pinchflat.json @@ -0,0 +1,48 @@ +{ + "name": "Pinchflat", + "slug": "pinchflat", + "categories": [ + 13 + ], + "date_created": "2026-05-05", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 8945, + "documentation": "https://github.com/kieraneglin/pinchflat/wiki", + "website": "https://github.com/kieraneglin/pinchflat", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/pinchflat.webp", + "description": "Pinchflat is a self-hosted YouTube media manager built with yt-dlp for automatically downloading and organizing content from channels and playlists.", + "install_methods": [ + { + "type": "default", + "script": "ct/pinchflat.sh", + "config_path": "/opt/pinchflat/.env", + "resources": { + "cpu": 2, + "ram": 2048, + "hdd": 8, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "For large media libraries, increase disk space or mount external storage at `/opt/pinchflat/downloads` before downloading media to avoid filling the LXC disk.", + "type": "warning" + }, + { + "text": "Pinchflat data is stored in `/opt/pinchflat/config`", + "type": "info" + }, + { + "text": "downloaded media is stored in `/opt/pinchflat/downloads`", + "type": "info" + } + ] +} diff --git a/json/shlink.json b/json/shlink.json deleted file mode 100644 index 1506ca04..00000000 --- a/json/shlink.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "Shlink", - "slug": "shlink", - "categories": [ - 0 - ], - "date_created": "2026-04-20", - "type": "ct", - "updateable": true, - "privileged": false, - "has_arm": false, - "interface_port": 3000, - "documentation": "https://shlink.io/documentation/", - "website": "https://shlink.io/", - "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/shlink.webp", - "description": "Shlink is a self-hosted URL shortener built in PHP that provides detailed analytics, a REST API, tags, expiration dates, and integrations via webhooks.", - "install_methods": [ - { - "type": "default", - "script": "ct/shlink.sh", - "config_path": "/opt/shlink/.env", - "resources": { - "cpu": 2, - "ram": 2048, - "hdd": 4, - "os": "Debian", - "version": "13" - } - } - ], - "default_credentials": { - "username": null, - "password": null - }, - "notes": [ - { - "text": "The initial API key is stored in /opt/shlink/.env. You need it to connect Shlink Web Client or any API consumer.", - "type": "warning" - }, - { - "text": "Configure your short domain by editing DEFAULT_DOMAIN in /opt/shlink/.env and restarting the service.", - "type": "info" - }, - { - "text": "Shlink API runs on port 8080, the Web Client (if installed) on port 3000.", - "type": "info" - } - ] -} \ No newline at end of file diff --git a/json/umbraco.json b/json/umbraco.json new file mode 100644 index 00000000..c3a71e7d --- /dev/null +++ b/json/umbraco.json @@ -0,0 +1,44 @@ +{ + "name": "Umbraco CMS", + "slug": "umbraco", + "categories": [ + 25 + ], + "date_created": "2026-05-06", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 443, + "documentation": "https://docs.umbraco.com/", + "website": "https://umbraco.com/", + "logo": "https://umbraco.com/media/54xnncgt/umbraco_logo_blue05.webp?rmode=pad&width=680&quality=85&v=1dad6b6701b24f0", + "config_path": "", + "description": "Umbraco is a free, open-source .NET CMS with a friendly editing experience, beautiful backoffice, and powerful customization options. Automatically setup a Umbraco server up, as well as a FTP server so you can publish to this container from Visual Studio.", + "install_methods": [ + { + "type": "default", + "script": "ct/umbraco.sh", + "resources": { + "cpu": 2, + "ram": 512, + "hdd": 8, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "Cridentials are saved in /root", + "type": "info" + }, + { + "text": "The FTPProfile.pubxml can be used to publish directly from Visual Studio, but you can also use the built-in code editor in the Umbraco backoffice.", + "type": "info" + } + ] +} diff --git a/misc/tools.func b/misc/tools.func index 088b1d0d..f0892c61 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -7979,7 +7979,7 @@ setup_postgresql_db() { IFS=',' read -ra EXT_LIST <<<"${PG_DB_EXTENSIONS:-}" for ext in "${EXT_LIST[@]}"; do ext=$(echo "$ext" | xargs) # Trim whitespace - $STD sudo -u postgres psql -d "$PG_DB_NAME" -c "CREATE EXTENSION IF NOT EXISTS $ext;" + $STD sudo -u postgres psql -d "$PG_DB_NAME" -c "CREATE EXTENSION IF NOT EXISTS \"$ext\";" done fi