This commit is contained in:
CanbiZ 2025-11-24 11:42:00 +01:00
parent e147c848bb
commit bea8814994
4 changed files with 816 additions and 499 deletions

View File

@ -47,17 +47,7 @@ variables() {
METHOD="default" # sets the METHOD variable to "default", used for the API call. METHOD="default" # sets the METHOD variable to "default", used for the API call.
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable. RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable.
SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"}
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"
# Parse dev_mode early
parse_dev_mode
# Setup persistent log directory if logs mode active
if [[ "${DEV_MODE_LOGS:-false}" == "true" ]]; then
mkdir -p /var/log/community-scripts
BUILD_LOG="/var/log/community-scripts/create-lxc-${SESSION_ID}-$(date +%Y%m%d_%H%M%S).log"
fi
# Get Proxmox VE version and kernel version # Get Proxmox VE version and kernel version
if command -v pveversion >/dev/null 2>&1; then if command -v pveversion >/dev/null 2>&1; then
@ -535,35 +525,6 @@ base_settings() {
TAGS="community-script,${var_tags:-}" TAGS="community-script,${var_tags:-}"
ENABLE_FUSE=${var_fuse:-"${1:-no}"} ENABLE_FUSE=${var_fuse:-"${1:-no}"}
ENABLE_TUN=${var_tun:-"${1:-no}"} ENABLE_TUN=${var_tun:-"${1:-no}"}
ENABLE_NESTING=${var_nesting:-"${1:-1}"}
ENABLE_KEYCTL=${var_keyctl:-"${1:-0}"}
ALLOW_MOUNT_FS=${var_mount_fs:-""}
ENABLE_MKNOD=${var_mknod:-"${1:-0}"}
PROTECT_CT=${var_protection:-"${1:-no}"}
CT_TIMEZONE=${var_timezone:-""}
# Normalize feature flags to 0/1 immediately (pct requires numeric values, not yes/no)
# This must happen here before any usage of these variables
case "${ENABLE_NESTING,,}" in
yes | true) ENABLE_NESTING="1" ;;
no | false) ENABLE_NESTING="0" ;;
esac
case "${ENABLE_KEYCTL,,}" in
yes | true) ENABLE_KEYCTL="1" ;;
no | false) ENABLE_KEYCTL="0" ;;
esac
case "${ENABLE_MKNOD,,}" in
yes | true) ENABLE_MKNOD="1" ;;
no | false) ENABLE_MKNOD="0" ;;
esac
case "${ENABLE_FUSE,,}" in
yes | true) ENABLE_FUSE="1" ;;
no | false) ENABLE_FUSE="0" ;;
esac
case "${PROTECT_CT,,}" in
yes | true) PROTECT_CT="1" ;;
no | false) PROTECT_CT="0" ;;
esac
# Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts # Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts
if [ -z "$var_os" ]; then if [ -z "$var_os" ]; then
@ -587,9 +548,9 @@ default_var_settings() {
# Allowed var_* keys (alphabetically sorted) # Allowed var_* keys (alphabetically sorted)
# Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique) # Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique)
local VAR_WHITELIST=( local VAR_WHITELIST=(
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_keyctl var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_gateway var_hostname var_ipv6_method var_mac var_mtu
var_net var_nesting var_ns var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_net var_ns var_pw var_ram var_tags var_tun var_unprivileged
var_verbose var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_verbose var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage
) )
@ -667,14 +628,6 @@ var_ssh=no
# Features/Tags/verbosity # Features/Tags/verbosity
var_fuse=no var_fuse=no
var_tun=no var_tun=no
# Advanced Settings (Proxmox-official features)
var_nesting=1 # Allow nesting (required for Docker/LXC in CT)
var_keyctl=0 # Allow keyctl() - needed for Docker (systemd-networkd workaround)
var_mknod=0 # Allow device node creation (requires kernel 5.3+, experimental)
var_mount_fs= # Allow specific filesystems: nfs,fuse,ext4,etc (leave empty for defaults)
var_protection=no # Prevent accidental deletion of container
var_timezone= # Container timezone (e.g. Europe/Berlin, leave empty for host timezone)
var_tags=community-script var_tags=community-script
var_verbose=no var_verbose=no
@ -941,12 +894,6 @@ _build_current_app_vars_tmp() {
_apt_cacher_ip="${APT_CACHER_IP:-}" _apt_cacher_ip="${APT_CACHER_IP:-}"
_fuse="${ENABLE_FUSE:-no}" _fuse="${ENABLE_FUSE:-no}"
_tun="${ENABLE_TUN:-no}" _tun="${ENABLE_TUN:-no}"
_nesting="${ENABLE_NESTING:-1}"
_keyctl="${ENABLE_KEYCTL:-0}"
_mknod="${ENABLE_MKNOD:-0}"
_mount_fs="${ALLOW_MOUNT_FS:-}"
_protect="${PROTECT_CT:-no}"
_timezone="${CT_TIMEZONE:-}"
_tags="${TAGS:-}" _tags="${TAGS:-}"
_verbose="${VERBOSE:-no}" _verbose="${VERBOSE:-no}"
@ -990,12 +937,6 @@ _build_current_app_vars_tmp() {
[ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")" [ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")"
[ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")" [ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")"
[ -n "$_nesting" ] && echo "var_nesting=$(_sanitize_value "$_nesting")"
[ -n "$_keyctl" ] && echo "var_keyctl=$(_sanitize_value "$_keyctl")"
[ -n "$_mknod" ] && echo "var_mknod=$(_sanitize_value "$_mknod")"
[ -n "$_mount_fs" ] && echo "var_mount_fs=$(_sanitize_value "$_mount_fs")"
[ -n "$_protect" ] && echo "var_protection=$(_sanitize_value "$_protect")"
[ -n "$_timezone" ] && echo "var_timezone=$(_sanitize_value "$_timezone")"
[ -n "$_tags" ] && echo "var_tags=$(_sanitize_value "$_tags")" [ -n "$_tags" ] && echo "var_tags=$(_sanitize_value "$_tags")"
[ -n "$_verbose" ] && echo "var_verbose=$(_sanitize_value "$_verbose")" [ -n "$_verbose" ] && echo "var_verbose=$(_sanitize_value "$_verbose")"
@ -1578,51 +1519,6 @@ advanced_settings() {
configure_ssh_settings configure_ssh_settings
export SSH_KEYS_FILE export SSH_KEYS_FILE
echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}"
# Advanced Settings - Proxmox Features
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS" --yesno "Configure Advanced Proxmox Features?" 10 58); then
# keyctl: for Docker support
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Enable keyctl()" --yesno "Allow keyctl() system calls?\n\nNeeded for: Docker inside container, systemd-networkd\nDefault: No (not needed for most applications)" 10 58); then
ENABLE_KEYCTL="1"
else
ENABLE_KEYCTL="0"
fi
echo -e "${SEARCH}${BOLD}${DGN}Allow keyctl(): ${BGN}$ENABLE_KEYCTL${CL}"
# mknod: device node creation
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Enable mknod()" --yesno "Allow device node creation?\n\nNeeded for: Complex device management (experimental, kernel 5.3+)\nDefault: No (rarely needed)" 10 58); then
ENABLE_MKNOD="1"
else
ENABLE_MKNOD="0"
fi
echo -e "${SEARCH}${BOLD}${DGN}Allow mknod(): ${BGN}$ENABLE_MKNOD${CL}"
# mount: specific filesystems
if MOUNT_FS=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allow specific filesystems (e.g., nfs,fuse,ext4)\nLeave blank for defaults" 8 58 "$ALLOW_MOUNT_FS" --title "Mount Filesystems" 3>&1 1>&2 2>&3); then
ALLOW_MOUNT_FS="$MOUNT_FS"
[ -z "$ALLOW_MOUNT_FS" ] && ALLOW_MOUNT_FS="(defaults)"
else
exit_script
fi
echo -e "${SEARCH}${BOLD}${DGN}Mount Filesystems: ${BGN}$ALLOW_MOUNT_FS${CL}"
# Container protection
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Protection Flag" --yesno "Prevent accidental deletion?\n\nIf enabled, container cannot be deleted or its disk modified\nDefault: No" 10 58); then
PROTECT_CT="yes"
else
PROTECT_CT="no"
fi
echo -e "${SEARCH}${BOLD}${DGN}Container Protection: ${BGN}$PROTECT_CT${CL}"
# Container timezone
if CT_TIMEZONE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set container timezone (e.g., Europe/Berlin)\nLeave blank to use host timezone" 8 58 "$CT_TIMEZONE" --title "Container Timezone" 3>&1 1>&2 2>&3); then
[ -z "$CT_TIMEZONE" ] && CT_TIMEZONE="(host)"
else
exit_script
fi
echo -e "${SEARCH}${BOLD}${DGN}Container Timezone: ${BGN}$CT_TIMEZONE${CL}"
fi
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then
ENABLE_FUSE="yes" ENABLE_FUSE="yes"
else else
@ -1795,16 +1691,7 @@ install_script() {
fi fi
NEXTID=$(pvesh get /cluster/nextid) NEXTID=$(pvesh get /cluster/nextid)
# Get timezone using timedatectl (Debian 13+ compatible)
# Fallback to /etc/timezone for older systems
if command -v timedatectl >/dev/null 2>&1; then
timezone=$(timedatectl show --value --property=Timezone 2>/dev/null || echo "UTC")
elif [ -f /etc/timezone ]; then
timezone=$(cat /etc/timezone) timezone=$(cat /etc/timezone)
else
timezone="UTC"
fi
# Show APP Header # Show APP Header
header_info header_info
@ -1932,12 +1819,13 @@ settings_menu() {
local settings_items=( local settings_items=(
"1" "Manage API-Diagnostic Setting" "1" "Manage API-Diagnostic Setting"
"2" "Edit Default.vars" "2" "Edit Default.vars"
"3" "Edit Default Storage"
) )
if [ -f "$(get_app_defaults_path)" ]; then if [ -f "$(get_app_defaults_path)" ]; then
settings_items+=("3" "Edit App.vars for ${APP}") settings_items+=("4" "Edit App.vars for ${APP}")
settings_items+=("4" "Exit") settings_items+=("5" "Exit")
else else
settings_items+=("3" "Exit") settings_items+=("4" "Exit")
fi fi
local choice local choice
@ -2298,34 +2186,14 @@ build_container() {
none) ;; none) ;;
esac esac
# Build FEATURES array with advanced settings if [ "$CT_TYPE" == "1" ]; then
# Note: All feature flags are already normalized to 0/1 in default_settings() FEATURES="keyctl=1,nesting=1"
# Proxmox requires each feature as a separate parameter, not comma-separated string else
FEATURES_ARRAY=() FEATURES="nesting=1"
FEATURES_ARRAY+=("nesting=${ENABLE_NESTING}")
# keyctl: needed for Docker inside containers (systemd-networkd workaround)
# Typically needed for unprivileged containers with Docker
if [ "$CT_TYPE" == "1" ] || [ "$ENABLE_KEYCTL" == "1" ]; then
FEATURES_ARRAY+=("keyctl=1")
fi fi
# mknod: allow device node creation (requires kernel 5.3+, experimental) if [ "$ENABLE_FUSE" == "yes" ]; then
if [ "$ENABLE_MKNOD" == "1" ]; then FEATURES="$FEATURES,fuse=1"
FEATURES_ARRAY+=("mknod=1")
fi
# FUSE: required for rclone, mergerfs, AppImage, etc.
if [ "$ENABLE_FUSE" == "1" ]; then
FEATURES_ARRAY+=("fuse=1")
fi
# mount: allow specific filesystems (e.g., nfs, ext4, etc.)
# Format: mount=fstype1;fstype2;fstype3 (semicolon-separated, not comma!)
if [ -n "$ALLOW_MOUNT_FS" ]; then
# Replace commas with semicolons for proper pct syntax
ALLOW_MOUNT_FS_FORMATTED="${ALLOW_MOUNT_FS//,/;}"
FEATURES_ARRAY+=("mount=$ALLOW_MOUNT_FS_FORMATTED")
fi fi
TEMP_DIR=$(mktemp -d) TEMP_DIR=$(mktemp -d)
@ -2338,16 +2206,6 @@ build_container() {
export DIAGNOSTICS="$DIAGNOSTICS" export DIAGNOSTICS="$DIAGNOSTICS"
export RANDOM_UUID="$RANDOM_UUID" export RANDOM_UUID="$RANDOM_UUID"
export SESSION_ID="$SESSION_ID" export SESSION_ID="$SESSION_ID"
export BUILD_LOG="$BUILD_LOG"
export INSTALL_LOG="/root/.install-${SESSION_ID}.log"
export dev_mode="${dev_mode:-}"
export DEV_MODE_MOTD="${DEV_MODE_MOTD:-false}"
export DEV_MODE_KEEP="${DEV_MODE_KEEP:-false}"
export DEV_MODE_TRACE="${DEV_MODE_TRACE:-false}"
export DEV_MODE_PAUSE="${DEV_MODE_PAUSE:-false}"
export DEV_MODE_BREAKPOINT="${DEV_MODE_BREAKPOINT:-false}"
export DEV_MODE_LOGS="${DEV_MODE_LOGS:-false}"
export DEV_MODE_DRYRUN="${DEV_MODE_DRYRUN:-false}"
export CACHER="$APT_CACHER" export CACHER="$APT_CACHER"
export CACHER_IP="$APT_CACHER_IP" export CACHER_IP="$APT_CACHER_IP"
export tz="$timezone" export tz="$timezone"
@ -2361,59 +2219,22 @@ build_container() {
export CTTYPE="$CT_TYPE" export CTTYPE="$CT_TYPE"
export ENABLE_FUSE="$ENABLE_FUSE" export ENABLE_FUSE="$ENABLE_FUSE"
export ENABLE_TUN="$ENABLE_TUN" export ENABLE_TUN="$ENABLE_TUN"
export ENABLE_NESTING="$ENABLE_NESTING"
export ENABLE_KEYCTL="$ENABLE_KEYCTL"
export ENABLE_MKNOD="$ENABLE_MKNOD"
export ALLOW_MOUNT_FS="$ALLOW_MOUNT_FS"
export PROTECT_CT="$PROTECT_CT"
export CT_TIMEZONE="$CT_TIMEZONE"
export PCT_OSTYPE="$var_os" export PCT_OSTYPE="$var_os"
export PCT_OSVERSION="$var_version" export PCT_OSVERSION="$var_version"
export PCT_DISK_SIZE="$DISK_SIZE" export PCT_DISK_SIZE="$DISK_SIZE"
export PCT_OPTIONS="
# Build PCT_OPTIONS array (not string) for proper parameter handling -features $FEATURES
PCT_OPTIONS=() -hostname $HN
-tags $TAGS
# Add features - each as separate -features parameter $SD
for feature in "${FEATURES_ARRAY[@]}"; do $NS
PCT_OPTIONS+=("-features" "$feature") $NET_STRING
done -onboot 1
-cores $CORE_COUNT
PCT_OPTIONS+=("-hostname" "$HN") -memory $RAM_SIZE
PCT_OPTIONS+=("-tags" "$TAGS") -unprivileged $CT_TYPE
$PW
if [ -n "$SD" ]; then "
PCT_OPTIONS+=($SD) # Storage device flags (already formatted)
fi
if [ -n "$NS" ]; then
PCT_OPTIONS+=($NS) # Nameserver flags (already formatted)
fi
# Network configuration (single string with all network parameters)
PCT_OPTIONS+=($NET_STRING)
PCT_OPTIONS+=("-onboot" "1")
PCT_OPTIONS+=("-cores" "$CORE_COUNT")
PCT_OPTIONS+=("-memory" "$RAM_SIZE")
PCT_OPTIONS+=("-unprivileged" "$CT_TYPE")
# Protection flag
if [ "$PROTECT_CT" == "1" ]; then
PCT_OPTIONS+=("-protection" "1")
fi
# Timezone flag
if [ -n "$CT_TIMEZONE" ]; then
PCT_OPTIONS+=("-timezone" "$CT_TIMEZONE")
fi
# Password flag (already formatted as "-password xxx")
if [ -n "$PW" ]; then
PCT_OPTIONS+=($PW)
fi
export PCT_OPTIONS
export TEMPLATE_STORAGE="${var_template_storage:-}" export TEMPLATE_STORAGE="${var_template_storage:-}"
export CONTAINER_STORAGE="${var_container_storage:-}" export CONTAINER_STORAGE="${var_container_storage:-}"
create_lxc_container || exit $? create_lxc_container || exit $?
@ -2588,13 +2409,20 @@ EOF
[[ "$selected_gpu" == "INTEL" ]] && devices=("${INTEL_DEVICES[@]}") [[ "$selected_gpu" == "INTEL" ]] && devices=("${INTEL_DEVICES[@]}")
[[ "$selected_gpu" == "AMD" ]] && devices=("${AMD_DEVICES[@]}") [[ "$selected_gpu" == "AMD" ]] && devices=("${AMD_DEVICES[@]}")
# Use pct set to add devices with proper dev0/dev1 format # Add lxc.mount.entry for each device
# GIDs will be detected and set after container starts
local dev_index=0
for dev in "${devices[@]}"; do for dev in "${devices[@]}"; do
# Add to config using pct set (will be visible in GUI) echo "lxc.mount.entry: $dev $dev none bind,optional,create=file" >>"$LXC_CONFIG"
echo "dev${dev_index}: ${dev},gid=44" >>"$LXC_CONFIG"
dev_index=$((dev_index + 1)) if [[ "$CT_TYPE" == "0" ]]; then
# Privileged container - also add cgroup allows
local major minor
major=$(stat -c '%t' "$dev" 2>/dev/null || echo "0")
minor=$(stat -c '%T' "$dev" 2>/dev/null || echo "0")
if [[ "$major" != "0" && "$minor" != "0" ]]; then
echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG"
fi
fi
done done
export GPU_TYPE="$selected_gpu" export GPU_TYPE="$selected_gpu"
@ -2607,11 +2435,20 @@ EOF
return 0 return 0
fi fi
# Use pct set for NVIDIA devices # Add lxc.mount.entry for each NVIDIA device
local dev_index=0
for dev in "${NVIDIA_DEVICES[@]}"; do for dev in "${NVIDIA_DEVICES[@]}"; do
echo "dev${dev_index}: ${dev},gid=44" >>"$LXC_CONFIG" echo "lxc.mount.entry: $dev $dev none bind,optional,create=file" >>"$LXC_CONFIG"
dev_index=$((dev_index + 1))
if [[ "$CT_TYPE" == "0" ]]; then
# Privileged container - also add cgroup allows
local major minor
major=$(stat -c '%t' "$dev" 2>/dev/null || echo "0")
minor=$(stat -c '%T' "$dev" 2>/dev/null || echo "0")
if [[ "$major" != "0" && "$minor" != "0" ]]; then
echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG"
fi
fi
done done
export GPU_TYPE="NVIDIA" export GPU_TYPE="NVIDIA"
@ -2723,9 +2560,7 @@ EOF'
fi fi
if pct exec "$CTID" -- test -e "/usr/share/zoneinfo/$tz"; then if pct exec "$CTID" -- test -e "/usr/share/zoneinfo/$tz"; then
# Set timezone using symlink (Debian 13+ compatible) pct exec "$CTID" -- bash -c "tz='$tz'; echo \"\$tz\" >/etc/timezone && ln -sf \"/usr/share/zoneinfo/\$tz\" /etc/localtime"
# Create /etc/timezone for backwards compatibility with older scripts
pct exec "$CTID" -- bash -c "tz='$tz'; ln -sf \"/usr/share/zoneinfo/\$tz\" /etc/localtime && echo \"\$tz\" >/etc/timezone || true"
else else
msg_warn "Skipping timezone setup zone '$tz' not found in container" msg_warn "Skipping timezone setup zone '$tz' not found in container"
fi fi
@ -2742,105 +2577,13 @@ EOF'
install_ssh_keys_into_ct install_ssh_keys_into_ct
# Run application installer # Run application installer
# NOTE: We disable error handling here because: if ! lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/${var_install}.sh)"; then
# 1. Container errors are caught by error_handler INSIDE container local exit_code=$?
# 2. Container creates flag file with exit code # Try to copy installation log from container before exiting
# 3. We read flag file and handle cleanup manually below
# 4. We DON'T want host error_handler to fire for lxc-attach command itself
set +Eeuo pipefail # Disable ALL error handling temporarily
trap - ERR # Remove ERR trap completely
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/${var_install}.sh)"
local lxc_exit=$?
set -Eeuo pipefail # Re-enable error handling
trap 'error_handler' ERR # Restore ERR trap
# Check for error flag file in container (more reliable than lxc-attach exit code)
local install_exit_code=0
if [[ -n "${SESSION_ID:-}" ]]; then
local error_flag="/root/.install-${SESSION_ID}.failed"
if pct exec "$CTID" -- test -f "$error_flag" 2>/dev/null; then
install_exit_code=$(pct exec "$CTID" -- cat "$error_flag" 2>/dev/null || echo "1")
pct exec "$CTID" -- rm -f "$error_flag" 2>/dev/null || true
fi
fi
# Fallback to lxc-attach exit code if no flag file
if [[ $install_exit_code -eq 0 && $lxc_exit -ne 0 ]]; then
install_exit_code=$lxc_exit
fi
# Installation failed?
if [[ $install_exit_code -ne 0 ]]; then
msg_error "Installation failed in container ${CTID} (exit code: ${install_exit_code})"
# Copy both logs from container before potential deletion
local build_log_copied=false
local install_log_copied=false
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then
# Copy BUILD_LOG (creation log) if it exists pct pull "$CTID" "/root/.install-${SESSION_ID}.log" "/tmp/install-${SESSION_ID}.log" 2>/dev/null || true
if [[ -f "${BUILD_LOG}" ]]; then
cp "${BUILD_LOG}" "/tmp/create-lxc-${CTID}-${SESSION_ID}.log" 2>/dev/null && build_log_copied=true
fi fi
exit $exit_code
# Copy INSTALL_LOG from container
if pct pull "$CTID" "/root/.install-${SESSION_ID}.log" "/tmp/install-lxc-${CTID}-${SESSION_ID}.log" 2>/dev/null; then
install_log_copied=true
fi
# Show available logs
echo ""
[[ "$build_log_copied" == true ]] && echo -e "${GN}✔${CL} Container creation log: ${BL}/tmp/create-lxc-${CTID}-${SESSION_ID}.log${CL}"
[[ "$install_log_copied" == true ]] && echo -e "${GN}✔${CL} Installation log: ${BL}/tmp/install-lxc-${CTID}-${SESSION_ID}.log${CL}"
fi
# Dev mode: Keep container or open breakpoint shell
if [[ "${DEV_MODE_KEEP:-false}" == "true" ]]; then
msg_dev "Keep mode active - container ${CTID} preserved"
return 0
elif [[ "${DEV_MODE_BREAKPOINT:-false}" == "true" ]]; then
msg_dev "Breakpoint mode - opening shell in container ${CTID}"
echo -e "${YW}Type 'exit' to return to host${CL}"
pct enter "$CTID"
echo ""
echo -en "${YW}Container ${CTID} still running. Remove now? (y/N): ${CL}"
if read -r response && [[ "$response" =~ ^[Yy]$ ]]; then
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
msg_ok "Container ${CTID} removed"
else
msg_dev "Container ${CTID} kept for debugging"
fi
exit $install_exit_code
fi
# Prompt user for cleanup with 60s timeout (plain echo - no msg_info to avoid spinner)
echo ""
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
if read -t 60 -r response; then
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
# Remove container
echo -e "\n${TAB}${HOLD}${YW}Removing container ${CTID}${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}"
elif [[ "$response" =~ ^[Nn]$ ]]; then
echo -e "\n${TAB}${YW}Container ${CTID} kept for debugging${CL}"
fi
else
# Timeout - auto-remove
echo -e "\n${YW}No response - auto-removing container${CL}"
echo -e "${TAB}${HOLD}${YW}Removing container ${CTID}${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}"
fi
exit $install_exit_code
fi fi
} }
@ -2922,40 +2665,79 @@ fix_gpu_gids() {
return 0 return 0
fi fi
# Silent operation to avoid spinner conflicts
msg_custom "🔧" "${BL}" "Detecting and setting correct GPU group IDs" msg_custom "🔧" "${BL}" "Detecting and setting correct GPU group IDs"
# Get actual GIDs from container # Ermittle die tatsächlichen GIDs aus dem Container
local video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3") local video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3")
local render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3") local render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3")
# Create groups if they don't exist # Fallbacks wenn Gruppen nicht existieren
if [[ -z "$video_gid" ]]; then if [[ -z "$video_gid" ]]; then
pct exec "$CTID" -- sh -c "groupadd -r video 2>/dev/null || true" >/dev/null 2>&1 # Versuche die video Gruppe zu erstellen
pct exec "$CTID" -- sh -c "groupadd -r video 2>/dev/null || true"
video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3") video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3")
[[ -z "$video_gid" ]] && video_gid="44" [[ -z "$video_gid" ]] && video_gid="44" # Ultimate fallback
fi fi
if [[ -z "$render_gid" ]]; then if [[ -z "$render_gid" ]]; then
pct exec "$CTID" -- sh -c "groupadd -r render 2>/dev/null || true" >/dev/null 2>&1 # Versuche die render Gruppe zu erstellen
pct exec "$CTID" -- sh -c "groupadd -r render 2>/dev/null || true"
render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3") render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3")
[[ -z "$render_gid" ]] && render_gid="104" [[ -z "$render_gid" ]] && render_gid="104" # Ultimate fallback
fi fi
# Stop container to update config msg_custom "" "${DGN}" "Container GIDs detected - video:${video_gid}, render:${render_gid}"
# Prüfe ob die GIDs von den Defaults abweichen
local need_update=0
if [[ "$video_gid" != "44" ]] || [[ "$render_gid" != "104" ]]; then
need_update=1
fi
if [[ $need_update -eq 1 ]]; then
msg_custom "🔄" "${YW}" "Updating device GIDs in container config"
# Stoppe Container für Config-Update
pct stop "$CTID" >/dev/null 2>&1 pct stop "$CTID" >/dev/null 2>&1
sleep 1
# Update dev entries with correct GIDs # Update die dev Einträge mit korrekten GIDs
sed -i.bak -E "s|(dev[0-9]+: /dev/dri/renderD[0-9]+),gid=[0-9]+|\1,gid=${render_gid}|g" "$LXC_CONFIG" # Backup der Config
sed -i -E "s|(dev[0-9]+: /dev/dri/card[0-9]+),gid=[0-9]+|\1,gid=${video_gid}|g" "$LXC_CONFIG" cp "$LXC_CONFIG" "${LXC_CONFIG}.bak"
# Restart container # Parse und update jeden dev Eintrag
while IFS= read -r line; do
if [[ "$line" =~ ^dev[0-9]+: ]]; then
# Extract device path
local device_path=$(echo "$line" | sed -E 's/^dev[0-9]+: ([^,]+).*/\1/')
local dev_num=$(echo "$line" | sed -E 's/^(dev[0-9]+):.*/\1/')
if [[ "$device_path" =~ renderD ]]; then
# RenderD device - use render GID
echo "${dev_num}: ${device_path},gid=${render_gid}"
elif [[ "$device_path" =~ card ]]; then
# Card device - use video GID
echo "${dev_num}: ${device_path},gid=${video_gid}"
else
# Keep original line
echo "$line"
fi
else
# Keep non-dev lines
echo "$line"
fi
done <"$LXC_CONFIG" >"${LXC_CONFIG}.new"
mv "${LXC_CONFIG}.new" "$LXC_CONFIG"
# Starte Container wieder
pct start "$CTID" >/dev/null 2>&1 pct start "$CTID" >/dev/null 2>&1
sleep 2 sleep 3
msg_ok "GPU passthrough configured (video:${video_gid}, render:${render_gid})" msg_ok "Device GIDs updated successfully"
else
# For privileged containers: also fix permissions inside container msg_ok "Device GIDs are already correct"
fi
if [[ "$CT_TYPE" == "0" ]]; then if [[ "$CT_TYPE" == "0" ]]; then
pct exec "$CTID" -- bash -c " pct exec "$CTID" -- bash -c "
if [ -d /dev/dri ]; then if [ -d /dev/dri ]; then
@ -3121,7 +2903,7 @@ create_lxc_container() {
case "${_ans,,}" in case "${_ans,,}" in
y | yes) y | yes)
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)" msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
if $STD apt-get update && $STD apt-get install -y --only-upgrade pve-container lxc-pve; then if apt-get update -qq >/dev/null && apt-get install -y --only-upgrade pve-container lxc-pve >/dev/null; then
msg_ok "LXC stack upgraded." msg_ok "LXC stack upgraded."
if [[ "$do_retry" == "yes" ]]; then if [[ "$do_retry" == "yes" ]]; then
msg_info "Retrying container creation after upgrade" msg_info "Retrying container creation after upgrade"
@ -3566,13 +3348,13 @@ create_lxc_container() {
exit 211 exit 211
} }
LOGFILE="/tmp/pct_create_${CTID}_$(date +%Y%m%d_%H%M%S)_${SESSION_ID}.log" LOGFILE="/tmp/pct_create_${CTID}.log"
msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}" msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}"
msg_debug "Logfile: $LOGFILE" msg_debug "Logfile: $LOGFILE"
# First attempt # First attempt
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >"$LOGFILE" 2>&1; then if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >"$LOGFILE" 2>&1; then
msg_debug "Container creation failed on ${TEMPLATE_STORAGE}. Validating template..." msg_error "Container creation failed on ${TEMPLATE_STORAGE}. Checking template..."
# Validate template file # Validate template file
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
@ -3591,48 +3373,49 @@ create_lxc_container() {
# Retry after repair # Retry after repair
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
# Fallback to local storage if not already on local # Fallback to local storage
if [[ "$TEMPLATE_STORAGE" != "local" ]]; then if [[ "$TEMPLATE_STORAGE" != "local" ]]; then
msg_info "Retrying container creation with fallback to local storage..." msg_warn "Retrying container creation with fallback to local storage..."
LOCAL_TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE" LOCAL_TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then
msg_info "Downloading template to local..." msg_info "Downloading template to local..."
pveam download local "$TEMPLATE" >/dev/null 2>&1 pveam download local "$TEMPLATE" >/dev/null 2>&1
fi fi
if ! pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then if pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
# Local fallback also failed - check for LXC stack version issue
if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically."
offer_lxc_stack_upgrade_and_maybe_retry "yes"
rc=$?
case $rc in
0) : ;; # success - container created, continue
2)
echo "Upgrade was declined. Please update and re-run:
apt update && apt install --only-upgrade pve-container lxc-pve"
exit 231
;;
3)
echo "Upgrade and/or retry failed. Please inspect: $LOGFILE"
exit 231
;;
esac
else
msg_error "Container creation failed. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x
pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" 2>&1 | tee -a "$LOGFILE"
set +x
fi
exit 209
fi
else
msg_ok "Container successfully created using local fallback." msg_ok "Container successfully created using local fallback."
else
# --- Dynamic stack upgrade + auto-retry on the well-known error pattern ---
if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically."
offer_lxc_stack_upgrade_and_maybe_retry "yes"
rc=$?
case $rc in
0) : ;; # success - container created, continue
2)
echo "Upgrade was declined. Please update and re-run:
apt update && apt install --only-upgrade pve-container lxc-pve"
exit 231
;;
3)
echo "Upgrade and/or retry failed. Please inspect: $LOGFILE"
exit 231
;;
esac
else
msg_error "Container creation failed even with local fallback. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x
bash -x -c "pct create $CTID local:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}" 2>&1 | tee -a "$LOGFILE"
set +x
fi
exit 209
fi
fi fi
else else
# Already on local storage and still failed - check LXC stack version msg_error "Container creation failed on local storage. See $LOGFILE"
# --- Dynamic stack upgrade + auto-retry on the well-known error pattern ---
if grep -qiE 'unsupported .* version' "$LOGFILE"; then if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template." echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
@ -3655,14 +3438,12 @@ create_lxc_container() {
msg_error "Container creation failed. See $LOGFILE" msg_error "Container creation failed. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x set -x
pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" 2>&1 | tee -a "$LOGFILE" bash -x -c "pct create $CTID local:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}" 2>&1 | tee -a "$LOGFILE"
set +x set +x
fi fi
exit 209 exit 209
fi fi
fi fi
else
msg_ok "Container successfully created after template repair."
fi fi
fi fi
@ -3679,9 +3460,6 @@ create_lxc_container() {
} }
msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created." msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created."
# Report container creation to API
post_to_api
} }
# ============================================================================== # ==============================================================================

