diff --git a/CHANGELOG.md b/CHANGELOG.md index 32d685cc5..191e4db2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -512,9 +512,26 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit ### 🆕 New Scripts - - Nezha ([#16025](https://github.com/community-scripts/ProxmoxVE/pull/16025)) + - Discourse ([#16024](https://github.com/community-scripts/ProxmoxVE/pull/16024)) +- Mastodon ([#16029](https://github.com/community-scripts/ProxmoxVE/pull/16029)) +- Docspell ([#16033](https://github.com/community-scripts/ProxmoxVE/pull/16033)) +- Poznote ([#16030](https://github.com/community-scripts/ProxmoxVE/pull/16030)) +- Shiori ([#16026](https://github.com/community-scripts/ProxmoxVE/pull/16026)) +- Nezha ([#16025](https://github.com/community-scripts/ProxmoxVE/pull/16025)) - PasswordPusher ([#16031](https://github.com/community-scripts/ProxmoxVE/pull/16031)) +### 🚀 Updated Scripts + + - #### 🐞 Bug Fixes + + - Vikunja: pin install/update to v2.3.0 due upstream issues [@MickLesk](https://github.com/MickLesk) ([#16059](https://github.com/community-scripts/ProxmoxVE/pull/16059)) + +### 💾 Core + + - #### 🐞 Bug Fixes + + - core: Handle LXC upgrade prompt cancellation [@MickLesk](https://github.com/MickLesk) ([#16058](https://github.com/community-scripts/ProxmoxVE/pull/16058)) + ## 2026-07-26 ### 🆕 New Scripts diff --git a/ct/discourse.sh b/ct/discourse.sh new file mode 100644 index 000000000..7413d2ad5 --- /dev/null +++ b/ct/discourse.sh @@ -0,0 +1,71 @@ +#!/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://www.discourse.org/ + +APP="Discourse" +var_tags="${var_tags:-forum;community;discussion}" +var_cpu="${var_cpu:-4}" +var_ram="${var_ram:-4096}" +var_disk="${var_disk:-20}" +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/discourse ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if [[ ! -f /opt/discourse/.env ]]; then + msg_error "No Discourse Configuration Found!" + exit + fi + + msg_info "Stopping Service" + systemctl stop discourse + msg_ok "Stopped Service" + + create_backup /opt/discourse/.env + + msg_info "Updating Discourse" + PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql + cd /opt/discourse + git pull origin main + $STD bundle install --deployment --without test development + $STD yarn install + $STD runuser -u postgres -- psql -d discourse -c "CREATE EXTENSION IF NOT EXISTS vector;" + $STD bundle exec rails assets:precompile + $STD bundle exec rails db:migrate + msg_ok "Updated Discourse" + + restore_backup + + msg_info "Starting Service" + systemctl start discourse + msg_ok "Started Service" + 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 "${GATEWAY}${BGN}http://${IP}${CL}" diff --git a/ct/docspell.sh b/ct/docspell.sh new file mode 100644 index 000000000..5f4570f93 --- /dev/null +++ b/ct/docspell.sh @@ -0,0 +1,61 @@ +#!/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://docspell.org/ + +APP="Docspell" +var_tags="${var_tags:-documents;ocr;paperless;productivity}" +var_cpu="${var_cpu:-4}" +var_ram="${var_ram:-4096}" +var_disk="${var_disk:-16}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +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 /etc/docspell-restserver/docspell-server.conf ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "docspell-joex" "eikek/docspell"; then + msg_info "Stopping Services" + systemctl stop docspell-joex docspell-restserver + msg_ok "Stopped Services" + + create_backup /etc/docspell-joex/docspell-joex.conf \ + /etc/docspell-restserver/docspell-server.conf + + DPKG_FORCE_CONFOLD=1 fetch_and_deploy_gh_release "docspell-joex" "eikek/docspell" "binary" "latest" "/opt/docspell" "docspell-joex_*_all.deb" + DPKG_FORCE_CONFOLD=1 fetch_and_deploy_gh_release "docspell-restserver" "eikek/docspell" "binary" "latest" "/opt/docspell" "docspell-restserver_*_all.deb" + + restore_backup + + msg_info "Starting Services" + systemctl start docspell-restserver docspell-joex + msg_ok "Started Services" + 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 "${GATEWAY}${BGN}http://${IP}:7880${CL}" diff --git a/ct/headers/discourse b/ct/headers/discourse new file mode 100644 index 000000000..640f31219 --- /dev/null +++ b/ct/headers/discourse @@ -0,0 +1,6 @@ + ____ _ + / __ \(_)_____________ __ _______________ + / / / / / ___/ ___/ __ \/ / / / ___/ ___/ _ \ + / /_/ / (__ ) /__/ /_/ / /_/ / / (__ ) __/ +/_____/_/____/\___/\____/\__,_/_/ /____/\___/ + diff --git a/ct/headers/docspell b/ct/headers/docspell new file mode 100644 index 000000000..51277d47b --- /dev/null +++ b/ct/headers/docspell @@ -0,0 +1,6 @@ + ____ ____ + / __ \____ ______________ ___ / / / + / / / / __ \/ ___/ ___/ __ \/ _ \/ / / + / /_/ / /_/ / /__(__ ) /_/ / __/ / / +/_____/\____/\___/____/ .___/\___/_/_/ + /_/ diff --git a/ct/headers/mastodon b/ct/headers/mastodon new file mode 100644 index 000000000..8724445e3 --- /dev/null +++ b/ct/headers/mastodon @@ -0,0 +1,6 @@ + __ ___ __ __ + / |/ /___ ______/ /_____ ____/ /___ ____ + / /|_/ / __ `/ ___/ __/ __ \/ __ / __ \/ __ \ + / / / / /_/ (__ ) /_/ /_/ / /_/ / /_/ / / / / +/_/ /_/\__,_/____/\__/\____/\__,_/\____/_/ /_/ + diff --git a/ct/headers/poznote b/ct/headers/poznote new file mode 100644 index 000000000..7552f6df0 --- /dev/null +++ b/ct/headers/poznote @@ -0,0 +1,6 @@ + ____ __ + / __ \____ ____ ____ ____ / /____ + / /_/ / __ \/_ / / __ \/ __ \/ __/ _ \ + / ____/ /_/ / / /_/ / / / /_/ / /_/ __/ +/_/ \____/ /___/_/ /_/\____/\__/\___/ + diff --git a/ct/headers/shiori b/ct/headers/shiori new file mode 100644 index 000000000..a20e716b9 --- /dev/null +++ b/ct/headers/shiori @@ -0,0 +1,6 @@ + _____ __ _ _ + / ___// /_ (_)___ _____(_) + \__ \/ __ \/ / __ \/ ___/ / + ___/ / / / / / /_/ / / / / +/____/_/ /_/_/\____/_/ /_/ + diff --git a/ct/mastodon.sh b/ct/mastodon.sh new file mode 100644 index 000000000..4380b3d61 --- /dev/null +++ b/ct/mastodon.sh @@ -0,0 +1,81 @@ +#!/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/mastodon/mastodon + +APP="Mastodon" +var_tags="${var_tags:-social;fediverse;activitypub}" +var_cpu="${var_cpu:-4}" +var_ram="${var_ram:-4096}" +var_disk="${var_disk:-20}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +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/mastodon ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "mastodon" "mastodon/mastodon"; then + msg_info "Stopping Services" + systemctl stop mastodon-web mastodon-sidekiq mastodon-streaming + msg_ok "Stopped Services" + + create_backup /opt/mastodon/public/system /opt/mastodon/.env.production + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "mastodon" "mastodon/mastodon" "tarball" + sed -i "s/config.force_ssl = true/config.force_ssl = ENV.fetch('LOCAL_HTTPS', 'false') == 'true'/" /opt/mastodon/config/environments/production.rb + sed -i "s/https = Rails.env.production? || ENV\['LOCAL_HTTPS'\] == 'true'/https = ENV.fetch('LOCAL_HTTPS', 'false') == 'true'/" /opt/mastodon/config/initializers/1_hosts.rb + + msg_info "Installing Ruby Dependencies" + cd /opt/mastodon + export PATH="$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH" + $STD bundle config set --local without 'development test' + $STD bundle config set --local deployment 'true' + $STD bundle install -j"$(nproc)" + msg_ok "Installed Ruby Dependencies" + + msg_info "Installing Node.js Dependencies" + $STD yarn install + msg_ok "Installed Node.js Dependencies" + + restore_backup + + msg_info "Running Database Migrations" + RAILS_ENV=production $STD bundle exec rails db:migrate + msg_ok "Ran Database Migrations" + + msg_info "Precompiling Assets" + RAILS_ENV=production SECRET_KEY_BASE_DUMMY=1 $STD bundle exec rails assets:precompile + msg_ok "Precompiled Assets" + + msg_info "Starting Services" + systemctl start mastodon-web mastodon-sidekiq mastodon-streaming + msg_ok "Started Services" + 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 "${GATEWAY}${BGN}http://${IP}${CL}" diff --git a/ct/poznote.sh b/ct/poznote.sh new file mode 100644 index 000000000..ece0c604e --- /dev/null +++ b/ct/poznote.sh @@ -0,0 +1,64 @@ +#!/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/timothepoznanski/poznote + +APP="Poznote" +var_tags="${var_tags:-notes;documentation;php}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-512}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +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/html/data ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "poznote" "timothepoznanski/poznote"; then + msg_info "Stopping Service" + systemctl stop nginx + msg_ok "Stopped Service" + + create_backup /var/www/html/data + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "poznote" "timothepoznanski/poznote" "tarball" + + msg_info "Deploying New Version" + cp -r /opt/poznote/src/. /var/www/html/ + chown -R www-data:www-data /var/www/html + msg_ok "Deployed New Version" + + restore_backup + + msg_info "Starting Service" + systemctl start nginx + 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 "${GATEWAY}${BGN}http://${IP}:8040${CL}" diff --git a/ct/shiori.sh b/ct/shiori.sh new file mode 100644 index 000000000..0c7f21f8d --- /dev/null +++ b/ct/shiori.sh @@ -0,0 +1,58 @@ +#!/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/go-shiori/shiori + +APP="Shiori" +var_tags="${var_tags:-bookmarks;read-it-later;notes}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-1024}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +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/shiori ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "shiori" "go-shiori/shiori"; then + msg_info "Stopping Service" + systemctl stop shiori + msg_ok "Stopped Service" + + create_backup /opt/shiori/data + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "shiori" "go-shiori/shiori" "prebuild" "latest" "/opt/shiori" "shiori_Linux_$(arch_resolve "x86_64" "aarch64")_*.tar.gz" + chmod +x /opt/shiori/shiori + restore_backup + + msg_info "Starting Service" + systemctl start shiori + 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 "${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/ct/vikunja.sh b/ct/vikunja.sh index 71fc47380..687c8d78d 100644 --- a/ct/vikunja.sh +++ b/ct/vikunja.sh @@ -29,9 +29,9 @@ function update_script() { exit fi - RELEASE="$( [[ -f "$HOME/.vikunja" ]] && cat "$HOME/.vikunja" 2>/dev/null || [[ -f /opt/Vikunja_version ]] && cat /opt/Vikunja_version 2>/dev/null || true)" - if [[ -z "$RELEASE" ]] || [[ "$RELEASE" == "unstable" ]] || dpkg --compare-versions "${RELEASE:-0.0.0}" lt "1.0.0"; then - msg_warn "You are upgrading from Vikunja '$RELEASE'." + INSTALLED_VERSION="$( [[ -f "$HOME/.vikunja" ]] && cat "$HOME/.vikunja" 2>/dev/null || [[ -f /opt/Vikunja_version ]] && cat /opt/Vikunja_version 2>/dev/null || true)" + if [[ -z "$INSTALLED_VERSION" ]] || [[ "$INSTALLED_VERSION" == "unstable" ]] || dpkg --compare-versions "${INSTALLED_VERSION:-0.0.0}" lt "1.0.0"; then + msg_warn "You are upgrading from Vikunja '$INSTALLED_VERSION'." msg_warn "This requires MANUAL config changes in /etc/vikunja/config.yml." msg_warn "See: https://vikunja.io/changelog/whats-new-in-vikunja-1.0.0/#config-changes" @@ -46,7 +46,8 @@ function update_script() { [[ "$CONFIRM2" =~ ^[yY]$ ]] || exit 0 fi - if check_for_gh_release "vikunja" "go-vikunja/vikunja"; then + RELEASE="v2.3.0" + if check_for_gh_release "vikunja" "go-vikunja/vikunja" "${RELEASE}" "v2.4.0 is killed at startup by the systemd SystemCallFilter shipped in the .deb (upstream go-vikunja/vikunja#3252); pinned until a fixed release is out"; then echo msg_warn "The package update may include config file changes." echo -e "${TAB}${YW}How do you want to handle /etc/vikunja/config.yml?${CL}" @@ -65,7 +66,7 @@ function update_script() { systemctl stop vikunja msg_ok "Stopped Service" - fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb" + fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "${RELEASE}" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb" $STD systemctl daemon-reload msg_info "Starting Service" diff --git a/install/discourse-install.sh b/install/discourse-install.sh new file mode 100644 index 000000000..ef3152ea6 --- /dev/null +++ b/install/discourse-install.sh @@ -0,0 +1,218 @@ +#!/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://www.discourse.org/ + +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 \ + libssl-dev \ + libreadline-dev \ + zlib1g-dev \ + libyaml-dev \ + imagemagick \ + gsfonts \ + brotli \ + nginx \ + redis-server +msg_ok "Installed Dependencies" + +PG_VERSION="17" PG_MODULES="pgvector" setup_postgresql +NODE_VERSION="24" setup_nodejs +RUBY_VERSION="3.4.4" setup_ruby + +msg_info "Configuring PostgreSQL for Discourse" +DISCOURSE_DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) +PG_HBA=$(find /etc/postgresql -name pg_hba.conf 2>/dev/null | head -n1) +sed -i 's/^local\s\+all\s\+all\s\+peer$/local all all md5/' "$PG_HBA" +$STD systemctl restart postgresql +PG_DB_NAME="discourse" PG_DB_USER="discourse" PG_DB_PASS="$DISCOURSE_DB_PASS" PG_DB_EXTENSIONS="vector" setup_postgresql_db +msg_ok "Configured PostgreSQL for Discourse" + +msg_info "Configuring Discourse" +DISCOURSE_SECRET_KEY=$(openssl rand -hex 64) +$STD git clone --depth 1 https://github.com/discourse/discourse.git /opt/discourse +cd /opt/discourse +cat </opt/discourse/.env +RAILS_ENV=production +RAILS_LOG_TO_STDOUT=true +RAILS_SERVE_STATIC_FILES=true +SECRET_KEY_BASE=${DISCOURSE_SECRET_KEY} +DISCOURSE_DB_HOST=/var/run/postgresql +DISCOURSE_DB_PORT=5432 +DISCOURSE_DB_NAME=discourse +DISCOURSE_DB_USERNAME=discourse +DISCOURSE_DB_PASSWORD=${DISCOURSE_DB_PASS} +DISCOURSE_REDIS_URL=redis://localhost:6379 +DISCOURSE_DEVELOPER_EMAILS=admin@discourse.local +DISCOURSE_HOSTNAME=${LOCAL_IP} +DISCOURSE_SMTP_ADDRESS=localhost +DISCOURSE_SMTP_PORT=25 +DISCOURSE_SMTP_AUTHENTICATION=none +DISCOURSE_NOTIFICATION_EMAIL=noreply@${LOCAL_IP} +DISCOURSE_SKIP_NEW_ACCOUNT_EMAIL=true +APP_ROOT=/opt/discourse +EOF + +mkdir -p /opt/discourse/tmp/sockets /opt/discourse/tmp/pids /opt/discourse/log +chown -R root:root /opt/discourse +chmod 755 /opt/discourse +msg_ok "Configured Discourse" + +msg_info "Installing Discourse Dependencies" +$STD systemctl enable --now redis-server +cd /opt/discourse +export PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH" +eval "$(rbenv init - bash)" 2>/dev/null || true +export RAILS_ENV=production +export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 +$STD corepack enable +$STD bundle config set --local deployment true +$STD bundle config set --local without 'test development' +$STD bundle install +$STD pnpm install +msg_ok "Installed Discourse Dependencies" + +msg_info "Setting Up Database" +cd /opt/discourse +export PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH" +eval "$(rbenv init - bash)" 2>/dev/null || true +export RAILS_ENV=production +set -a +source /opt/discourse/.env +set +a +$STD bundle exec rails db:migrate +$STD bundle exec rails db:seed +msg_ok "Set Up Database" + +msg_info "Creating Admin Account" +ADMIN_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c16) +$STD bundle exec rails runner " +user = User.new(email: 'admin@discourse.local', username: 'admin', password: '${ADMIN_PASS}') +user.active = true +user.admin = true +user.approved = true +user.save!(validate: false) +user.activate +user.grant_admin! +user.change_trust_level!(TrustLevel[4]) +SiteSetting.has_login_hint = false +SiteSetting.wizard_enabled = false +" +cat <~/discourse.creds + Discourse Credentials + Admin Username: admin + Admin Email: admin@discourse.local + Admin Password: ${ADMIN_PASS} + Database Password: ${DISCOURSE_DB_PASS} +EOF +msg_ok "Created Admin Account" + +msg_info "Building Discourse Assets" +cd /opt/discourse +export PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH" +eval "$(rbenv init - bash)" 2>/dev/null || true +export RAILS_ENV=production +set -a && source /opt/discourse/.env && set +a +$STD bundle exec rails assets:precompile +msg_ok "Built Discourse Assets" + +msg_info "Creating Services" +cat </etc/systemd/system/discourse.service +[Unit] +Description=Discourse Forum +After=network.target postgresql.service redis-server.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/discourse +EnvironmentFile=/opt/discourse/.env +Environment=PATH=/root/.rbenv/shims:/root/.rbenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ExecStart=/root/.rbenv/shims/bundle exec pitchfork -c config/pitchfork.conf.rb +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF + +cat </etc/systemd/system/discourse-sidekiq.service +[Unit] +Description=Discourse Sidekiq +After=network.target postgresql.service redis-server.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/discourse +EnvironmentFile=/opt/discourse/.env +Environment=PATH=/root/.rbenv/shims:/root/.rbenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ExecStart=/root/.rbenv/shims/bundle exec sidekiq -q critical -q default -q low -q ultra_low +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now discourse discourse-sidekiq +msg_ok "Created Services" + +msg_info "Configuring Nginx" +cat </etc/nginx/sites-available/discourse +server { + listen 80 default_server; + server_name _; + root /opt/discourse/public; + + client_max_body_size 100M; + proxy_busy_buffers_size 512k; + proxy_buffers 4 512k; + + location /assets/ { + gzip_static on; + expires max; + add_header Cache-Control public,immutable; + } + + location /uploads/ { + expires 1h; + } + + location / { + try_files \$uri @discourse; + } + + location @discourse { + 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; + proxy_set_header X-Accel-Mapping /opt/discourse/public/=/downloads/; + } +} +EOF +ln -sf /etc/nginx/sites-available/discourse /etc/nginx/sites-enabled/discourse +rm -f /etc/nginx/sites-enabled/default +$STD systemctl enable --now nginx +$STD systemctl reload nginx +msg_ok "Configured Nginx" + +motd_ssh +customize +cleanup_lxc diff --git a/install/docspell-install.sh b/install/docspell-install.sh new file mode 100644 index 000000000..122bf160d --- /dev/null +++ b/install/docspell-install.sh @@ -0,0 +1,108 @@ +#!/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://docspell.org/ + +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 \ + ocrmypdf \ + tesseract-ocr \ + tesseract-ocr-deu \ + tesseract-ocr-eng \ + unpaper \ + weasyprint \ + libreoffice-core \ + ghostscript \ + libreoffice-writer \ + libreoffice-calc \ + python3-pip \ + python3-uno \ + python3-venv + +python3 -m venv \ + --system-site-packages \ + /opt/unoserver + +$STD /opt/unoserver/bin/pip install --upgrade pip +$STD /opt/unoserver/bin/pip install unoserver +msg_ok "Installed Dependencies" + +JAVA_VERSION="21" setup_java +PG_VERSION="17" setup_postgresql +PG_DB_NAME="docspell" PG_DB_USER="docspell" setup_postgresql_db + +fetch_and_deploy_gh_release "docspell-joex" "eikek/docspell" "binary" "latest" "/opt/docspell" "docspell-joex_*_all.deb" +fetch_and_deploy_gh_release "docspell-restserver" "eikek/docspell" "binary" "latest" "/opt/docspell" "docspell-restserver_*_all.deb" + +msg_info "Configuring Docspell" +DOCSPELL_SECRET=$(openssl rand -hex 32) +DOCSPELL_ADMIN_SECRET=$(openssl rand -hex 32) +cat </etc/docspell-restserver/docspell-server.conf +docspell.server { + app-id = "rest1" + base-url = "http://${LOCAL_IP}:7880" + internal-url = "http://127.0.0.1:7880" + bind { + address = "0.0.0.0" + port = 7880 + } + auth.server-secret = "hex:${DOCSPELL_SECRET}" + admin-endpoint.secret = "${DOCSPELL_ADMIN_SECRET}" + full-text-search { + enabled = true + backend = "postgresql" + postgresql.use-default-connection = true + } + backend { + jdbc { + url = "jdbc:postgresql://127.0.0.1:5432/${PG_DB_NAME}" + user = "${PG_DB_USER}" + password = "${PG_DB_PASS}" + } + signup.mode = "open" + } +} +EOF +cat </etc/docspell-joex/docspell-joex.conf +docspell.joex { + app-id = "joex1" + base-url = "http://127.0.0.1:7878" + bind { + address = "127.0.0.1" + port = 7878 + } + jdbc { + url = "jdbc:postgresql://127.0.0.1:5432/${PG_DB_NAME}" + user = "${PG_DB_USER}" + password = "${PG_DB_PASS}" + } + full-text-search { + enabled = true + backend = "postgresql" + postgresql.use-default-connection = true + } + scheduler.pool-size = 1 + text-analysis.nlp.mode = "basic" +} +EOF +chown root:docspell /etc/docspell-joex/docspell-joex.conf /etc/docspell-restserver/docspell-server.conf +chmod 640 /etc/docspell-joex/docspell-joex.conf /etc/docspell-restserver/docspell-server.conf +msg_ok "Configured Docspell" + +msg_info "Creating Services" +systemctl enable -q --now docspell-restserver docspell-joex +msg_ok "Created Services" + +motd_ssh +customize +cleanup_lxc diff --git a/install/mastodon-install.sh b/install/mastodon-install.sh new file mode 100644 index 000000000..f3cfd2876 --- /dev/null +++ b/install/mastodon-install.sh @@ -0,0 +1,275 @@ +#!/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/mastodon/mastodon + +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 \ + git \ + imagemagick \ + libvips-tools \ + libpq-dev \ + libxslt1-dev \ + file \ + protobuf-compiler \ + pkg-config \ + autoconf \ + bison \ + build-essential \ + libssl-dev \ + libyaml-dev \ + libreadline-dev \ + zlib1g-dev \ + libffi-dev \ + libgdbm-dev \ + libidn-dev \ + libicu-dev \ + libjemalloc-dev \ + libjemalloc2 \ + redis-server \ + nginx +msg_ok "Installed Dependencies" + +setup_ffmpeg +NODE_VERSION="24" NODE_MODULE="corepack" setup_nodejs +$STD corepack enable + +PG_VERSION="17" setup_postgresql +PG_DB_NAME="mastodon_production" PG_DB_USER="mastodon" PG_DB_SKIP_ALTER_ROLE="true" setup_postgresql_db +$STD sudo -u postgres psql -c "ALTER USER mastodon CREATEDB;" + +RUBY_VERSION="4.0.5" RUBY_INSTALL_RAILS="false" setup_ruby +export PATH="$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH" + +fetch_and_deploy_gh_release "mastodon" "mastodon/mastodon" "tarball" +sed -i "s/config.force_ssl = true/config.force_ssl = ENV.fetch('LOCAL_HTTPS', 'false') == 'true'/" /opt/mastodon/config/environments/production.rb +sed -i "s/https = Rails.env.production? || ENV\['LOCAL_HTTPS'\] == 'true'/https = ENV.fetch('LOCAL_HTTPS', 'false') == 'true'/" /opt/mastodon/config/initializers/1_hosts.rb + +msg_info "Installing Ruby Dependencies" +cd /opt/mastodon +$STD bundle config set --local without 'development test' +$STD bundle config set --local deployment 'true' +$STD bundle install -j"$(nproc)" +msg_ok "Installed Ruby Dependencies" + +msg_info "Installing Node.js Dependencies" +$STD yarn install +msg_ok "Installed Node.js Dependencies" + +msg_info "Configuring Mastodon" +SECRET_KEY_BASE=$(RAILS_ENV=production bundle exec rails secret) +OTP_SECRET=$(RAILS_ENV=production bundle exec rails secret) + +VAPID_OUTPUT=$(RAILS_ENV=production bundle exec rails mastodon:webpush:generate_vapid_key 2>/dev/null) +VAPID_PRIVATE_KEY=$(echo "$VAPID_OUTPUT" | grep "^VAPID_PRIVATE_KEY=" | cut -d= -f2-) +VAPID_PUBLIC_KEY=$(echo "$VAPID_OUTPUT" | grep "^VAPID_PUBLIC_KEY=" | cut -d= -f2-) + +ENCRYPT_OUTPUT=$(RAILS_ENV=production bundle exec rails db:encryption:init 2>/dev/null) +AR_DET_KEY=$(echo "$ENCRYPT_OUTPUT" | grep "^ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=" | cut -d= -f2-) +AR_SALT=$(echo "$ENCRYPT_OUTPUT" | grep "^ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=" | cut -d= -f2-) +AR_PRIMARY=$(echo "$ENCRYPT_OUTPUT" | grep "^ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=" | cut -d= -f2-) + +mkdir -p /opt/mastodon/public/system +cat </opt/mastodon/.env.production +LOCAL_DOMAIN=${LOCAL_IP} +LOCAL_HTTPS=false +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +DB_HOST=127.0.0.1 +DB_USER=mastodon +DB_NAME=mastodon_production +DB_PASS=${PG_DB_PASS} +DB_PORT=5432 +RAILS_ENV=production +NODE_ENV=production +RAILS_SERVE_STATIC_FILES=true +BIND=0.0.0.0 +SECRET_KEY_BASE=${SECRET_KEY_BASE} +OTP_SECRET=${OTP_SECRET} +VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY} +VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY} +ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=${AR_DET_KEY} +ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=${AR_SALT} +ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=${AR_PRIMARY} +SMTP_SERVER= +SMTP_PORT=587 +SMTP_FROM_ADDRESS=notifications@${LOCAL_IP} +EOF +msg_ok "Configured Mastodon" + +msg_info "Setting up Database" +RAILS_ENV=production $STD bundle exec rails db:setup +msg_ok "Set up Database" + +msg_info "Precompiling Assets (Patience)" +RAILS_ENV=production SECRET_KEY_BASE_DUMMY=1 $STD bundle exec rails assets:precompile +msg_ok "Precompiled Assets" + +msg_info "Creating Admin Account" +if ! ADMIN_OUTPUT=$(EMAIL_DOMAIN_ALLOWLIST="${LOCAL_IP}" RAILS_ENV=production bundle exec bin/tootctl accounts create admin \ + --email "admin@${LOCAL_IP}" \ + --confirmed \ + --approve \ + --role Owner); then + msg_error "Failed to create Mastodon admin account" + exit 1 +fi +ADMIN_PASS=$(echo "$ADMIN_OUTPUT" | sed -n 's/^New password: //p') +if [[ -z "$ADMIN_PASS" ]]; then + msg_error "Failed to retrieve Mastodon admin password" + exit 1 +fi +RAILS_ENV=production $STD bundle exec bin/tootctl settings registrations approved +cat < ~/mastodon.creds + Mastodon Admin Credentials + URL: http://${LOCAL_IP} + Email: admin@${LOCAL_IP} + Password: ${ADMIN_PASS} +EOF +msg_ok "Created Admin Account" + +msg_info "Creating Services" +cat </etc/systemd/system/mastodon-web.service +[Unit] +Description=mastodon-web +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/mastodon +Environment=RAILS_ENV=production +Environment=PORT=3000 +Environment=PATH=/root/.rbenv/shims:/root/.rbenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ExecStart=/root/.rbenv/shims/bundle exec puma -C config/puma.rb +ExecReload=/bin/kill -SIGUSR1 \$MAINPID +TimeoutSec=15 +Restart=always + +[Install] +WantedBy=multi-user.target +EOF + +cat </etc/systemd/system/mastodon-sidekiq.service +[Unit] +Description=mastodon-sidekiq +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/mastodon +Environment=RAILS_ENV=production +Environment=DB_POOL=25 +Environment=PATH=/root/.rbenv/shims:/root/.rbenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ExecStart=/root/.rbenv/shims/bundle exec sidekiq -c 25 +TimeoutSec=15 +Restart=always + +[Install] +WantedBy=multi-user.target +EOF + +cat </etc/systemd/system/mastodon-streaming.service +[Unit] +Description=mastodon-streaming +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/mastodon +Environment=NODE_ENV=production +Environment=PORT=4000 +ExecStart=/usr/bin/node ./streaming +TimeoutSec=15 +Restart=always + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now mastodon-web mastodon-sidekiq mastodon-streaming +msg_ok "Created Services" + +msg_info "Configuring Nginx" +cat <<'EOF' >/etc/nginx/sites-available/mastodon +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +upstream mastodon_web { + server 127.0.0.1:3000 fail_timeout=0; +} + +upstream mastodon_streaming { + server 127.0.0.1:4000 fail_timeout=0; +} + +server { + listen 80; + server_name _; + client_max_body_size 99m; + root /opt/mastodon/public; + + gzip on; + gzip_types text/plain application/json application/javascript text/css image/svg+xml; + + location / { + try_files $uri @proxy; + } + + location ~ ^/assets/ { + add_header Cache-Control "public, max-age=2419200, must-revalidate"; + try_files $uri =404; + } + + location ^~ /api/v1/streaming { + 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; + proxy_pass http://mastodon_streaming; + proxy_buffering off; + proxy_redirect off; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + tcp_nodelay on; + } + + location @proxy { + 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; + proxy_pass http://mastodon_web; + proxy_buffering on; + proxy_redirect off; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + } +} +EOF +ln -sf /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon +rm -f /etc/nginx/sites-enabled/default +$STD nginx -t +systemctl enable -q --now redis-server +systemctl enable -q --now nginx +systemctl reload nginx +msg_ok "Configured Nginx" + +motd_ssh +customize +cleanup_lxc diff --git a/install/poznote-install.sh b/install/poznote-install.sh new file mode 100644 index 000000000..4b91388ec --- /dev/null +++ b/install/poznote-install.sh @@ -0,0 +1,63 @@ +#!/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/timothepoznanski/poznote + +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 nginx +msg_ok "Installed Dependencies" + +PHP_VERSION="8.4" PHP_FPM="YES" setup_php + +fetch_and_deploy_gh_release "poznote" "timothepoznanski/poznote" "tarball" + +msg_info "Deploying Poznote" +mkdir -p /var/www/html/data/database +cp -r /opt/poznote/src/. /var/www/html/ +touch /var/www/html/data/database/poznote.db +chown -R www-data:www-data /var/www/html +msg_ok "Deployed Poznote" + +msg_info "Configuring Nginx" +cat </etc/nginx/sites-available/poznote +server { + listen 8040; + root /var/www/html; + index index.php index.html; + + location / { + try_files \$uri \$uri/ /index.php?\$query_string; + } + + location ~ \.php$ { + include fastcgi_params; + fastcgi_pass unix:/run/php/php8.4-fpm.sock; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT \$document_root; + } + + location ~ /\.ht { + deny all; + } +} +EOF +ln -sf /etc/nginx/sites-available/poznote /etc/nginx/sites-enabled/poznote +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/shiori-install.sh b/install/shiori-install.sh new file mode 100644 index 000000000..f14e03592 --- /dev/null +++ b/install/shiori-install.sh @@ -0,0 +1,52 @@ +#!/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/go-shiori/shiori + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +fetch_and_deploy_gh_release "shiori" "go-shiori/shiori" "prebuild" "latest" "/opt/shiori" "shiori_Linux_$(arch_resolve "x86_64" "aarch64")_*.tar.gz" + +msg_info "Configuring Shiori" +mkdir -p /opt/shiori/data +SECRET_KEY=$(tr -d '-' /opt/shiori/.env +SHIORI_DIR=/opt/shiori/data +SHIORI_HTTP_PORT=8080 +SHIORI_HTTP_ADDRESS=0.0.0.0: +SHIORI_HTTP_SECRET_KEY=${SECRET_KEY} +EOF +msg_ok "Configured Shiori" + +msg_info "Creating Service" +cat </etc/systemd/system/shiori.service +[Unit] +Description=Shiori Bookmark Manager +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/shiori +EnvironmentFile=/opt/shiori/.env +ExecStart=/opt/shiori/shiori server +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now shiori +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc diff --git a/install/vikunja-install.sh b/install/vikunja-install.sh index 6495068bf..1f6707522 100644 --- a/install/vikunja-install.sh +++ b/install/vikunja-install.sh @@ -13,7 +13,8 @@ setting_up_container network_check update_os -fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb" +RELEASE="v2.3.0" +fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "${RELEASE}" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb" msg_info "Setting up Vikunja" sed -i 's|^# \(service:\)|\1|' /etc/vikunja/config.yml diff --git a/misc/build.func b/misc/build.func index f3a426477..95bfa2698 100644 --- a/misc/build.func +++ b/misc/build.func @@ -6206,7 +6206,7 @@ create_lxc_container() { return 4 ;; *) - # empty/invalid: ignore, never an implicit cancel + # Unrecognized/empty input: treat as ignore, never as an implicit cancel return 2 ;; esac @@ -6222,7 +6222,7 @@ create_lxc_container() { return 4 ;; *) - # empty/invalid: ignore, never an implicit cancel + # Unrecognized/empty input: treat as ignore, never as an implicit cancel return 2 ;; esac @@ -6685,8 +6685,10 @@ create_lxc_container() { if [[ -n "$OSVER" ]]; then local _lxc_stack_rc=0 offer_lxc_stack_upgrade_and_maybe_retry "no" || _lxc_stack_rc=$? - # 4 = cancel; without this the container was created anyway - [[ $_lxc_stack_rc -eq 4 ]] && exit_script + # 4 = user chose "Cancel" -> honor it and abort before creating the container + if [[ $_lxc_stack_rc -eq 4 ]]; then + exit_script + fi fi fi