mirror of
https://github.com/community-scripts/ProxmoxVE-Local.git
synced 2026-07-22 21:43:51 -04:00
Allow using local copies of helper/install scripts during development and forward environment variables and a GitHub token through the UI and websocket layer. Changes: - scripts/core/alpine-install.func & scripts/core/install.func: try to load misc/tools.func from the local scripts directory before falling back to downloading from GitHub; improved error messaging on failure. - scripts/core/build.func: resolve SCRIPT_DIR, prefer local alpine/install function files and export their contents to FUNCTIONS_FILE_PATH; fall back to remote download if local files are missing; use local install scripts for lxc-attach when available (fallback to remote). Adjusted dev MOTD path to source from /tmp. - src/app/_components/ConfigurationModal.tsx: added a password input for var_github_token (passed as GITHUB_TOKEN to mitigate API rate limits). - src/server/api/websocket/handler.ts: websocket handler now accepts an envVars object and forwards it into startScriptExecution so environment variables from the client can be supplied to script runs. Overall this improves local development workflows and enables passing custom env vars and a GitHub token to scripts.
250 lines
9.0 KiB
Plaintext
250 lines
9.0 KiB
Plaintext
# Copyright (c) 2021-2026 community-scripts ORG
|
|
# Author: tteck (tteckster)
|
|
# Co-Author: MickLesk
|
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
|
|
if ! command -v curl >/dev/null 2>&1; then
|
|
apk update && apk add curl >/dev/null 2>&1
|
|
fi
|
|
source "$(dirname "${BASH_SOURCE[0]}")/core.func"
|
|
source "$(dirname "${BASH_SOURCE[0]}")/error-handler.func"
|
|
load_functions
|
|
catch_errors
|
|
|
|
# Persist diagnostics setting inside container (exported from build.func)
|
|
# so addon scripts running later can find the user's choice
|
|
if [[ ! -f /usr/local/community-scripts/diagnostics ]]; then
|
|
mkdir -p /usr/local/community-scripts
|
|
echo "DIAGNOSTICS=${DIAGNOSTICS:-no}" >/usr/local/community-scripts/diagnostics
|
|
fi
|
|
|
|
# Get LXC IP address (must be called INSIDE container, after network is up)
|
|
get_lxc_ip
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# post_progress_to_api()
|
|
#
|
|
# - Lightweight progress ping from inside the container
|
|
# - Updates the existing telemetry record status
|
|
# - Arguments:
|
|
# * $1: status (optional, default: "configuring")
|
|
# - Signals that the installation is actively progressing (not stuck)
|
|
# - Fire-and-forget: never blocks or fails the script
|
|
# - Only executes if DIAGNOSTICS=yes and RANDOM_UUID is set
|
|
# ------------------------------------------------------------------------------
|
|
post_progress_to_api() {
|
|
command -v curl &>/dev/null || return 0
|
|
[[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0
|
|
[[ -z "${RANDOM_UUID:-}" ]] && return 0
|
|
|
|
local progress_status="${1:-configuring}"
|
|
|
|
curl -fsS -m 5 -X POST "https://telemetry.community-scripts.org/telemetry" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"lxc\",\"nsapp\":\"${app:-unknown}\",\"status\":\"${progress_status}\"}" &>/dev/null || true
|
|
}
|
|
|
|
# This function enables IPv6 if it's not disabled and sets verbose mode
|
|
verb_ip6() {
|
|
set_std_mode # Set STD mode based on VERBOSE
|
|
|
|
if [ "${IPV6_METHOD:-}" = "disable" ]; then
|
|
msg_info "Disabling IPv6 (this may affect some services)"
|
|
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
|
|
$STD sysctl -w net.ipv6.conf.default.disable_ipv6=1
|
|
$STD sysctl -w net.ipv6.conf.lo.disable_ipv6=1
|
|
mkdir -p /etc/sysctl.d
|
|
$STD tee /etc/sysctl.d/99-disable-ipv6.conf >/dev/null <<EOF
|
|
net.ipv6.conf.all.disable_ipv6 = 1
|
|
net.ipv6.conf.default.disable_ipv6 = 1
|
|
net.ipv6.conf.lo.disable_ipv6 = 1
|
|
EOF
|
|
$STD rc-update add sysctl default
|
|
msg_ok "Disabled IPv6"
|
|
fi
|
|
}
|
|
|
|
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
|
|
setting_up_container() {
|
|
msg_info "Setting up Container OS"
|
|
while [ $i -gt 0 ]; do
|
|
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
|
|
break
|
|
fi
|
|
echo 1>&2 -en "${CROSS}${RD} No Network! "
|
|
sleep $RETRY_EVERY
|
|
i=$((i - 1))
|
|
done
|
|
|
|
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then
|
|
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
|
|
echo -e "${NETWORK}Check Network Settings"
|
|
exit 121
|
|
fi
|
|
msg_ok "Set up Container OS"
|
|
msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}"
|
|
post_progress_to_api
|
|
}
|
|
|
|
# This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected
|
|
network_check() {
|
|
set +e
|
|
trap - ERR
|
|
ipv4_connected=false
|
|
|
|
# Check IPv4 connectivity to Cloudflare, Google & Quad9 DNS servers
|
|
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ping -c 1 -W 1 8.8.8.8 &>/dev/null || ping -c 1 -W 1 9.9.9.9 &>/dev/null; then
|
|
msg_ok "IPv4 Internet Connected"
|
|
ipv4_connected=true
|
|
else
|
|
msg_error "IPv4 Internet Not Connected"
|
|
fi
|
|
|
|
if [[ $ipv4_connected == false ]]; then
|
|
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
|
|
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
|
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
|
|
else
|
|
echo -e "${NETWORK}Check Network Settings"
|
|
exit 122
|
|
fi
|
|
fi
|
|
|
|
# DNS resolution checks for GitHub-related domains
|
|
GIT_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com" "git.community-scripts.org")
|
|
GIT_STATUS="Git DNS:"
|
|
DNS_FAILED=false
|
|
|
|
for HOST in "${GIT_HOSTS[@]}"; do
|
|
RESOLVEDIP=$(getent hosts "$HOST" | awk '{ print $1 }' | grep -E '(^([0-9]{1,3}\.){3}[0-9]{1,3}$)|(^[a-fA-F0-9:]+$)' | head -n1)
|
|
if [[ -z "$RESOLVEDIP" ]]; then
|
|
GIT_STATUS+="$HOST:($DNSFAIL)"
|
|
DNS_FAILED=true
|
|
else
|
|
GIT_STATUS+=" $HOST:($DNSOK)"
|
|
fi
|
|
done
|
|
|
|
if [[ "$DNS_FAILED" == true ]]; then
|
|
fatal "$GIT_STATUS"
|
|
else
|
|
msg_ok "$GIT_STATUS"
|
|
fi
|
|
|
|
set -e
|
|
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
|
}
|
|
|
|
# This function updates the Container OS by running apk upgrade with mirror fallback
|
|
update_os() {
|
|
msg_info "Updating Container OS"
|
|
if ! $STD apk -U upgrade; then
|
|
msg_warn "apk update failed (dl-cdn.alpinelinux.org), trying alternate mirrors..."
|
|
local alpine_mirrors="mirror.init7.net ftp.halifax.rwth-aachen.de mirrors.edge.kernel.org alpine.mirror.wearetriple.com mirror.leaseweb.com uk.alpinelinux.org dl-2.alpinelinux.org dl-4.alpinelinux.org"
|
|
local apk_ok=false
|
|
for m in $(printf '%s\n' $alpine_mirrors | shuf); do
|
|
if timeout 2 bash -c "echo >/dev/tcp/$m/80" 2>/dev/null; then
|
|
msg_custom "${INFO}" "${YW}" "Attempting mirror: ${m}"
|
|
cat <<EOF >/etc/apk/repositories
|
|
http://$m/alpine/latest-stable/main
|
|
http://$m/alpine/latest-stable/community
|
|
EOF
|
|
if $STD apk -U upgrade; then
|
|
msg_ok "CDN set to ${m}: tests passed"
|
|
apk_ok=true
|
|
break
|
|
else
|
|
msg_warn "Mirror ${m} failed"
|
|
fi
|
|
fi
|
|
done
|
|
if [[ "$apk_ok" != true ]]; then
|
|
msg_error "All Alpine mirrors failed. Check network or try again later."
|
|
exit 1
|
|
fi
|
|
fi
|
|
local tools_content
|
|
local _tools_local
|
|
_tools_local="$(dirname "${BASH_SOURCE[0]}")/tools.func"
|
|
if [[ -f "$_tools_local" ]]; then
|
|
tools_content=$(cat "$_tools_local") || {
|
|
msg_error "Failed to load tools.func from local"
|
|
exit 115
|
|
}
|
|
else
|
|
tools_content=$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) || {
|
|
msg_error "Failed to download tools.func"
|
|
exit 115
|
|
}
|
|
fi
|
|
source /dev/stdin <<<"$tools_content"
|
|
if ! declare -f fetch_and_deploy_gh_release >/dev/null 2>&1; then
|
|
msg_error "tools.func loaded but incomplete — missing expected functions"
|
|
exit 115
|
|
fi
|
|
msg_ok "Updated Container OS"
|
|
post_progress_to_api
|
|
}
|
|
|
|
# This function modifies the message of the day (motd) and SSH settings
|
|
motd_ssh() {
|
|
echo "export TERM='xterm-256color'" >>/root/.bashrc
|
|
|
|
PROFILE_FILE="/etc/profile.d/00_lxc-details.sh"
|
|
echo "echo -e \"\"" >"$PROFILE_FILE"
|
|
echo -e "echo -e \"${BOLD}${APPLICATION} LXC Container${CL}"\" >>"$PROFILE_FILE"
|
|
echo -e "echo -e \"${TAB}${GATEWAY}${YW} Provided by: ${GN}community-scripts ORG ${YW}| GitHub: ${GN}https://github.com/community-scripts/ProxmoxVE${CL}\"" >>"$PROFILE_FILE"
|
|
echo "echo \"\"" >>"$PROFILE_FILE"
|
|
echo -e "echo -e \"${TAB}${OS}${YW} OS: ${GN}\$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '\"') - Version: \$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '\"')${CL}\"" >>"$PROFILE_FILE"
|
|
echo -e "echo -e \"${TAB}${HOSTNAME}${YW} Hostname: ${GN}\$(hostname)${CL}\"" >>"$PROFILE_FILE"
|
|
echo -e "echo -e \"${TAB}${INFO}${YW} IP Address: ${GN}\$(ip -4 addr show eth0 | awk '/inet / {print \$2}' | cut -d/ -f1 | head -n 1)${CL}\"" >>"$PROFILE_FILE"
|
|
|
|
# Configure SSH if enabled
|
|
if [[ "${SSH_ROOT}" == "yes" ]]; then
|
|
# Enable sshd service
|
|
$STD rc-update add sshd
|
|
# Allow root login via SSH
|
|
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
|
|
# Start the sshd service
|
|
$STD /etc/init.d/sshd start
|
|
fi
|
|
post_progress_to_api
|
|
}
|
|
|
|
# Validate Timezone for some LXC's
|
|
validate_tz() {
|
|
[[ -f "/usr/share/zoneinfo/$1" ]]
|
|
}
|
|
|
|
# This function customizes the container and enables passwordless login for the root user
|
|
customize() {
|
|
if [[ "$PASSWORD" == "" ]]; then
|
|
msg_info "Customizing Container"
|
|
passwd -d root >/dev/null 2>&1
|
|
|
|
# Ensure agetty is available
|
|
apk add --no-cache --force-broken-world util-linux >/dev/null 2>&1
|
|
|
|
# Create persistent autologin boot script
|
|
mkdir -p /etc/local.d
|
|
cat <<'EOF' >/etc/local.d/autologin.start
|
|
#!/bin/sh
|
|
sed -i 's|^tty1::respawn:.*|tty1::respawn:/sbin/agetty --autologin root --noclear tty1 38400 linux|' /etc/inittab
|
|
kill -HUP 1
|
|
EOF
|
|
touch /root/.hushlogin
|
|
|
|
chmod +x /etc/local.d/autologin.start
|
|
rc-update add local >/dev/null 2>&1
|
|
|
|
# Apply autologin immediately for current session
|
|
/etc/local.d/autologin.start
|
|
|
|
msg_ok "Customized Container"
|
|
fi
|
|
|
|
echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update
|
|
chmod +x /usr/bin/update
|
|
post_progress_to_api
|
|
}
|