View File

@ -47,7 +47,17 @@ variables() {
METHOD="default" # sets the METHOD variable to "default", used for the API call. METHOD="default" # sets the METHOD variable to "default", used for the API call.
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable. RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable.
SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"} BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"
# Parse dev_mode early
parse_dev_mode
# Setup persistent log directory if logs mode active
if [[ "${DEV_MODE_LOGS:-false}" == "true" ]]; then
mkdir -p /var/log/community-scripts
BUILD_LOG="/var/log/community-scripts/create-lxc-${SESSION_ID}-$(date +%Y%m%d_%H%M%S).log"
fi
# Get Proxmox VE version and kernel version # Get Proxmox VE version and kernel version
if command -v pveversion >/dev/null 2>&1; then if command -v pveversion >/dev/null 2>&1; then
@ -525,6 +535,35 @@ base_settings() {
TAGS="community-script,${var_tags:-}" TAGS="community-script,${var_tags:-}"
ENABLE_FUSE=${var_fuse:-"${1:-no}"} ENABLE_FUSE=${var_fuse:-"${1:-no}"}
ENABLE_TUN=${var_tun:-"${1:-no}"} ENABLE_TUN=${var_tun:-"${1:-no}"}
ENABLE_NESTING=${var_nesting:-"${1:-1}"}
ENABLE_KEYCTL=${var_keyctl:-"${1:-0}"}
ALLOW_MOUNT_FS=${var_mount_fs:-""}
ENABLE_MKNOD=${var_mknod:-"${1:-0}"}
PROTECT_CT=${var_protection:-"${1:-no}"}
CT_TIMEZONE=${var_timezone:-""}
# Normalize feature flags to 0/1 immediately (pct requires numeric values, not yes/no)
# This must happen here before any usage of these variables
case "${ENABLE_NESTING,,}" in
yes | true) ENABLE_NESTING="1" ;;
no | false) ENABLE_NESTING="0" ;;
esac
case "${ENABLE_KEYCTL,,}" in
yes | true) ENABLE_KEYCTL="1" ;;
no | false) ENABLE_KEYCTL="0" ;;
esac
case "${ENABLE_MKNOD,,}" in
yes | true) ENABLE_MKNOD="1" ;;
no | false) ENABLE_MKNOD="0" ;;
esac
case "${ENABLE_FUSE,,}" in
yes | true) ENABLE_FUSE="1" ;;
no | false) ENABLE_FUSE="0" ;;
esac
case "${PROTECT_CT,,}" in
yes | true) PROTECT_CT="1" ;;
no | false) PROTECT_CT="0" ;;
esac
# Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts # Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts
if [ -z "$var_os" ]; then if [ -z "$var_os" ]; then
@ -548,9 +587,9 @@ default_var_settings() {
# Allowed var_* keys (alphabetically sorted) # Allowed var_* keys (alphabetically sorted)
# Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique) # Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique)
local VAR_WHITELIST=( local VAR_WHITELIST=(
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_keyctl
var_gateway var_hostname var_ipv6_method var_mac var_mtu var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
var_net var_ns var_pw var_ram var_tags var_tun var_unprivileged var_net var_nesting var_ns var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
var_verbose var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_verbose var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage
) )
@ -628,6 +667,14 @@ var_ssh=no
# Features/Tags/verbosity # Features/Tags/verbosity
var_fuse=no var_fuse=no
var_tun=no var_tun=no
# Advanced Settings (Proxmox-official features)
var_nesting=1 # Allow nesting (required for Docker/LXC in CT)
var_keyctl=0 # Allow keyctl() - needed for Docker (systemd-networkd workaround)
var_mknod=0 # Allow device node creation (requires kernel 5.3+, experimental)
var_mount_fs= # Allow specific filesystems: nfs,fuse,ext4,etc (leave empty for defaults)
var_protection=no # Prevent accidental deletion of container
var_timezone= # Container timezone (e.g. Europe/Berlin, leave empty for host timezone)
var_tags=community-script var_tags=community-script
var_verbose=no var_verbose=no
@ -894,6 +941,12 @@ _build_current_app_vars_tmp() {
_apt_cacher_ip="${APT_CACHER_IP:-}" _apt_cacher_ip="${APT_CACHER_IP:-}"
_fuse="${ENABLE_FUSE:-no}" _fuse="${ENABLE_FUSE:-no}"
_tun="${ENABLE_TUN:-no}" _tun="${ENABLE_TUN:-no}"
_nesting="${ENABLE_NESTING:-1}"
_keyctl="${ENABLE_KEYCTL:-0}"
_mknod="${ENABLE_MKNOD:-0}"
_mount_fs="${ALLOW_MOUNT_FS:-}"
_protect="${PROTECT_CT:-no}"
_timezone="${CT_TIMEZONE:-}"
_tags="${TAGS:-}" _tags="${TAGS:-}"
_verbose="${VERBOSE:-no}" _verbose="${VERBOSE:-no}"
@ -937,6 +990,12 @@ _build_current_app_vars_tmp() {
[ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")" [ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")"
[ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")" [ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")"
[ -n "$_nesting" ] && echo "var_nesting=$(_sanitize_value "$_nesting")"
[ -n "$_keyctl" ] && echo "var_keyctl=$(_sanitize_value "$_keyctl")"
[ -n "$_mknod" ] && echo "var_mknod=$(_sanitize_value "$_mknod")"
[ -n "$_mount_fs" ] && echo "var_mount_fs=$(_sanitize_value "$_mount_fs")"
[ -n "$_protect" ] && echo "var_protection=$(_sanitize_value "$_protect")"
[ -n "$_timezone" ] && echo "var_timezone=$(_sanitize_value "$_timezone")"
[ -n "$_tags" ] && echo "var_tags=$(_sanitize_value "$_tags")" [ -n "$_tags" ] && echo "var_tags=$(_sanitize_value "$_tags")"
[ -n "$_verbose" ] && echo "var_verbose=$(_sanitize_value "$_verbose")" [ -n "$_verbose" ] && echo "var_verbose=$(_sanitize_value "$_verbose")"
@ -1519,6 +1578,51 @@ advanced_settings() {
configure_ssh_settings configure_ssh_settings
export SSH_KEYS_FILE export SSH_KEYS_FILE
echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}"
# Advanced Settings - Proxmox Features
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS" --yesno "Configure Advanced Proxmox Features?" 10 58); then
# keyctl: for Docker support
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Enable keyctl()" --yesno "Allow keyctl() system calls?\n\nNeeded for: Docker inside container, systemd-networkd\nDefault: No (not needed for most applications)" 10 58); then
ENABLE_KEYCTL="1"
else
ENABLE_KEYCTL="0"
fi
echo -e "${SEARCH}${BOLD}${DGN}Allow keyctl(): ${BGN}$ENABLE_KEYCTL${CL}"
# mknod: device node creation
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Enable mknod()" --yesno "Allow device node creation?\n\nNeeded for: Complex device management (experimental, kernel 5.3+)\nDefault: No (rarely needed)" 10 58); then
ENABLE_MKNOD="1"
else
ENABLE_MKNOD="0"
fi
echo -e "${SEARCH}${BOLD}${DGN}Allow mknod(): ${BGN}$ENABLE_MKNOD${CL}"
# mount: specific filesystems
if MOUNT_FS=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allow specific filesystems (e.g., nfs,fuse,ext4)\nLeave blank for defaults" 8 58 "$ALLOW_MOUNT_FS" --title "Mount Filesystems" 3>&1 1>&2 2>&3); then
ALLOW_MOUNT_FS="$MOUNT_FS"
[ -z "$ALLOW_MOUNT_FS" ] && ALLOW_MOUNT_FS="(defaults)"
else
exit_script
fi
echo -e "${SEARCH}${BOLD}${DGN}Mount Filesystems: ${BGN}$ALLOW_MOUNT_FS${CL}"
# Container protection
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Protection Flag" --yesno "Prevent accidental deletion?\n\nIf enabled, container cannot be deleted or its disk modified\nDefault: No" 10 58); then
PROTECT_CT="yes"
else
PROTECT_CT="no"
fi
echo -e "${SEARCH}${BOLD}${DGN}Container Protection: ${BGN}$PROTECT_CT${CL}"
# Container timezone
if CT_TIMEZONE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set container timezone (e.g., Europe/Berlin)\nLeave blank to use host timezone" 8 58 "$CT_TIMEZONE" --title "Container Timezone" 3>&1 1>&2 2>&3); then
[ -z "$CT_TIMEZONE" ] && CT_TIMEZONE="(host)"
else
exit_script
fi
echo -e "${SEARCH}${BOLD}${DGN}Container Timezone: ${BGN}$CT_TIMEZONE${CL}"
fi
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then
ENABLE_FUSE="yes" ENABLE_FUSE="yes"
else else
@ -1691,7 +1795,16 @@ install_script() {
fi fi
NEXTID=$(pvesh get /cluster/nextid) NEXTID=$(pvesh get /cluster/nextid)
# Get timezone using timedatectl (Debian 13+ compatible)
# Fallback to /etc/timezone for older systems
if command -v timedatectl >/dev/null 2>&1; then
timezone=$(timedatectl show --value --property=Timezone 2>/dev/null || echo "UTC")
elif [ -f /etc/timezone ]; then
timezone=$(cat /etc/timezone) timezone=$(cat /etc/timezone)
else
timezone="UTC"
fi
# Show APP Header # Show APP Header
header_info header_info
@ -1819,13 +1932,12 @@ settings_menu() {
local settings_items=( local settings_items=(
"1" "Manage API-Diagnostic Setting" "1" "Manage API-Diagnostic Setting"
"2" "Edit Default.vars" "2" "Edit Default.vars"
"3" "Edit Default Storage"
) )
if [ -f "$(get_app_defaults_path)" ]; then if [ -f "$(get_app_defaults_path)" ]; then
settings_items+=("4" "Edit App.vars for ${APP}") settings_items+=("3" "Edit App.vars for ${APP}")
settings_items+=("5" "Exit")
else
settings_items+=("4" "Exit") settings_items+=("4" "Exit")
else
settings_items+=("3" "Exit")
fi fi
local choice local choice
@ -2186,14 +2298,34 @@ build_container() {
none) ;; none) ;;
esac esac
if [ "$CT_TYPE" == "1" ]; then # Build FEATURES array with advanced settings
FEATURES="keyctl=1,nesting=1" # Note: All feature flags are already normalized to 0/1 in default_settings()
else # Proxmox requires each feature as a separate parameter, not comma-separated string
FEATURES="nesting=1" FEATURES_ARRAY=()
FEATURES_ARRAY+=("nesting=${ENABLE_NESTING}")
# keyctl: needed for Docker inside containers (systemd-networkd workaround)
# Typically needed for unprivileged containers with Docker
if [ "$CT_TYPE" == "1" ] || [ "$ENABLE_KEYCTL" == "1" ]; then
FEATURES_ARRAY+=("keyctl=1")
fi fi
if [ "$ENABLE_FUSE" == "yes" ]; then # mknod: allow device node creation (requires kernel 5.3+, experimental)
FEATURES="$FEATURES,fuse=1" if [ "$ENABLE_MKNOD" == "1" ]; then
FEATURES_ARRAY+=("mknod=1")
fi
# FUSE: required for rclone, mergerfs, AppImage, etc.
if [ "$ENABLE_FUSE" == "1" ]; then
FEATURES_ARRAY+=("fuse=1")
fi
# mount: allow specific filesystems (e.g., nfs, ext4, etc.)
# Format: mount=fstype1;fstype2;fstype3 (semicolon-separated, not comma!)
if [ -n "$ALLOW_MOUNT_FS" ]; then
# Replace commas with semicolons for proper pct syntax
ALLOW_MOUNT_FS_FORMATTED="${ALLOW_MOUNT_FS//,/;}"
FEATURES_ARRAY+=("mount=$ALLOW_MOUNT_FS_FORMATTED")
fi fi
TEMP_DIR=$(mktemp -d) TEMP_DIR=$(mktemp -d)
@ -2206,6 +2338,16 @@ build_container() {
export DIAGNOSTICS="$DIAGNOSTICS" export DIAGNOSTICS="$DIAGNOSTICS"
export RANDOM_UUID="$RANDOM_UUID" export RANDOM_UUID="$RANDOM_UUID"
export SESSION_ID="$SESSION_ID" export SESSION_ID="$SESSION_ID"
export BUILD_LOG="$BUILD_LOG"
export INSTALL_LOG="/root/.install-${SESSION_ID}.log"
export dev_mode="${dev_mode:-}"
export DEV_MODE_MOTD="${DEV_MODE_MOTD:-false}"
export DEV_MODE_KEEP="${DEV_MODE_KEEP:-false}"
export DEV_MODE_TRACE="${DEV_MODE_TRACE:-false}"
export DEV_MODE_PAUSE="${DEV_MODE_PAUSE:-false}"
export DEV_MODE_BREAKPOINT="${DEV_MODE_BREAKPOINT:-false}"
export DEV_MODE_LOGS="${DEV_MODE_LOGS:-false}"
export DEV_MODE_DRYRUN="${DEV_MODE_DRYRUN:-false}"
export CACHER="$APT_CACHER" export CACHER="$APT_CACHER"
export CACHER_IP="$APT_CACHER_IP" export CACHER_IP="$APT_CACHER_IP"
export tz="$timezone" export tz="$timezone"
@ -2219,22 +2361,59 @@ build_container() {
export CTTYPE="$CT_TYPE" export CTTYPE="$CT_TYPE"
export ENABLE_FUSE="$ENABLE_FUSE" export ENABLE_FUSE="$ENABLE_FUSE"
export ENABLE_TUN="$ENABLE_TUN" export ENABLE_TUN="$ENABLE_TUN"
export ENABLE_NESTING="$ENABLE_NESTING"
export ENABLE_KEYCTL="$ENABLE_KEYCTL"
export ENABLE_MKNOD="$ENABLE_MKNOD"
export ALLOW_MOUNT_FS="$ALLOW_MOUNT_FS"
export PROTECT_CT="$PROTECT_CT"
export CT_TIMEZONE="$CT_TIMEZONE"
export PCT_OSTYPE="$var_os" export PCT_OSTYPE="$var_os"
export PCT_OSVERSION="$var_version" export PCT_OSVERSION="$var_version"
export PCT_DISK_SIZE="$DISK_SIZE" export PCT_DISK_SIZE="$DISK_SIZE"
export PCT_OPTIONS="
-features $FEATURES # Build PCT_OPTIONS array (not string) for proper parameter handling
-hostname $HN PCT_OPTIONS=()
-tags $TAGS
$SD # Add features - each as separate -features parameter
$NS for feature in "${FEATURES_ARRAY[@]}"; do
$NET_STRING PCT_OPTIONS+=("-features" "$feature")
-onboot 1 done
-cores $CORE_COUNT
-memory $RAM_SIZE PCT_OPTIONS+=("-hostname" "$HN")
-unprivileged $CT_TYPE PCT_OPTIONS+=("-tags" "$TAGS")
$PW
" if [ -n "$SD" ]; then
PCT_OPTIONS+=($SD) # Storage device flags (already formatted)
fi
if [ -n "$NS" ]; then
PCT_OPTIONS+=($NS) # Nameserver flags (already formatted)
fi
# Network configuration (single string with all network parameters)
PCT_OPTIONS+=($NET_STRING)
PCT_OPTIONS+=("-onboot" "1")
PCT_OPTIONS+=("-cores" "$CORE_COUNT")
PCT_OPTIONS+=("-memory" "$RAM_SIZE")
PCT_OPTIONS+=("-unprivileged" "$CT_TYPE")
# Protection flag
if [ "$PROTECT_CT" == "1" ]; then
PCT_OPTIONS+=("-protection" "1")
fi
# Timezone flag
if [ -n "$CT_TIMEZONE" ]; then
PCT_OPTIONS+=("-timezone" "$CT_TIMEZONE")
fi
# Password flag (already formatted as "-password xxx")
if [ -n "$PW" ]; then
PCT_OPTIONS+=($PW)
fi
export PCT_OPTIONS
export TEMPLATE_STORAGE="${var_template_storage:-}" export TEMPLATE_STORAGE="${var_template_storage:-}"
export CONTAINER_STORAGE="${var_container_storage:-}" export CONTAINER_STORAGE="${var_container_storage:-}"
create_lxc_container || exit $? create_lxc_container || exit $?
@ -2409,20 +2588,13 @@ EOF
[[ "$selected_gpu" == "INTEL" ]] && devices=("${INTEL_DEVICES[@]}") [[ "$selected_gpu" == "INTEL" ]] && devices=("${INTEL_DEVICES[@]}")
[[ "$selected_gpu" == "AMD" ]] && devices=("${AMD_DEVICES[@]}") [[ "$selected_gpu" == "AMD" ]] && devices=("${AMD_DEVICES[@]}")
# Add lxc.mount.entry for each device # Use pct set to add devices with proper dev0/dev1 format
# GIDs will be detected and set after container starts
local dev_index=0
for dev in "${devices[@]}"; do for dev in "${devices[@]}"; do
echo "lxc.mount.entry: $dev $dev none bind,optional,create=file" >>"$LXC_CONFIG" # Add to config using pct set (will be visible in GUI)
echo "dev${dev_index}: ${dev},gid=44" >>"$LXC_CONFIG"
if [[ "$CT_TYPE" == "0" ]]; then dev_index=$((dev_index + 1))
# Privileged container - also add cgroup allows
local major minor
major=$(stat -c '%t' "$dev" 2>/dev/null || echo "0")
minor=$(stat -c '%T' "$dev" 2>/dev/null || echo "0")
if [[ "$major" != "0" && "$minor" != "0" ]]; then
echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG"
fi
fi
done done
export GPU_TYPE="$selected_gpu" export GPU_TYPE="$selected_gpu"
@ -2435,20 +2607,11 @@ EOF
return 0 return 0
fi fi
# Add lxc.mount.entry for each NVIDIA device # Use pct set for NVIDIA devices
local dev_index=0
for dev in "${NVIDIA_DEVICES[@]}"; do for dev in "${NVIDIA_DEVICES[@]}"; do
echo "lxc.mount.entry: $dev $dev none bind,optional,create=file" >>"$LXC_CONFIG" echo "dev${dev_index}: ${dev},gid=44" >>"$LXC_CONFIG"
dev_index=$((dev_index + 1))
if [[ "$CT_TYPE" == "0" ]]; then
# Privileged container - also add cgroup allows
local major minor
major=$(stat -c '%t' "$dev" 2>/dev/null || echo "0")
minor=$(stat -c '%T' "$dev" 2>/dev/null || echo "0")
if [[ "$major" != "0" && "$minor" != "0" ]]; then
echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG"
fi
fi
done done
export GPU_TYPE="NVIDIA" export GPU_TYPE="NVIDIA"
@ -2560,7 +2723,9 @@ EOF'
fi fi
if pct exec "$CTID" -- test -e "/usr/share/zoneinfo/$tz"; then if pct exec "$CTID" -- test -e "/usr/share/zoneinfo/$tz"; then
pct exec "$CTID" -- bash -c "tz='$tz'; echo \"\$tz\" >/etc/timezone && ln -sf \"/usr/share/zoneinfo/\$tz\" /etc/localtime" # Set timezone using symlink (Debian 13+ compatible)
# Create /etc/timezone for backwards compatibility with older scripts
pct exec "$CTID" -- bash -c "tz='$tz'; ln -sf \"/usr/share/zoneinfo/\$tz\" /etc/localtime && echo \"\$tz\" >/etc/timezone || true"
else else
msg_warn "Skipping timezone setup zone '$tz' not found in container" msg_warn "Skipping timezone setup zone '$tz' not found in container"
fi fi
@ -2576,14 +2741,121 @@ EOF'
# Install SSH keys # Install SSH keys
install_ssh_keys_into_ct install_ssh_keys_into_ct
# Run application installer # Dev mode: Setup MOTD/SSH AFTER network is ready and before installation
if ! lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/${var_install}.sh)"; then # This ensures the container is fully booted and accessible via SSH
local exit_code=$? if [[ "${DEV_MODE_MOTD:-false}" == "true" ]]; then
# Try to copy installation log from container before exiting msg_dev "Setting up MOTD and SSH for debugging access"
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then pct exec "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/${var_install}.sh)" <<'MOTD_SETUP'
pct pull "$CTID" "/root/.install-${SESSION_ID}.log" "/tmp/install-${SESSION_ID}.log" 2>/dev/null || true # Only run motd_ssh function if it exists
if declare -f motd_ssh >/dev/null 2>&1; then
motd_ssh
else
msg_warn "motd_ssh function not found in ${var_install}.sh"
fi fi
exit $exit_code MOTD_SETUP
msg_dev "MOTD/SSH ready - container accessible via SSH (IP: $ip_in_lxc)"
fi
# Run application installer
# NOTE: We disable error handling here because:
# 1. Container errors are caught by error_handler INSIDE container
# 2. Container creates flag file with exit code
# 3. We read flag file and handle cleanup manually below
# 4. We DON'T want host error_handler to fire for lxc-attach command itself
set +Eeuo pipefail # Disable ALL error handling temporarily
trap - ERR # Remove ERR trap completely
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/${var_install}.sh)"
local lxc_exit=$?
set -Eeuo pipefail # Re-enable error handling
trap 'error_handler' ERR # Restore ERR trap
# Check for error flag file in container (more reliable than lxc-attach exit code)
local install_exit_code=0
if [[ -n "${SESSION_ID:-}" ]]; then
local error_flag="/root/.install-${SESSION_ID}.failed"
if pct exec "$CTID" -- test -f "$error_flag" 2>/dev/null; then
install_exit_code=$(pct exec "$CTID" -- cat "$error_flag" 2>/dev/null || echo "1")
pct exec "$CTID" -- rm -f "$error_flag" 2>/dev/null || true
fi
fi
# Fallback to lxc-attach exit code if no flag file
if [[ $install_exit_code -eq 0 && $lxc_exit -ne 0 ]]; then
install_exit_code=$lxc_exit
fi
# Installation failed?
if [[ $install_exit_code -ne 0 ]]; then
msg_error "Installation failed in container ${CTID} (exit code: ${install_exit_code})"
# Copy both logs from container before potential deletion
local build_log_copied=false
local install_log_copied=false
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then
# Copy BUILD_LOG (creation log) if it exists
if [[ -f "${BUILD_LOG}" ]]; then
cp "${BUILD_LOG}" "/tmp/create-lxc-${CTID}-${SESSION_ID}.log" 2>/dev/null && build_log_copied=true
fi
# Copy INSTALL_LOG from container
if pct pull "$CTID" "/root/.install-${SESSION_ID}.log" "/tmp/install-lxc-${CTID}-${SESSION_ID}.log" 2>/dev/null; then
install_log_copied=true
fi
# Show available logs
echo ""
[[ $build_log_copied == true ]] && echo -e "${GN}✔${CL} Container creation log: ${BL}/tmp/create-lxc-${CTID}-${SESSION_ID}.log${CL}"
[[ $install_log_copied == true ]] && echo -e "${GN}✔${CL} Installation log: ${BL}/tmp/install-lxc-${CTID}-${SESSION_ID}.log${CL}"
fi
# Dev mode: Keep container or open breakpoint shell
if [[ "${DEV_MODE_KEEP:-false}" == "true" ]]; then
msg_dev "Keep mode active - container ${CTID} preserved"
return 0
elif [[ "${DEV_MODE_BREAKPOINT:-false}" == "true" ]]; then
msg_dev "Breakpoint mode - opening shell in container ${CTID}"
echo -e "${YW}Type 'exit' to return to host${CL}"
pct enter "$CTID"
echo ""
echo -en "${YW}Container ${CTID} still running. Remove now? (y/N): ${CL}"
if read -r response && [[ "$response" =~ ^[Yy]$ ]]; then
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
msg_ok "Container ${CTID} removed"
else
msg_dev "Container ${CTID} kept for debugging"
fi
exit $install_exit_code
fi
# Prompt user for cleanup with 60s timeout (plain echo - no msg_info to avoid spinner)
echo ""
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
if read -t 60 -r response; then
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
# Remove container
echo -e "\n${TAB}${HOLD}${YW}Removing container ${CTID}${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}"
elif [[ "$response" =~ ^[Nn]$ ]]; then
echo -e "\n${TAB}${YW}Container ${CTID} kept for debugging${CL}"
fi
else
# Timeout - auto-remove
echo -e "\n${YW}No response - auto-removing container${CL}"
echo -e "${TAB}${HOLD}${YW}Removing container ${CTID}${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}"
fi
exit $install_exit_code
fi fi
} }
@ -2665,79 +2937,40 @@ fix_gpu_gids() {
return 0 return 0
fi fi
# Silent operation to avoid spinner conflicts
msg_custom "🔧" "${BL}" "Detecting and setting correct GPU group IDs" msg_custom "🔧" "${BL}" "Detecting and setting correct GPU group IDs"
# Ermittle die tatsächlichen GIDs aus dem Container # Get actual GIDs from container
local video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3") local video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3")
local render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3") local render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3")
# Fallbacks wenn Gruppen nicht existieren # Create groups if they don't exist
if [[ -z "$video_gid" ]]; then if [[ -z "$video_gid" ]]; then
# Versuche die video Gruppe zu erstellen pct exec "$CTID" -- sh -c "groupadd -r video 2>/dev/null || true" >/dev/null 2>&1
pct exec "$CTID" -- sh -c "groupadd -r video 2>/dev/null || true"
video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3") video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3")
[[ -z "$video_gid" ]] && video_gid="44" # Ultimate fallback [[ -z "$video_gid" ]] && video_gid="44"
fi fi
if [[ -z "$render_gid" ]]; then if [[ -z "$render_gid" ]]; then
# Versuche die render Gruppe zu erstellen pct exec "$CTID" -- sh -c "groupadd -r render 2>/dev/null || true" >/dev/null 2>&1
pct exec "$CTID" -- sh -c "groupadd -r render 2>/dev/null || true"
render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3") render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3")
[[ -z "$render_gid" ]] && render_gid="104" # Ultimate fallback [[ -z "$render_gid" ]] && render_gid="104"
fi fi
msg_custom "" "${DGN}" "Container GIDs detected - video:${video_gid}, render:${render_gid}" # Stop container to update config
# Prüfe ob die GIDs von den Defaults abweichen
local need_update=0
if [[ "$video_gid" != "44" ]] || [[ "$render_gid" != "104" ]]; then
need_update=1
fi
if [[ $need_update -eq 1 ]]; then
msg_custom "🔄" "${YW}" "Updating device GIDs in container config"
# Stoppe Container für Config-Update
pct stop "$CTID" >/dev/null 2>&1 pct stop "$CTID" >/dev/null 2>&1
sleep 1
# Update die dev Einträge mit korrekten GIDs # Update dev entries with correct GIDs
# Backup der Config sed -i.bak -E "s|(dev[0-9]+: /dev/dri/renderD[0-9]+),gid=[0-9]+|\1,gid=${render_gid}|g" "$LXC_CONFIG"
cp "$LXC_CONFIG" "${LXC_CONFIG}.bak" sed -i -E "s|(dev[0-9]+: /dev/dri/card[0-9]+),gid=[0-9]+|\1,gid=${video_gid}|g" "$LXC_CONFIG"
# Parse und update jeden dev Eintrag # Restart container
while IFS= read -r line; do
if [[ "$line" =~ ^dev[0-9]+: ]]; then
# Extract device path
local device_path=$(echo "$line" | sed -E 's/^dev[0-9]+: ([^,]+).*/\1/')
local dev_num=$(echo "$line" | sed -E 's/^(dev[0-9]+):.*/\1/')
if [[ "$device_path" =~ renderD ]]; then
# RenderD device - use render GID
echo "${dev_num}: ${device_path},gid=${render_gid}"
elif [[ "$device_path" =~ card ]]; then
# Card device - use video GID
echo "${dev_num}: ${device_path},gid=${video_gid}"
else
# Keep original line
echo "$line"
fi
else
# Keep non-dev lines
echo "$line"
fi
done <"$LXC_CONFIG" >"${LXC_CONFIG}.new"
mv "${LXC_CONFIG}.new" "$LXC_CONFIG"
# Starte Container wieder
pct start "$CTID" >/dev/null 2>&1 pct start "$CTID" >/dev/null 2>&1
sleep 3 sleep 2
msg_ok "Device GIDs updated successfully" msg_ok "GPU passthrough configured (video:${video_gid}, render:${render_gid})"
else
msg_ok "Device GIDs are already correct" # For privileged containers: also fix permissions inside container
fi
if [[ "$CT_TYPE" == "0" ]]; then if [[ "$CT_TYPE" == "0" ]]; then
pct exec "$CTID" -- bash -c " pct exec "$CTID" -- bash -c "
if [ -d /dev/dri ]; then if [ -d /dev/dri ]; then
@ -2903,7 +3136,7 @@ create_lxc_container() {
case "${_ans,,}" in case "${_ans,,}" in
y | yes) y | yes)
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)" msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
if apt-get update -qq >/dev/null && apt-get install -y --only-upgrade pve-container lxc-pve >/dev/null; then if $STD apt-get update && $STD apt-get install -y --only-upgrade pve-container lxc-pve; then
msg_ok "LXC stack upgraded." msg_ok "LXC stack upgraded."
if [[ "$do_retry" == "yes" ]]; then if [[ "$do_retry" == "yes" ]]; then
msg_info "Retrying container creation after upgrade" msg_info "Retrying container creation after upgrade"
@ -3348,13 +3581,13 @@ create_lxc_container() {
exit 211 exit 211
} }
LOGFILE="/tmp/pct_create_${CTID}.log" LOGFILE="/tmp/pct_create_${CTID}_$(date +%Y%m%d_%H%M%S)_${SESSION_ID}.log"
msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}" msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}"
msg_debug "Logfile: $LOGFILE" msg_debug "Logfile: $LOGFILE"
# First attempt # First attempt
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >"$LOGFILE" 2>&1; then if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >"$LOGFILE" 2>&1; then
msg_error "Container creation failed on ${TEMPLATE_STORAGE}. Checking template..." msg_debug "Container creation failed on ${TEMPLATE_STORAGE}. Validating template..."
# Validate template file # Validate template file
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
@ -3373,49 +3606,16 @@ create_lxc_container() {
# Retry after repair # Retry after repair
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
# Fallback to local storage # Fallback to local storage if not already on local
if [[ "$TEMPLATE_STORAGE" != "local" ]]; then if [[ "$TEMPLATE_STORAGE" != "local" ]]; then
msg_warn "Retrying container creation with fallback to local storage..." msg_info "Retrying container creation with fallback to local storage..."
LOCAL_TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE" LOCAL_TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then
msg_info "Downloading template to local..." msg_info "Downloading template to local..."
pveam download local "$TEMPLATE" >/dev/null 2>&1 pveam download local "$TEMPLATE" >/dev/null 2>&1
fi fi
if pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then if ! pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
msg_ok "Container successfully created using local fallback." # Local fallback also failed - check for LXC stack version issue
else
# --- Dynamic stack upgrade + auto-retry on the well-known error pattern ---
if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically."
offer_lxc_stack_upgrade_and_maybe_retry "yes"
rc=$?
case $rc in
0) : ;; # success - container created, continue
2)
echo "Upgrade was declined. Please update and re-run:
apt update && apt install --only-upgrade pve-container lxc-pve"
exit 231
;;
3)
echo "Upgrade and/or retry failed. Please inspect: $LOGFILE"
exit 231
;;
esac
else
msg_error "Container creation failed even with local fallback. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x
bash -x -c "pct create $CTID local:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}" 2>&1 | tee -a "$LOGFILE"
set +x
fi
exit 209
fi
fi
else
msg_error "Container creation failed on local storage. See $LOGFILE"
# --- Dynamic stack upgrade + auto-retry on the well-known error pattern ---
if grep -qiE 'unsupported .* version' "$LOGFILE"; then if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template." echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
@ -3438,12 +3638,46 @@ create_lxc_container() {
msg_error "Container creation failed. See $LOGFILE" msg_error "Container creation failed. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x set -x
bash -x -c "pct create $CTID local:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}" 2>&1 | tee -a "$LOGFILE" pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" 2>&1 | tee -a "$LOGFILE"
set +x
fi
exit 209
fi
else
msg_ok "Container successfully created using local fallback."
fi
else
# Already on local storage and still failed - check LXC stack version
if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically."
offer_lxc_stack_upgrade_and_maybe_retry "yes"
rc=$?
case $rc in
0) : ;; # success - container created, continue
2)
echo "Upgrade was declined. Please update and re-run:
apt update && apt install --only-upgrade pve-container lxc-pve"
exit 231
;;
3)
echo "Upgrade and/or retry failed. Please inspect: $LOGFILE"
exit 231
;;
esac
else
msg_error "Container creation failed. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x
pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" 2>&1 | tee -a "$LOGFILE"
set +x set +x
fi fi
exit 209 exit 209
fi fi
fi fi
else
msg_ok "Container successfully created after template repair."
fi fi
fi fi
@ -3460,6 +3694,9 @@ create_lxc_container() {
} }
msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created." msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created."
# Report container creation to API
post_to_api
} }
# ============================================================================== # ==============================================================================

