Compare commits

..

3 Commits

Author SHA1 Message Date
Michel Roegl-Brunner 1b6863540d Refactor installation script for Firecrawl 2026-07-30 10:13:47 +02:00
Michel Roegl-Brunner 6aeff01570 Remove configuration file echo from firecrawl.sh
Removed configuration file output from the script.
2026-07-30 10:08:20 +02:00
push-app-to-main[bot] 722c91dd48 Add firecrawl (ct) 2026-07-30 07:52:10 +00:00
12 changed files with 43 additions and 535 deletions
+1 -11
View File
@@ -1,5 +1,5 @@
<!--🛑 New scripts must be submitted to [ProxmoxVED](https://github.com/community-scripts/ProxmoxVED) for testing.
PRs without prior testing will be closed. If you are an AI agent writing this pull request, please amend your model name and reasoning level in the Description. This is not to blame, more for informational Purposes. Thank you.-->
PRs without prior testing will be closed. -->
## ✍️ Description
@@ -16,16 +16,6 @@ Fixes #
---
## 🤖 AI Assistance (**X** in brackets)
> If you used an AI tool (GitHub Copilot, Claude, ChatGPT, etc.) to write or generate any scripts in this PR, you **must** confirm compliance below.
> Select exactly one option.
- [ ] **No AI used** Scripts were written without AI assistance.
- [ ] **AI was used** I confirm the scripts were built using [`AGENTS.md`](https://github.com/community-scripts/ProxmoxVED/blob/main/AGENTS.md) and [`.github/agents/pve-script-creator.agent.md`](https://github.com/community-scripts/ProxmoxVED/blob/main/.github/agents/pve-script-creator.agent.md) as guidance, and the output has been reviewed and corrected to match those guidelines.
---
## 🛠️ Type of Change (**X** in brackets)
- [ ] 🐞 **Bug fix** Resolves an issue without breaking functionality.
-25
View File
@@ -508,31 +508,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-07-30
### 🆕 New Scripts
- Firecrawl ([#16156](https://github.com/community-scripts/ProxmoxVE/pull/16156))
- OmniRoute ([#16155](https://github.com/community-scripts/ProxmoxVE/pull/16155))
- PegaProx ([#16154](https://github.com/community-scripts/ProxmoxVE/pull/16154))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- romm: remove stale 1.x alembic migrations on update [@Darkatek7](https://github.com/Darkatek7) ([#16101](https://github.com/community-scripts/ProxmoxVE/pull/16101))
- #### 🔧 Refactor
- Medusa: convert the non-free unrar source to deb822 format [@angusmaul](https://github.com/angusmaul) ([#16093](https://github.com/community-scripts/ProxmoxVE/pull/16093))
### 💾 Core
- #### ✨ New Features
- tools.func: support dynamic gitlab URL | add setup_mysql_db function [@MickLesk](https://github.com/MickLesk) ([#16166](https://github.com/community-scripts/ProxmoxVE/pull/16166))
- core: add configurable host CA inheritance during bootstrap [@MickLesk](https://github.com/MickLesk) ([#15889](https://github.com/community-scripts/ProxmoxVE/pull/15889))
## 2026-07-29
### 🚀 Updated Scripts
-6
View File
@@ -1,6 +0,0 @@
____ _ ____ __
/ __ \____ ___ ____ (_) __ \____ __ __/ /____
/ / / / __ `__ \/ __ \/ / /_/ / __ \/ / / / __/ _ \
/ /_/ / / / / / / / / / / _, _/ /_/ / /_/ / /_/ __/
\____/_/ /_/ /_/_/ /_/_/_/ |_|\____/\__,_/\__/\___/
-6
View File
@@ -1,6 +0,0 @@
____ ____
/ __ \___ ____ _____ _/ __ \_________ _ __
/ /_/ / _ \/ __ `/ __ `/ /_/ / ___/ __ \| |/_/
/ ____/ __/ /_/ / /_/ / ____/ / / /_/ /> <
/_/ \___/\__, /\__,_/_/ /_/ \____/_/|_|
/____/
-69
View File
@@ -1,69 +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/diegosouzapw/OmniRoute
APP="OmniRoute"
var_tags="${var_tags:-ai;gateway;llm}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-10}"
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/omniroute ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Checking for Updates"
local LATEST
LATEST=$(npm view omniroute version 2>/dev/null)
if [[ -z "$LATEST" ]]; then
msg_error "Could not determine latest OmniRoute version"
exit
fi
if [[ "$LATEST" == "$(omniroute --version 2>/dev/null)" ]]; then
msg_ok "Already up to date (${LATEST})"
exit
fi
msg_ok "New version available: ${LATEST}"
msg_info "Stopping Service"
systemctl stop omniroute
msg_ok "Stopped Service"
msg_info "Updating OmniRoute to ${LATEST}"
$STD npm install -g omniroute@latest
msg_ok "Updated OmniRoute to ${LATEST}"
msg_info "Starting Service"
systemctl start omniroute
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 "${TAB}${GATEWAY}${BGN}http://${IP}:20128${CL}"
echo -e "${INFO}${YW} The admin password is stored in /opt/omniroute/.env (INITIAL_PASSWORD)${CL}"
-64
View File
@@ -1,64 +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/PegaProx/project-pegaprox
APP="PegaProx"
var_tags="${var_tags:-proxmox;management}"
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_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/pegaprox ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "pegaprox" "PegaProx/project-pegaprox"; then
msg_info "Stopping Service"
systemctl stop pegaprox
msg_ok "Stopped Service"
create_backup /opt/pegaprox/config /etc/pegaprox/secret.key
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "pegaprox" "PegaProx/project-pegaprox" "tarball"
msg_info "Updating Python Environment"
$STD uv venv --python 3.12 /opt/pegaprox/venv
$STD uv pip install --python /opt/pegaprox/venv/bin/python -r /opt/pegaprox/requirements.txt
msg_ok "Updated Python Environment"
restore_backup
msg_info "Starting Service"
systemctl start pegaprox
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}https://${IP}:5000${CL}"
-4
View File
@@ -44,10 +44,6 @@ function update_script() {
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "romm" "rommapp/romm" "tarball" "latest" "/opt/romm"
find /opt/romm/backend/alembic/versions -maxdepth 1 -type f -name '1.*.py' -delete 2>/dev/null || true
find /opt/romm/backend/alembic/versions -maxdepth 1 -type f -name '2.0.0_.py' -delete 2>/dev/null || true
find /opt/romm/backend -name '__pycache__' -type d -prune -exec rm -rf {} + 2>/dev/null || true
restore_backup
msg_info "Updating ROMM"
+3 -7
View File
@@ -19,16 +19,12 @@ $STD apt install -y \
git-core \
mediainfo
cat <<EOF >/etc/apt/sources.list.d/non-free.sources
Types: deb
URIs: https://deb.debian.org/debian
Suites: trixie
Components: non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
cat <<EOF >/etc/apt/sources.list.d/non-free.list
deb https://deb.debian.org/debian trixie main contrib non-free non-free-firmware
EOF
$STD apt update
$STD apt install -y unrar
rm /etc/apt/sources.list.d/non-free.sources
rm /etc/apt/sources.list.d/non-free.list
msg_ok "Installed Dependencies"
msg_info "Installing Medusa"
-59
View File
@@ -1,59 +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/diegosouzapw/OmniRoute
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
NODE_VERSION="24" setup_nodejs
msg_info "Installing OmniRoute"
$STD npm install -g omniroute@latest
msg_ok "Installed OmniRoute"
msg_info "Configuring OmniRoute"
mkdir -p /opt/omniroute
cat <<EOF >/opt/omniroute/.env
JWT_SECRET=$(openssl rand -base64 48)
API_KEY_SECRET=$(openssl rand -hex 32)
STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)
STORAGE_ENCRYPTION_KEY_VERSION=v1
INITIAL_PASSWORD=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-20)
PORT=20128
OMNIROUTE_SERVER_HOST=0.0.0.0
EOF
chmod 600 /opt/omniroute/.env
msg_ok "Configured OmniRoute"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/omniroute.service
[Unit]
Description=OmniRoute AI Gateway
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/omniroute
Environment=DATA_DIR=/opt/omniroute
ExecStart=/usr/bin/omniroute
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now omniroute
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
-60
View File
@@ -1,60 +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/PegaProx/project-pegaprox
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 sshpass
msg_ok "Installed Dependencies"
PYTHON_VERSION="3.12" setup_uv
fetch_and_deploy_gh_release "pegaprox" "PegaProx/project-pegaprox" "tarball"
msg_info "Setting up Python Environment"
$STD uv venv --python 3.12 /opt/pegaprox/venv
$STD uv pip install --python /opt/pegaprox/venv/bin/python -r /opt/pegaprox/requirements.txt
msg_ok "Set up Python Environment"
msg_info "Generating Master Key"
mkdir -p /etc/pegaprox
cat <<EOF >/etc/pegaprox/secret.key
$(openssl rand -base64 32 | tr '+/' '-_')
EOF
chmod 600 /etc/pegaprox/secret.key
msg_ok "Generated Master Key"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/pegaprox.service
[Unit]
Description=PegaProx - Multi-Cluster Proxmox VE Management
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/pegaprox
ExecStart=/opt/pegaprox/venv/bin/python /opt/pegaprox/pegaprox_multi_cluster.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now pegaprox
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
+15 -146
View File
@@ -1130,7 +1130,6 @@ base_settings() {
APT_CACHER=${var_apt_cacher:-""}
APT_CACHER_IP=${var_apt_cacher_ip:-""}
INHERIT_HOST_CA="${var_inherit_host_ca:-no}"
# Runtime check: Verify APT cacher is reachable if configured
if [[ -n "$APT_CACHER_IP" && "$APT_CACHER" == "yes" ]]; then
@@ -1213,7 +1212,7 @@ load_vars_file() {
# Allowed var_* keys
local VAR_WHITELIST=(
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain
@@ -1410,12 +1409,6 @@ load_vars_file() {
continue
fi
;;
var_inherit_host_ca)
if [[ "$var_val" != "yes" && "$var_val" != "no" && "$var_val" != "auto" ]]; then
msg_warn "Invalid host CA inheritance value '$var_val' in $file (must be yes/no/auto), ignoring"
continue
fi
;;
var_container_storage | var_template_storage)
# Validate that the storage exists and is active on the current node
local _storage_status
@@ -1455,7 +1448,7 @@ default_var_settings() {
# Allowed var_* keys (alphabetically sorted)
# Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique)
local VAR_WHITELIST=(
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage
@@ -1538,7 +1531,6 @@ var_ssh=no
# HTTP/HTTPS proxy (optional - for networks requiring a proxy)
# var_http_proxy=http://proxy.local:8080
# var_http_no_proxy=localhost,127.0.0.1,.local
# var_inherit_host_ca=no
# Features/Tags/verbosity
var_fuse=no
@@ -1639,7 +1631,7 @@ get_app_defaults_path() {
if ! declare -p VAR_WHITELIST >/dev/null 2>&1; then
# Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique)
declare -ag VAR_WHITELIST=(
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain
@@ -1789,7 +1781,6 @@ _build_current_app_vars_tmp() {
_apt_cacher_ip="${APT_CACHER_IP:-}"
_http_proxy="${HTTP_PROXY:-${var_http_proxy:-}}"
_http_no_proxy="${HTTP_NO_PROXY:-${var_http_no_proxy:-}}"
_inherit_host_ca="${INHERIT_HOST_CA:-${var_inherit_host_ca:-no}}"
_fuse="${ENABLE_FUSE:-no}"
_tun="${ENABLE_TUN:-no}"
_gpu="${ENABLE_GPU:-no}"
@@ -1843,7 +1834,6 @@ _build_current_app_vars_tmp() {
[ -n "$_apt_cacher_ip" ] && echo "var_apt_cacher_ip=$(_sanitize_value "$_apt_cacher_ip")"
[ -n "$_http_proxy" ] && echo "var_http_proxy=$(_sanitize_value "$_http_proxy")"
[ -n "$_http_no_proxy" ] && echo "var_http_no_proxy=$(_sanitize_value "$_http_no_proxy")"
[ -n "$_inherit_host_ca" ] && echo "var_inherit_host_ca=$(_sanitize_value "$_inherit_host_ca")"
[ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")"
[ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")"
@@ -2008,7 +1998,7 @@ advanced_settings() {
TAGS="community-script${var_tags:+;${var_tags}}"
fi
local STEP=1
local MAX_STEP=31
local MAX_STEP=30
# Store values for back navigation - inherit from var_* app defaults
local _ct_type="${var_unprivileged:-1}"
@@ -2030,7 +2020,6 @@ advanced_settings() {
local _apt_cacher_ip="${var_apt_cacher_ip:-}"
local _http_proxy="${var_http_proxy:-}"
local _http_no_proxy="${var_http_no_proxy:-}"
local _inherit_host_ca="${var_inherit_host_ca:-no}"
local _mtu="${var_mtu:-}"
local _sd="${var_searchdomain:-}"
local _ns="${var_ns:-}"
@@ -2860,47 +2849,9 @@ advanced_settings() {
;;
# ═══════════════════════════════════════════════════════════════════════════
# STEP 25: Host CA Inheritance
# STEP 25: Container Timezone
# ═══════════════════════════════════════════════════════════════════════════
25)
local host_ca_count=0
local host_ca_dir="/usr/local/share/ca-certificates"
local cert
shopt -s nullglob
for cert in "$host_ca_dir"/*.crt; do
host_ca_count=$((host_ca_count + 1))
done
shopt -u nullglob
if [[ $host_ca_count -eq 0 ]]; then
_inherit_host_ca="no"
((STEP++))
continue
fi
local host_ca_default_flag="--defaultno"
[[ "$_inherit_host_ca" == "yes" ]] && host_ca_default_flag=""
if whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "HOST CA INHERITANCE" \
--ok-button "Next" --cancel-button "Back" \
$host_ca_default_flag \
--yesno "\nInherit host CA certificates into this container?\n\nDetected on host: ${host_ca_count} certificate(s) in:\n${host_ca_dir}\n\nRecommended for private PKI / TLS-inspection environments.\n\n(App default: ${var_inherit_host_ca:-no})" 16 72; then
_inherit_host_ca="yes"
else
if [ $? -eq 1 ]; then
_inherit_host_ca="no"
else
((STEP--))
continue
fi
fi
((STEP++))
;;
# ═══════════════════════════════════════════════════════════════════════════
# STEP 26: Container Timezone
# ═══════════════════════════════════════════════════════════════════════════
26)
local tz_hint="$_ct_timezone"
[[ -z "$tz_hint" ]] && tz_hint="(empty - will use host timezone)"
@@ -2923,9 +2874,9 @@ advanced_settings() {
;;
# ═══════════════════════════════════════════════════════════════════════════
# STEP 27: Container Protection
# STEP 26: Container Protection
# ═══════════════════════════════════════════════════════════════════════════
27)
26)
local protect_default_flag="--defaultno"
[[ "$_protect_ct" == "yes" || "$_protect_ct" == "1" ]] && protect_default_flag=""
@@ -2947,9 +2898,9 @@ advanced_settings() {
;;
# ═══════════════════════════════════════════════════════════════════════════
# STEP 28: Device Node Creation (mknod)
# STEP 27: Device Node Creation (mknod)
# ═══════════════════════════════════════════════════════════════════════════
28)
27)
local mknod_default_flag="--defaultno"
[[ "$_enable_mknod" == "1" ]] && mknod_default_flag=""
@@ -2971,9 +2922,9 @@ advanced_settings() {
;;
# ═══════════════════════════════════════════════════════════════════════════
# STEP 29: Mount Filesystems
# STEP 28: Mount Filesystems
# ═══════════════════════════════════════════════════════════════════════════
29)
28)
local mount_hint=""
[[ -n "$_mount_fs" ]] && mount_hint="$_mount_fs" || mount_hint="(none)"
@@ -2994,9 +2945,9 @@ advanced_settings() {
;;
# ═══════════════════════════════════════════════════════════════════════════
# STEP 30: Optional host-side post-install hook (path on the Proxmox HOST)
# STEP 29: Optional host-side post-install hook (path on the Proxmox HOST)
# ═══════════════════════════════════════════════════════════════════════════
30)
29)
local _hook_prompt="Optional: absolute path to a *.sh file ON THE PROXMOX HOST.
It runs as root on the HOST (NOT in the LXC) after the container
@@ -3046,9 +2997,9 @@ Leave empty to skip."
;;
# ═══════════════════════════════════════════════════════════════════════════
# STEP 31: Verbose Mode & Confirmation
# STEP 30: Verbose Mode & Confirmation
# ═══════════════════════════════════════════════════════════════════════════
31)
30)
local verbose_default_flag="--defaultno"
[[ "$_verbose" == "yes" ]] && verbose_default_flag=""
@@ -3077,7 +3028,6 @@ Leave empty to skip."
local apt_display="${_apt_cacher:-no}"
[[ "$_apt_cacher" == "yes" && -n "$_apt_cacher_ip" ]] && apt_display="$_apt_cacher_ip"
local http_proxy_display="${_http_proxy:-(none)}"
local inherit_ca_display="${_inherit_host_ca:-no}"
local post_install_display="${_post_install:-(none)}"
local post_install_warn=""
@@ -3108,7 +3058,6 @@ Advanced:
Timezone: $tz_display
APT Cacher: $apt_display
HTTP Proxy: $http_proxy_display
Inherit Host CAs: $inherit_ca_display
Verbose: $_verbose
Post-Install Script: ${post_install_display}${post_install_warn}"
@@ -3154,7 +3103,6 @@ Advanced:
APT_CACHER_IP="$_apt_cacher_ip"
HTTP_PROXY="$_http_proxy"
HTTP_NO_PROXY="$_http_no_proxy"
INHERIT_HOST_CA="$_inherit_host_ca"
VERBOSE="$_verbose"
var_post_install="$_post_install"
@@ -3173,7 +3121,6 @@ Advanced:
var_sdn_vnet="$_sdn_vnet"
var_http_proxy="$_http_proxy"
var_http_no_proxy="$_http_no_proxy"
var_inherit_host_ca="$_inherit_host_ca"
# Format optional values
[[ -n "$_mtu" ]] && MTU=",mtu=$_mtu" || MTU=""
@@ -4213,83 +4160,6 @@ EOF
msg_ok "Applied HTTP proxy in container"
}
# ------------------------------------------------------------------------------
# _apply_host_ca_certs_in_container()
#
# - Copies administrator-provided CA certificates from the Proxmox host into the
# container before base package bootstrap
# - Source: /usr/local/share/ca-certificates/*.crt (Debian convention)
# - Refreshes the container trust store when update-ca-certificates is available
# - No-op when no host certificates are present; failures are non-fatal
# ------------------------------------------------------------------------------
_apply_host_ca_certs_in_container() {
local host_ca_dir="/usr/local/share/ca-certificates"
[[ -z "${CTID:-}" ]] && return 0
local inherit_host_ca="${INHERIT_HOST_CA:-${var_inherit_host_ca:-no}}"
local -a host_certs=()
local cert
shopt -s nullglob
for cert in "$host_ca_dir"/*.crt; do
host_certs+=("$cert")
done
shopt -u nullglob
[[ ${#host_certs[@]} -eq 0 ]] && return 0
# Opt-in only: copy host CA certs solely when explicitly enabled.
# Any other value (no/auto/unset) is a silent no-op to preserve LXC isolation.
case "${inherit_host_ca,,}" in
yes | true | 1 | on) ;;
*)
return 0
;;
esac
msg_info "Inheriting host CA certificates into container"
local found=${#host_certs[@]}
local copied=0
local skipped=0
local cert_name
pct exec "$CTID" -- mkdir -p /usr/local/share/ca-certificates >/dev/null 2>&1 || {
msg_warn "Failed to create CA certificate directory in container"
return 0
}
for cert in "${host_certs[@]}"; do
cert_name="$(basename "$cert")"
if [[ ! -r "$cert" || "$cert_name" != *.crt ]]; then
msg_warn "Skipping invalid or unreadable host CA certificate: ${cert_name}"
skipped=$((skipped + 1))
continue
fi
if pct push "$CTID" "$cert" "/usr/local/share/ca-certificates/${cert_name}" >/dev/null 2>&1; then
pct exec "$CTID" -- chmod 644 "/usr/local/share/ca-certificates/${cert_name}" >/dev/null 2>&1 || true
copied=$((copied + 1))
else
msg_warn "Failed to push host CA certificate: ${cert_name}"
skipped=$((skipped + 1))
fi
done
if [[ $copied -eq 0 ]]; then
msg_warn "No host CA certificates were copied (${found} found, ${skipped} skipped)"
return 0
fi
local refresh_shell="bash"
[[ "$var_os" == "alpine" ]] && refresh_shell="ash"
if pct exec "$CTID" -- "$refresh_shell" -c 'command -v update-ca-certificates >/dev/null 2>&1 && update-ca-certificates' >/dev/null 2>&1; then
msg_ok "Inherited ${copied} host CA certificate(s) and updated trust store (${skipped} skipped)"
else
msg_warn "Copied ${copied} host CA certificate(s), but trust store update failed or update-ca-certificates is unavailable (${skipped} skipped)"
fi
}
# ------------------------------------------------------------------------------
# build_container()
#
@@ -4919,7 +4789,6 @@ EOF
local install_exit_code=0
_apply_http_proxy_in_container
_apply_host_ca_certs_in_container
# Continue with standard container setup
if [ "$var_os" == "alpine" ]; then
+24 -78
View File
@@ -2736,8 +2736,7 @@ get_latest_gl_tag() {
local repo_encoded
repo_encoded=$(printf '%s' "$repo" | sed 's|/|%2F|g')
local gitlab_url="${GITLAB_URL:-https://gitlab.com}"
local api_base="${gitlab_url}/api/v4/projects/${repo_encoded}/repository/tags"
local api_base="https://gitlab.com/api/v4/projects/${repo_encoded}/repository/tags"
local api_timeout="--connect-timeout 10 --max-time 60"
local header=()
@@ -2819,7 +2818,6 @@ get_latest_gl_tag() {
# Notes:
# - Supports CLEAN_INSTALL=1 to wipe target before extracting
# - Supports GITLAB_TOKEN for private/rate-limited projects
# - Supports GITLAB_URL for self-hosted GitLab (default: https://gitlab.com)
# - For repos that only publish tags, not formal GitLab Releases
# (use fetch_and_deploy_gl_release for proper Releases with assets)
# ------------------------------------------------------------------------------
@@ -2863,9 +2861,8 @@ fetch_and_deploy_gl_tag() {
repo_encoded=$(printf '%s' "$repo" | sed 's|/|%2F|g')
# GitLab source tarball URL (no release needed, works for any tag).
local gitlab_url="${GITLAB_URL:-https://gitlab.com}"
local version_safe="${resolved_tag//\//-}"
local tarball_url="${gitlab_url}/${repo}/-/archive/${resolved_tag}/${app_lc}-${version_safe}.tar.gz"
local tarball_url="https://gitlab.com/${repo}/-/archive/${resolved_tag}/${app_lc}-${version_safe}.tar.gz"
local tmpdir
tmpdir=$(mktemp -d) || return 1
@@ -6950,60 +6947,6 @@ setup_mariadb_db() {
export MARIADB_DB_PASS
}
# ------------------------------------------------------------------------------
# Creates a MySQL database and user (for apps that require MySQL, not MariaDB).
#
# Description:
# - Creates database, user and grants using the mysql root socket login
# - The user is created with host '%' because MySQL treats 'localhost'
# (socket) and '127.0.0.1' (TCP) as distinct hosts; apps connecting over
# TCP to 127.0.0.1 would not match a 'localhost' account. mysql-server
# binds to 127.0.0.1 by default, so '%' stays local-only.
#
# Variables:
# MYSQL_DB_NAME - Database name (required)
# MYSQL_DB_USER - Database user (required)
# MYSQL_DB_PASS - Password (optional, generated if unset)
#
# Exports:
# MYSQL_DB_NAME, MYSQL_DB_USER, MYSQL_DB_PASS
#
# Example:
# MYSQL_DB_NAME="fleet" MYSQL_DB_USER="fleet" setup_mysql_db
# ------------------------------------------------------------------------------
setup_mysql_db() {
if [[ -z "${MYSQL_DB_NAME:-}" || -z "${MYSQL_DB_USER:-}" ]]; then
msg_error "MYSQL_DB_NAME and MYSQL_DB_USER must be set before calling setup_mysql_db"
return 65
fi
if [[ -z "${MYSQL_DB_PASS:-}" ]]; then
MYSQL_DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
fi
msg_info "Setting up MySQL Database"
$STD mysql -u root -e "CREATE DATABASE \`${MYSQL_DB_NAME//\`/\`\`}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
$STD mysql -u root -e "CREATE USER '${MYSQL_DB_USER//\'/\'\'}'@'%' IDENTIFIED BY '${MYSQL_DB_PASS//\'/\'\'}';"
$STD mysql -u root -e "GRANT ALL ON \`${MYSQL_DB_NAME//\`/\`\`}\`.* TO '${MYSQL_DB_USER//\'/\'\'}'@'%';"
$STD mysql -u root -e "FLUSH PRIVILEGES;"
local app_name="${APPLICATION,,}"
local CREDS_FILE="${MYSQL_DB_CREDS_FILE:-${HOME}/${app_name}.creds}"
{
echo "MySQL Credentials"
echo "Database: $MYSQL_DB_NAME"
echo "User: $MYSQL_DB_USER"
echo "Password: $MYSQL_DB_PASS"
} >>"$CREDS_FILE"
msg_ok "Set up MySQL Database"
export MYSQL_DB_NAME
export MYSQL_DB_USER
export MYSQL_DB_PASS
}
# ------------------------------------------------------------------------------
# Installs or updates MeiliSearch search engine.
#
@@ -8252,17 +8195,22 @@ EOF
# ------------------------------------------------------------------------------
get_php_fpm_socket() {
local sock
if [[ -n "${PHP_VERSION:-}" && -S "/run/php/php${PHP_VERSION}-fpm.sock" ]]; then
echo "/run/php/php${PHP_VERSION}-fpm.sock"
return 0
fi
sock=$(find /run/php -maxdepth 1 -name "php*-fpm.sock" -type s 2>/dev/null | sort -V | tail -1)
if [[ -z "$sock" ]]; then
msg_error "No active PHP-FPM socket found under /run/php"
return 1
fi
echo "$sock"
}
# ------------------------------------------------------------------------------
# Enables an nginx site, validates the configuration and reloads the service.
#
@@ -8284,20 +8232,25 @@ get_php_fpm_socket() {
# ------------------------------------------------------------------------------
nginx_enable_site() {
local site="${1:-}"
if [[ -z "$site" ]]; then
msg_error "nginx_enable_site: no site name given"
return 1
fi
if [[ ! -f "/etc/nginx/sites-available/${site}" ]]; then
msg_error "nginx site config not found: /etc/nginx/sites-available/${site}"
return 1
fi
rm -f /etc/nginx/sites-enabled/default /etc/nginx/sites-available/default
ln -sf "/etc/nginx/sites-available/${site}" "/etc/nginx/sites-enabled/${site}"
if ! $STD nginx -t; then
msg_error "nginx configuration test failed for site '${site}'"
return 1
fi
$STD systemctl enable -q nginx
safe_service_restart nginx
}
@@ -9494,12 +9447,11 @@ get_latest_gitlab_release() {
local temp_file
temp_file=$(mktemp)
local gitlab_url="${GITLAB_URL:-https://gitlab.com}"
local http_code
http_code=$(curl --connect-timeout 10 --max-time 30 -sSL \
-w "%{http_code}" -o "$temp_file" \
"${header[@]}" \
"${gitlab_url}/api/v4/projects/$repo_encoded/releases?per_page=1&order_by=released_at&sort=desc" 2>/dev/null) || true
"https://gitlab.com/api/v4/projects/$repo_encoded/releases?per_page=1&order_by=released_at&sort=desc" 2>/dev/null) || true
if [[ "$http_code" != "200" ]]; then
rm -f "$temp_file"
@@ -9541,7 +9493,6 @@ get_latest_gitlab_release() {
# Notes:
# - Requires `jq` (auto-installed if missing)
# - Supports GITLAB_TOKEN env var for private/rate-limited repos
# - Supports GITLAB_URL for self-hosted GitLab (default: https://gitlab.com)
# - Does not modify anything, only checks version state
# ------------------------------------------------------------------------------
check_for_gl_release() {
@@ -9553,15 +9504,11 @@ check_for_gl_release() {
local app_lc="${app,,}"
local current_file="$HOME/.${app_lc}"
local gitlab_url="${GITLAB_URL:-https://gitlab.com}"
local gitlab_hostname="${gitlab_url#*://}"
gitlab_hostname="${gitlab_hostname%%/*}"
msg_info "Checking for update: ${app}"
# DNS check
if ! getent hosts "$gitlab_hostname" >/dev/null 2>&1; then
msg_error "Network error: cannot resolve $gitlab_hostname"
if ! getent hosts gitlab.com >/dev/null 2>&1; then
msg_error "Network error: cannot resolve gitlab.com"
return 6
fi
@@ -9584,7 +9531,7 @@ check_for_gl_release() {
local pinned_encoded="${pinned_version_in//\//%2F}"
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o "$gl_check_json" \
"${header[@]}" \
"${gitlab_url}/api/v4/projects/$repo_encoded/releases/$pinned_encoded" 2>/dev/null) || true
"https://gitlab.com/api/v4/projects/$repo_encoded/releases/$pinned_encoded" 2>/dev/null) || true
if [[ "$http_code" == "200" ]] && [[ -s "$gl_check_json" ]]; then
releases_json="[$(<"$gl_check_json")]"
fi
@@ -9595,7 +9542,7 @@ check_for_gl_release() {
if [[ -z "$releases_json" ]]; then
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o "$gl_check_json" \
"${header[@]}" \
"${gitlab_url}/api/v4/projects/$repo_encoded/releases?per_page=100&order_by=released_at&sort=desc" 2>/dev/null) || true
"https://gitlab.com/api/v4/projects/$repo_encoded/releases?per_page=100&order_by=released_at&sort=desc" 2>/dev/null) || true
if [[ "$http_code" == "200" ]] && [[ -s "$gl_check_json" ]]; then
releases_json=$(<"$gl_check_json")
@@ -9619,7 +9566,7 @@ check_for_gl_release() {
return 22
elif [[ "$http_code" == "000" || -z "$http_code" ]]; then
msg_error "GitLab API connection failed (no response)."
msg_error "Check your network/DNS: curl -sSL ${gitlab_url}/api/v4/version"
msg_error "Check your network/DNS: curl -sSL https://gitlab.com/api/v4/version"
rm -f "$gl_check_json"
return 7
else
@@ -9864,8 +9811,7 @@ fetch_and_deploy_gl_release() {
local repo_encoded
repo_encoded=$(printf '%s' "$repo" | sed 's|/|%2F|g')
local gitlab_url="${GITLAB_URL:-https://gitlab.com}"
local api_base="${gitlab_url}/api/v4/projects/$repo_encoded/releases"
local api_base="https://gitlab.com/api/v4/projects/$repo_encoded/releases"
local api_url
if [[ "$version" != "latest" ]]; then
api_url="$api_base/$version"
@@ -9914,7 +9860,7 @@ fetch_and_deploy_gl_release() {
msg_error " export GITLAB_TOKEN=\"glpat-your_token_here\""
elif [[ "$http_code" == "000" || -z "$http_code" ]]; then
msg_error "GitLab API connection failed (no response)."
msg_error "Check your network/DNS: curl -sSL ${gitlab_url}/api/v4/version"
msg_error "Check your network/DNS: curl -sSL https://gitlab.com/api/v4/version"
else
msg_error "Failed to fetch release metadata (HTTP $http_code)"
fi
@@ -9969,7 +9915,7 @@ fetch_and_deploy_gl_release() {
### Tarball Mode ###
if [[ "$mode" == "tarball" || "$mode" == "source" ]]; then
local direct_tarball_url="${gitlab_url}/$repo/-/archive/$tag_name/${app_lc}-${version_safe}.tar.gz"
local direct_tarball_url="https://gitlab.com/$repo/-/archive/$tag_name/${app_lc}-${version_safe}.tar.gz"
filename="${app_lc}-${version_safe}.tar.gz"
_download_source_tarball "$direct_tarball_url" "$tmpdir/$filename" "${header[@]}" || {
@@ -10017,7 +9963,7 @@ fetch_and_deploy_gl_release() {
if [[ -z "$url_match" ]]; then
local fallback_json
if fallback_json=$(_gl_scan_older_releases "$repo" "$repo_encoded" "$gitlab_url" "binary" "$asset_pattern" "$tag_name"); then
if fallback_json=$(_gl_scan_older_releases "$repo" "$repo_encoded" "https://gitlab.com" "binary" "$asset_pattern" "$tag_name"); then
json="$fallback_json"
tag_name=$(echo "$json" | jq -r '.tag_name // empty')
[[ "$tag_name" =~ ^v[0-9] ]] && version="${tag_name:1}" || version="$tag_name"
@@ -10089,7 +10035,7 @@ fetch_and_deploy_gl_release() {
if [[ -z "$asset_url" ]]; then
local fallback_json
if fallback_json=$(_gl_scan_older_releases "$repo" "$repo_encoded" "$gitlab_url" "prebuild" "$pattern" "$tag_name"); then
if fallback_json=$(_gl_scan_older_releases "$repo" "$repo_encoded" "https://gitlab.com" "prebuild" "$pattern" "$tag_name"); then
json="$fallback_json"
tag_name=$(echo "$json" | jq -r '.tag_name // empty')
[[ "$tag_name" =~ ^v[0-9] ]] && version="${tag_name:1}" || version="$tag_name"
@@ -10142,7 +10088,7 @@ fetch_and_deploy_gl_release() {
if [[ -z "$asset_url" ]]; then
local fallback_json
if fallback_json=$(_gl_scan_older_releases "$repo" "$repo_encoded" "$gitlab_url" "singlefile" "$pattern" "$tag_name"); then
if fallback_json=$(_gl_scan_older_releases "$repo" "$repo_encoded" "https://gitlab.com" "singlefile" "$pattern" "$tag_name"); then
json="$fallback_json"
tag_name=$(echo "$json" | jq -r '.tag_name // empty')
[[ "$tag_name" =~ ^v[0-9] ]] && version="${tag_name:1}" || version="$tag_name"