277
misc/install copy.func Normal file
View File

@ -0,0 +1,277 @@
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# Co-Author: MickLesk
# Co-Author: michelroegl-brunner
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# ==============================================================================
# INSTALL.FUNC - CONTAINER INSTALLATION & SETUP
# ==============================================================================
#
# This file provides installation functions executed inside LXC containers
# after creation. Handles:
#
# - Network connectivity verification (IPv4/IPv6)
# - OS updates and package installation
# - DNS resolution checks
# - MOTD and SSH configuration
# - Container customization and auto-login
#
# Usage:
# - Sourced by <app>-install.sh scripts
# - Executes via pct exec inside container
# - Requires internet connectivity
#
# ==============================================================================
# ==============================================================================
# SECTION 1: INITIALIZATION
# ==============================================================================
if ! command -v curl >/dev/null 2>&1; then
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
apt-get update >/dev/null 2>&1
apt-get install -y curl >/dev/null 2>&1
fi
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func)
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func)
load_functions
catch_errors
# ==============================================================================
# SECTION 2: NETWORK & CONNECTIVITY
# ==============================================================================
# ------------------------------------------------------------------------------
# verb_ip6()
#
# - Configures IPv6 based on DISABLEIPV6 variable
# - If DISABLEIPV6=yes: disables IPv6 via sysctl
# - Sets verbose mode via set_std_mode()
# ------------------------------------------------------------------------------
verb_ip6() {
set_std_mode # Set STD mode based on VERBOSE
if [ "$DISABLEIPV6" == "yes" ]; then
echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf
$STD sysctl -p
fi
}
# ------------------------------------------------------------------------------
# setting_up_container()
#
# - Verifies network connectivity via hostname -I
# - Retries up to RETRY_NUM times with RETRY_EVERY seconds delay
# - Removes Python EXTERNALLY-MANAGED restrictions
# - Disables systemd-networkd-wait-online.service for faster boot
# - Exits with error if network unavailable after retries
# ------------------------------------------------------------------------------
setting_up_container() {
msg_info "Setting up Container OS"
for ((i = RETRY_NUM; i > 0; i--)); do
if [ "$(hostname -I)" != "" ]; then
break
fi
echo 1>&2 -en "${CROSS}${RD} No Network! "
sleep $RETRY_EVERY
done
if [ "$(hostname -I)" = "" ]; then
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
echo -e "${NETWORK}Check Network Settings"
exit 1
fi
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
systemctl disable -q --now systemd-networkd-wait-online.service
msg_ok "Set up Container OS"
#msg_custom "${CM}" "${GN}" "Network Connected: ${BL}$(hostname -I)"
msg_ok "Network Connected: ${BL}$(hostname -I)"
}
# ------------------------------------------------------------------------------
# network_check()
#
# - Comprehensive network connectivity check for IPv4 and IPv6
# - Tests connectivity to multiple DNS servers:
# * IPv4: 1.1.1.1 (Cloudflare), 8.8.8.8 (Google), 9.9.9.9 (Quad9)
# * IPv6: 2606:4700:4700::1111, 2001:4860:4860::8888, 2620:fe::fe
# - Verifies DNS resolution for GitHub and Community-Scripts domains
# - Prompts user to continue if no internet detected
# - Uses fatal() on DNS resolution failure for critical hosts
# ------------------------------------------------------------------------------
network_check() {
set +e
trap - ERR
ipv4_connected=false
ipv6_connected=false
sleep 1
# Check IPv4 connectivity to Google, Cloudflare & 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
# Check IPv6 connectivity to Google, Cloudflare & Quad9 DNS servers.
if ping6 -c 1 -W 1 2606:4700:4700::1111 &>/dev/null || ping6 -c 1 -W 1 2001:4860:4860::8888 &>/dev/null || ping6 -c 1 -W 1 2620:fe::fe &>/dev/null; then
msg_ok "IPv6 Internet Connected"
ipv6_connected=true
else
msg_error "IPv6 Internet Not Connected"
fi
# If both IPv4 and IPv6 checks fail, prompt the user
if [[ $ipv4_connected == false && $ipv6_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 1
fi
fi
# DNS resolution checks for GitHub-related domains (IPv4 and/or IPv6)
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
}
# ==============================================================================
# SECTION 3: OS UPDATE & PACKAGE MANAGEMENT
# ==============================================================================
# ------------------------------------------------------------------------------
# update_os()
#
# - Updates container OS via apt-get update and dist-upgrade
# - Configures APT cacher proxy if CACHER=yes (accelerates package downloads)
# - Removes Python EXTERNALLY-MANAGED restrictions for pip
# - Sources tools.func for additional setup functions after update
# - Uses $STD wrapper to suppress output unless VERBOSE=yes
# ------------------------------------------------------------------------------
update_os() {
msg_info "Updating Container OS"
if [[ "$CACHER" == "yes" ]]; then
echo "Acquire::http::Proxy-Auto-Detect \"/usr/local/bin/apt-proxy-detect.sh\";" >/etc/apt/apt.conf.d/00aptproxy
cat <<'EOF' >/usr/local/bin/apt-proxy-detect.sh
#!/bin/bash
if nc -w1 -z "${CACHER_IP}" 3142; then
echo -n "http://${CACHER_IP}:3142"
else
echo -n "DIRECT"
fi
EOF
chmod +x /usr/local/bin/apt-proxy-detect.sh
fi
$STD apt-get update
$STD apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
msg_ok "Updated Container OS"
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func)
}
# ==============================================================================
# SECTION 4: MOTD & SSH CONFIGURATION
# ==============================================================================
# ------------------------------------------------------------------------------
# motd_ssh()
#
# - Configures Message of the Day (MOTD) with container information
# - Creates /etc/profile.d/00_lxc-details.sh with:
# * Application name
# * Warning banner (DEV repository)
# * OS name and version
# * Hostname and IP address
# * GitHub repository link
# - Disables executable flag on /etc/update-motd.d/* scripts
# - Enables root SSH access if SSH_ROOT=yes
# - Configures TERM environment variable for better terminal support
# ------------------------------------------------------------------------------
motd_ssh() {
grep -qxF "export TERM='xterm-256color'" /root/.bashrc || echo "export TERM='xterm-256color'" >>/root/.bashrc
if [ -f "/etc/os-release" ]; then
OS_NAME=$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '"')
OS_VERSION=$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"')
elif [ -f "/etc/debian_version" ]; then
OS_NAME="Debian"
OS_VERSION=$(cat /etc/debian_version)
fi
PROFILE_FILE="/etc/profile.d/00_lxc-details.sh"
echo "echo -e \"\"" >"$PROFILE_FILE"
echo -e "echo -e \"${BOLD}${YW}${APPLICATION} LXC Container - DEV Repository${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${RD}WARNING: This is a DEVELOPMENT version (ProxmoxVED). Do NOT use in production!${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} OS: ${GN}${OS_NAME} - Version: ${OS_VERSION}${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} Hostname: ${GN}\$(hostname)${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} IP Address: ${GN}\$(hostname -I | awk '{print \$1}')${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} Repository: ${GN}https://github.com/community-scripts/ProxmoxVED${CL}\"" >>"$PROFILE_FILE"
echo "echo \"\"" >>"$PROFILE_FILE"
chmod -x /etc/update-motd.d/*
if [[ "${SSH_ROOT}" == "yes" ]]; then
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
systemctl restart sshd
fi
}
# ==============================================================================
# SECTION 5: CONTAINER CUSTOMIZATION
# ==============================================================================
# ------------------------------------------------------------------------------
# customize()
#
# - Customizes container for passwordless root login if PASSWORD is empty
# - Configures getty for auto-login via /etc/systemd/system/container-getty@1.service.d/override.conf
# - Creates /usr/bin/update script for easy application updates
# - Injects SSH authorized keys if SSH_AUTHORIZED_KEY variable is set
# - Sets proper permissions on SSH directories and key files
# ------------------------------------------------------------------------------
customize() {
if [[ "$PASSWORD" == "" ]]; then
msg_info "Customizing Container"
GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf"
mkdir -p $(dirname $GETTY_OVERRIDE)
cat <<EOF >$GETTY_OVERRIDE
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
EOF
systemctl daemon-reload
systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//')
msg_ok "Customized Container"
fi
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update
chmod +x /usr/bin/update
if [[ -n "${SSH_AUTHORIZED_KEY}" ]]; then
mkdir -p /root/.ssh
echo "${SSH_AUTHORIZED_KEY}" >/root/.ssh/authorized_keys
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys
fi
}

View File

@ -28,6 +28,17 @@
# SECTION 1: INITIALIZATION # SECTION 1: INITIALIZATION
# ============================================================================== # ==============================================================================
# Ensure INSTALL_LOG is set (exported from build.func, but fallback if missing)
if [[ -z "${INSTALL_LOG:-}" ]]; then
INSTALL_LOG="/root/.install-${SESSION_ID:-unknown}.log"
fi
# Dev mode: Persistent logs directory
if [[ "${DEV_MODE_LOGS:-false}" == "true" ]]; then
mkdir -p /var/log/community-scripts
INSTALL_LOG="/var/log/community-scripts/install-${SESSION_ID:-unknown}-$(date +%Y%m%d_%H%M%S).log"
fi
if ! command -v curl >/dev/null 2>&1; then if ! command -v curl >/dev/null 2>&1; then
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
apt-get update >/dev/null 2>&1 apt-get update >/dev/null 2>&1
@ -38,6 +49,9 @@ source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxV
load_functions load_functions
catch_errors catch_errors
# Re-parse dev_mode in container context (flags exported from host)
parse_dev_mode
# ============================================================================== # ==============================================================================
# SECTION 2: NETWORK & CONNECTIVITY # SECTION 2: NETWORK & CONNECTIVITY
# ============================================================================== # ==============================================================================
@ -108,20 +122,23 @@ network_check() {
# Check IPv4 connectivity to Google, Cloudflare & Quad9 DNS servers. # Check IPv4 connectivity to Google, Cloudflare & 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 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 ipv4_connected=true
ipv4_status="${GN}✔${CL} IPv4"
else else
msg_error "IPv4 Internet Not Connected" ipv4_status="${RD}✖${CL} IPv4"
fi fi
# Check IPv6 connectivity to Google, Cloudflare & Quad9 DNS servers. # Check IPv6 connectivity to Google, Cloudflare & Quad9 DNS servers.
if ping6 -c 1 -W 1 2606:4700:4700::1111 &>/dev/null || ping6 -c 1 -W 1 2001:4860:4860::8888 &>/dev/null || ping6 -c 1 -W 1 2620:fe::fe &>/dev/null; then if ping6 -c 1 -W 1 2606:4700:4700::1111 &>/dev/null || ping6 -c 1 -W 1 2001:4860:4860::8888 &>/dev/null || ping6 -c 1 -W 1 2620:fe::fe &>/dev/null; then
msg_ok "IPv6 Internet Connected"
ipv6_connected=true ipv6_connected=true
ipv6_status="${GN}✔${CL} IPv6"
else else
msg_error "IPv6 Internet Not Connected" ipv6_status="${RD}✖${CL} IPv6"
fi fi
# Show combined status
msg_ok "Internet: ${ipv4_status} ${ipv6_status}"
# If both IPv4 and IPv6 checks fail, prompt the user # If both IPv4 and IPv6 checks fail, prompt the user
if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
@ -239,10 +256,6 @@ motd_ssh() {
fi fi
} }
# ==============================================================================
# SECTION 5: CONTAINER CUSTOMIZATION
# ==============================================================================
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# customize() # customize()
# #
@ -253,21 +266,33 @@ motd_ssh() {
# - Sets proper permissions on SSH directories and key files # - Sets proper permissions on SSH directories and key files
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
customize() { customize() {
if [[ "$PASSWORD" == "" ]]; then if [[ -z "${PASSWORD:-}" ]]; then
msg_info "Customizing Container" msg_info "Configuring autologin for root"
# Enable root account (remove password lock)
passwd -d root >/dev/null 2>&1 || true
# Create getty override for container-getty@1.service
GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf" GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf"
mkdir -p $(dirname $GETTY_OVERRIDE) mkdir -p $(dirname $GETTY_OVERRIDE)
cat <<EOF >$GETTY_OVERRIDE cat <<EOF >$GETTY_OVERRIDE
[Service] [Service]
ExecStart= ExecStart=
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
EOF EOF
systemctl daemon-reload
systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//') # Reload and restart getty service
msg_ok "Customized Container" $STD systemctl daemon-reload
$STD systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//') || true
msg_ok "Autologin configured"
fi fi
msg_ok "Customized Container"
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update
chmod +x /usr/bin/update chmod +x /usr/bin/update
if [[ -n "${SSH_AUTHORIZED_KEY}" ]]; then if [[ -n "${SSH_AUTHORIZED_KEY}" ]]; then
mkdir -p /root/.ssh mkdir -p /root/.ssh
echo "${SSH_AUTHORIZED_KEY}" >/root/.ssh/authorized_keys echo "${SSH_AUTHORIZED_KEY}" >/root/.ssh/authorized_keys