diff --git a/scripts/lcx/ lxc-conversion-manual-guide.sh b/scripts/lcx/ lxc-conversion-manual-guide.sh new file mode 100644 index 0000000..f4f8aad --- /dev/null +++ b/scripts/lcx/ lxc-conversion-manual-guide.sh @@ -0,0 +1,284 @@ +#!/bin/bash + +# ========================================================== +# ProxMenux - Manual LXC Conversion Guide +# ========================================================== +# Author : MacRimi +# Copyright : (c) 2024 MacRimi +# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE) +# Version : 1.0 +# Last Updated: 19/08/2025 +# ========================================================== + +# Configuration ============================================ +REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main" +BASE_DIR="/usr/local/share/proxmenux" +UTILS_FILE="$BASE_DIR/utils.sh" +VENV_PATH="/opt/googletrans-env" + +if [[ -f "$UTILS_FILE" ]]; then + source "$UTILS_FILE" +fi +load_language +initialize_cache +# ========================================================== + +show_command() { + local step="$1" + local description="$2" + local command="$3" + local note="$4" + local command_extra="$5" + + echo -e "${BGN}${step}.${CL} ${BL}${description}${CL}" + echo "" + echo -e "${TAB}${command}" + echo -e + [[ -n "$note" ]] && echo -e "${TAB}${DARK_GRAY}${note}${CL}" + [[ -n "$command_extra" ]] && echo -e "${TAB}${YW}${command_extra}${CL}" + echo "" +} + +show_privileged_to_unprivileged_guide() { + clear + show_proxmenux_logo + msg_title "$(translate "Manual Guide: Convert LXC Privileged to Unprivileged")" + + echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}" + echo -e + echo -e "${TAB}${BGN}$(translate "Source:")${CL} ${BL}https://forum.proxmox.com/threads/converting-between-privileged-and-unprivileged-containers.97243/${CL}" + echo -e + echo -e + echo -e "${TAB}${BOLD}$(translate "IMPORTANT PREREQUISITES:")${CL}" + echo -e + echo -e "${TAB}${BGN}• $(translate "Container must be stopped before conversion")${CL}" + echo -e "${TAB}${BGN}• $(translate "Create a backup of your container before proceeding")${CL}" + echo -e "${TAB}${BGN}• $(translate "This process changes file ownership inside the container")${CL}" + echo -e "${TAB}${BGN}• $(translate "Process may take several minutes depending on container size")${CL}" + echo -e "${TAB}${BGN}• $(translate "Works with LVM, ZFS, and BTRFS storage types")${CL}" + echo -e + echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}" + echo -e + + show_command "1" \ + "$(translate "List all containers to identify the privileged one:")" \ + "pct list" \ + "$(translate "Look for containers without 'unprivileged: 1' in their config")" + + show_command "2" \ + "$(translate "Stop the container if it's running:")" \ + "pct stop " \ + "$(translate "Replace with your actual container ID")" \ + "$(translate "Example: pct stop 114")" + + show_command "3" \ + "$(translate "Create a backup of the container configuration:")" \ + "cp /etc/pve/lxc/.conf /etc/pve/lxc/.conf.bak" \ + "$(translate "This creates a backup in case you need to revert changes")" \ + "$(translate "Example: cp /etc/pve/lxc/114.conf /etc/pve/lxc/114.conf.bak")" + + show_command "4" \ + "$(translate "Get the container's storage information:")" \ + "grep '^rootfs:' /etc/pve/lxc/.conf" \ + "$(translate "This shows the storage type and disk identifier")" \ + "$(translate "Example output: rootfs: local-lvm:vm-114-disk-0,size=8G")" + + show_command "5" \ + "$(translate "Get the actual disk path:")" \ + "pvesm path " \ + "$(translate "Replace with the value from step 4")" \ + "$(translate "Example: pvesm path local-lvm:vm-114-disk-0")" + + echo -e "${TAB}${BOLD}$(translate "STEP 6: Choose commands based on your storage type")${CL}" + echo -e + echo -e "${TAB}${BGN}$(translate "If pvesm path returned a DIRECTORY (ZFS/BTRFS):")${CL}" + echo -e "${TAB}${YW}$(translate "Example: /rpool/data/subvol-114-disk-0")${CL}" + echo -e + + show_command "6a" \ + "$(translate "For ZFS/BTRFS - Set the mount path:")" \ + "MOUNT_PATH=\"/rpool/data/subvol--disk-0\"" \ + "$(translate "Replace with your actual path from step 5")" \ + "$(translate "Example: MOUNT_PATH=\"/rpool/data/subvol-114-disk-0\"")" + + echo -e "${TAB}${BGN}$(translate "If pvesm path returned a DEVICE (LVM):")${CL}" + echo -e "${TAB}${YW}$(translate "Example: /dev/pve/vm-114-disk-0")${CL}" + echo -e + + show_command "6b" \ + "$(translate "For LVM - Create mount directory and mount:")" \ + "mkdir -p /tmp/lxc_convert_\nmount -o loop /dev/path/to/disk /tmp/lxc_convert_\nMOUNT_PATH=\"/tmp/lxc_convert_\"" \ + "$(translate "Replace paths with your actual values from step 5")" \ + "$(translate "Example: mkdir -p /tmp/lxc_convert_114")" + + show_command "7" \ + "$(translate "Convert file ownership (this takes time):")" \ + "find \"\$MOUNT_PATH\" -type f | while read file; do\n if [ -e \"\$file\" ]; then\n CURRENT_UID=\$(stat -c '%u' \"\$file\")\n CURRENT_GID=\$(stat -c '%g' \"\$file\")\n NEW_UID=\$((100000 + CURRENT_UID))\n NEW_GID=\$((100000 + CURRENT_GID))\n chown \"\$NEW_UID:\$NEW_GID\" \"\$file\"\n fi\ndone" \ + "$(translate "This converts all file UIDs/GIDs by adding 100000")" \ + "$(translate "Process may take several minutes for large containers")" + + show_command "8" \ + "$(translate "Convert directory ownership:")" \ + "find \"\$MOUNT_PATH\" -type d | while read dir; do\n if [ -e \"\$dir\" ]; then\n CURRENT_UID=\$(stat -c '%u' \"\$dir\")\n CURRENT_GID=\$(stat -c '%g' \"\$dir\")\n NEW_UID=\$((100000 + CURRENT_UID))\n NEW_GID=\$((100000 + CURRENT_GID))\n chown \"\$NEW_UID:\$NEW_GID\" \"\$dir\"\n fi\ndone" \ + "$(translate "This converts all directory UIDs/GIDs by adding 100000")" + + echo -e "${TAB}${BOLD}$(translate "STEP 9: Cleanup (LVM only)")${CL}" + echo -e "${TAB}${YW}$(translate "Only run this if you used LVM (step 6b):")${CL}" + echo -e + + show_command "9" \ + "$(translate "Unmount and cleanup (LVM only):")" \ + "umount /tmp/lxc_convert_\nrmdir /tmp/lxc_convert_" \ + "$(translate "Only needed if you mounted the filesystem in step 6b")" \ + "$(translate "Skip this step for ZFS/BTRFS")" + + show_command "10" \ + "$(translate "Add unprivileged flag to container configuration:")" \ + "echo 'unprivileged: 1' >> /etc/pve/lxc/.conf" \ + "$(translate "This marks the container as unprivileged")" + + show_command "11" \ + "$(translate "Start the converted container:")" \ + "pct start " \ + "$(translate "The container should now start as unprivileged")" + + show_command "12" \ + "$(translate "Verify the conversion:")" \ + "pct config | grep unprivileged" \ + "$(translate "Should show 'unprivileged: 1'")" + + echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}" + echo -e + echo -e "${TAB}${BOLD}$(translate "STORAGE TYPE IDENTIFICATION:")${CL}" + echo -e + echo -e "${TAB}${BGN}• $(translate "LVM:")${CL} ${YW}pvesm path returns /dev/xxx (block device)${CL}" + echo -e "${TAB}${BGN}• $(translate "ZFS:")${CL} ${YW}pvesm path returns /rpool/xxx (directory)${CL}" + echo -e "${TAB}${BGN}• $(translate "BTRFS:")${CL} ${YW}pvesm path returns directory path${CL}" + echo -e + echo -e "${TAB}${BOLD}$(translate "TROUBLESHOOTING:")${CL}" + echo -e + echo -e "${TAB}${BGN}$(translate "If mount fails (LVM):")${CL} ${YW}Check that the container is stopped and disk path is correct${CL}" + echo -e "${TAB}${BGN}$(translate "If path not accessible (ZFS/BTRFS):")${CL} ${YW}Verify the dataset/subvolume exists and is mounted${CL}" + echo -e "${TAB}${BGN}$(translate "If container won't start:")${CL} ${YW}Check /var/log/pve/tasks/ for detailed error messages${CL}" + echo -e "${TAB}${BGN}$(translate "To revert changes:")${CL} ${YW}cp /etc/pve/lxc/.conf.bak /etc/pve/lxc/.conf${CL}" + echo -e + + echo -e + msg_success "$(translate "Press Enter to return to menu...")" + echo -e + read -r +} + +show_unprivileged_to_privileged_guide() { + clear + show_proxmenux_logo + msg_title "$(translate "Manual Guide: Convert LXC Unprivileged to Privileged")" + + echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}" + echo -e + echo -e "${TAB}${RD}$(translate "SECURITY WARNING:")${CL} ${YW}$(translate "Privileged containers have full root access to the host system!")${CL}" + echo -e "${TAB}${YW}$(translate "Only convert to privileged if absolutely necessary for your use case.")${CL}" + echo -e + echo -e + echo -e "${TAB}${BOLD}$(translate "IMPORTANT PREREQUISITES:")${CL}" + echo -e + echo -e "${TAB}${BGN}• $(translate "Container must be stopped before conversion")${CL}" + echo -e "${TAB}${BGN}• $(translate "Create a backup of your container before proceeding")${CL}" + echo -e "${TAB}${BGN}• $(translate "Understand the security implications of privileged containers")${CL}" + echo -e "${TAB}${BGN}• $(translate "This is a simple configuration change")${CL}" + echo -e + echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}" + echo -e + + + show_command "1" \ + "$(translate "List all containers to identify the unprivileged one:")" \ + "pct list" \ + "$(translate "Look for containers with 'unprivileged: 1' in their config")" + + show_command "2" \ + "$(translate "Check if container is unprivileged:")" \ + "pct config | grep unprivileged" \ + "$(translate "Should show 'unprivileged: 1' if it's unprivileged")" \ + "$(translate "Example: pct config 110 | grep unprivileged")" + + show_command "3" \ + "$(translate "Stop the container if it's running:")" \ + "pct stop " \ + "$(translate "Replace with your actual container ID")" \ + "$(translate "Example: pct stop 110")" + + show_command "4" \ + "$(translate "Create a backup of the container configuration:")" \ + "cp /etc/pve/lxc/.conf /etc/pve/lxc/.conf.bak" \ + "$(translate "This creates a backup in case you need to revert changes")" \ + "$(translate "Example: cp /etc/pve/lxc/110.conf /etc/pve/lxc/110.conf.bak")" + + show_command "5" \ + "$(translate "Remove the unprivileged flag from configuration:")" \ + "sed -i '/^unprivileged: 1/d' /etc/pve/lxc/.conf" \ + "$(translate "This removes the 'unprivileged: 1' line from the config")" \ + "$(translate "Example: sed -i '/^unprivileged: 1/d' /etc/pve/lxc/110.conf")" + + show_command "6" \ + "$(translate "Add explicit privileged flag (optional but recommended):")" \ + "echo 'unprivileged: 0' >> /etc/pve/lxc/.conf" \ + "$(translate "This explicitly marks the container as privileged")" + + show_command "7" \ + "$(translate "Start the converted container:")" \ + "pct start " \ + "$(translate "The container should now start as privileged")" + + show_command "8" \ + "$(translate "Verify the conversion:")" \ + "pct config | grep unprivileged" \ + "$(translate "Should show 'unprivileged: 0' or no unprivileged line")" + + echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}" + echo -e + echo -e + echo -e "${TAB}${BOLD}$(translate "SECURITY CONSIDERATIONS:")${CL}" + echo -e + echo -e "${TAB}${RD}• $(translate "Privileged containers can access host devices directly")${CL}" + echo -e "${TAB}${RD}• $(translate "Root inside container = root on host system")${CL}" + echo -e "${TAB}${RD}• $(translate "Use only when unprivileged containers cannot meet your needs")${CL}" + echo -e "${TAB}${RD}• $(translate "Consider security implications for production environments")${CL}" + echo -e + echo -e + + echo -e "${TAB}${BOLD}$(translate "TROUBLESHOOTING:")${CL}" + echo -e + echo -e "${TAB}${BGN}$(translate "If container won't start:")${CL} ${YW}Check /var/log/pve/tasks/ for detailed error messages${CL}" + echo -e "${TAB}${BGN}$(translate "To revert changes:")${CL} ${YW}cp /etc/pve/lxc/.conf.bak /etc/pve/lxc/.conf${CL}" + echo -e "${TAB}${BGN}$(translate "If config issues occur:")${CL} ${YW}Manually edit /etc/pve/lxc/.conf${CL}" + echo -e + echo -e + + + echo -e + msg_success "$(translate "Press Enter to return to menu...")" + echo -e + read -r +} + +show_lxc_conversion_manual_menu() { + while true; do + CHOICE=$(dialog --title "$(translate "LXC Conversion Manual Guides")" \ + --menu "$(translate "Select conversion guide:")" 18 70 10 \ + "1" "$(translate "Convert Privileged to Unprivileged")" \ + "2" "$(translate "Convert Unprivileged to Privileged")" \ + "3" "$(translate "Return to Main Menu")" \ + 3>&1 1>&2 2>&3) + + case $CHOICE in + 1) show_privileged_to_unprivileged_guide ;; + 2) show_unprivileged_to_privileged_guide ;; + 3) return ;; + *) return ;; + esac + done +} + +# Main execution +show_lxc_conversion_manual_menu diff --git a/scripts/lcx/lxc-privileged-to-unprivileged.sh b/scripts/lcx/lxc-privileged-to-unprivileged.sh index 0f7668b..fcba20a 100644 --- a/scripts/lcx/lxc-privileged-to-unprivileged.sh +++ b/scripts/lcx/lxc-privileged-to-unprivileged.sh @@ -232,6 +232,10 @@ convert_direct_method() { fi msg_ok "$(translate 'Direct conversion completed for container') $CONTAINER_ID" + + echo -e + msg_success "Press Enter to continue..." + read -r } cleanup_and_finalize() { @@ -258,7 +262,7 @@ main() { msg_ok "$(translate 'Converted container ID:') $CONTAINER_ID" msg_ok "$(translate 'LXC conversion from privileged to unprivileged completed successfully!')" echo -e - msg_success "$(translate "Press Enter to continue")" + msg_success "$(translate "Press Enter to return to menu...")" read -r exit 0 } diff --git a/scripts/lcx/lxc-unprivileged-to-privileged.sh b/scripts/lcx/lxc-unprivileged-to-privileged.sh new file mode 100644 index 0000000..f197888 --- /dev/null +++ b/scripts/lcx/lxc-unprivileged-to-privileged.sh @@ -0,0 +1,144 @@ +#!/bin/bash + +# ========================================================== +# ProxMenu - LXC Unprivileged to Privileged Converter +# ========================================================== +# Author : MacRimi +# Copyright : (c) 2024 MacRimi +# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE) +# Version : 2.0 +# Last Updated: 19/08/2025 +# ========================================================== +# Description: +# This script converts an unprivileged LXC container to a privileged one +# by directly modifying the configuration file. +# WARNING: This reduces security. Use only when necessary. +# ========================================================== + +# Configuration ============================================ +REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main" +BASE_DIR="/usr/local/share/proxmenux" +UTILS_FILE="$BASE_DIR/utils.sh" +VENV_PATH="/opt/googletrans-env" + +if [[ -f "$UTILS_FILE" ]]; then + source "$UTILS_FILE" +fi + +load_language +initialize_cache + +# ========================================================== + + + +select_unprivileged_container() { + + CONTAINERS=$(pct list | awk 'NR>1 {print $1, $3}' | while read id name; do + if pct config "$id" | grep -q "^unprivileged: 1"; then + echo "$id" "$name" + fi + done | xargs -n2) + + if [ -z "$CONTAINERS" ]; then + msg_error "$(translate 'No unprivileged containers available in Proxmox.')" + exit 1 + fi + cleanup + CONTAINER_ID=$(whiptail --title "$(translate 'Select Unprivileged Container')" \ + --menu "$(translate 'Select the unprivileged LXC container to convert:')" 20 70 10 $CONTAINERS 3>&1 1>&2 2>&3) + + if [ -z "$CONTAINER_ID" ]; then + msg_error "$(translate 'No container selected. Exiting.')" + exit 1 + fi + + msg_ok "$(translate 'Unprivileged container selected:') $CONTAINER_ID" +} + +show_backup_warning() { + if ! whiptail --title "$(translate 'Backup Recommendation')" \ + --yes-button "$(translate 'Continue')" \ + --no-button "$(translate 'Exit')" \ + --yesno "$(translate 'It is recommended to create a backup before continuing.')" \ + 12 70; then + msg_info "$(translate 'Operation cancelled by user to create backup.')" + exit 0 + fi + +} + +convert_to_privileged() { + CONF_FILE="/etc/pve/lxc/$CONTAINER_ID.conf" + + CONTAINER_STATUS=$(pct status "$CONTAINER_ID" | awk '{print $2}') + + if [ "$CONTAINER_STATUS" == "running" ]; then + msg_info "$(translate 'Stopping container') $CONTAINER_ID..." + pct shutdown "$CONTAINER_ID" + + # Wait for container to stop + for i in {1..10}; do + sleep 1 + if [ "$(pct status "$CONTAINER_ID" | awk '{print $2}')" != "running" ]; then + break + fi + done + + # Verify container stopped + if [ "$(pct status "$CONTAINER_ID" | awk '{print $2}')" == "running" ]; then + msg_error "$(translate 'Failed to stop the container.')" + exit 1 + fi + + msg_ok "$(translate 'Container stopped.')" + else + msg_ok "$(translate 'Container is already stopped.')" + fi + + msg_info "$(translate 'Creating backup of configuration file...')" + cp "$CONF_FILE" "$CONF_FILE.bak" + msg_ok "$(translate 'Configuration backup created:') $CONF_FILE.bak" + + msg_info "$(translate 'Converting container to privileged...')" + sed -i '/^unprivileged: 1/d' "$CONF_FILE" + echo "unprivileged: 0" >> "$CONF_FILE" + + msg_ok "$(translate 'Container successfully converted to privileged.')" + + echo -e + msg_success "Press Enter to continue..." + read -r +} + +finalize_conversion() { + + if whiptail --yesno "$(translate 'Do you want to start the privileged container') $CONTAINER_ID $(translate 'now?')" 10 60; then + msg_info "$(translate 'Starting privileged container...')" + pct start "$CONTAINER_ID" + msg_ok "$(translate 'Privileged container') $CONTAINER_ID $(translate 'started successfully.')" + fi +} + +main() { + + show_proxmenux_logo + msg_title "$(translate "LXC Unprivileged to Privileged conversion")" + msg_info "$(translate 'Starting LXC Unprivileged to Privileged conversion process...')" + + + select_unprivileged_container + show_backup_warning + convert_to_privileged + finalize_conversion + + msg_ok "$(translate 'LXC conversion from unprivileged to privileged completed successfully!')" + msg_ "$(translate 'Converted container ID:') $CONTAINER_ID" + echo -e + msg_success "$(translate "Press Enter to return to menu...")" + read -r + exit 0 +} + +# Execute main function +main diff --git a/scripts/menus/lxc_menu.sh b/scripts/menus/lxc_menu.sh index 22d5c21..0ae05c0 100644 --- a/scripts/menus/lxc_menu.sh +++ b/scripts/menus/lxc_menu.sh @@ -30,42 +30,38 @@ initialize_cache # ========================================================== show_main_menu() { - CHOICE=$(dialog --backtitle "ProxMenux" --title "$(translate 'LXC Management')" \ + CHOICE=$(whiptail --title "$(translate 'LXC Conversion Management')" \ --menu "$(translate 'Select conversion option:')" 20 70 10 \ "1" "$(translate 'Convert Privileged to Unprivileged')" \ "2" "$(translate 'Convert Unprivileged to Privileged')" \ "3" "$(translate 'Show Container Privilege Status')" \ - "4" "$(translate 'Exit')" 3>&1 1>&2 2>&3) + "4" "$(translate "Help & Info (commands)")" \ + "5" "$(translate 'Exit')" 3>&1 1>&2 2>&3) case $CHOICE in 1) - bash <(curl -fsSL "$REPO_URL/scripts/lcx/lxc-privileged-to-unprivileged.sh") + bash <(curl -s "$REPO_URL/scripts/lxc/lxc-privileged-to-unprivileged.sh") ;; 2) - convert_unprivileged_to_privileged + bash <(curl -s "$REPO_URL/scripts/lxc/lxc-unprivileged-to-privileged.sh") ;; 3) show_container_status ;; 4) - exit 0 + bash <(curl -s "$REPO_URL/scripts/lxc/lxc-conversion-manual-guide.sh") + ;; + 5) + exec bash <(curl -s "$REPO_URL/scripts/menus/main_menu.sh") ;; *) - exit 0 - ;; + exec bash <(curl -s "$REPO_URL/scripts/menus/main_menu.sh") esac } -convert_unprivileged_to_privileged() { - - bash <(curl -fsSL "$REPO_URL/scripts/lcx/lxc-privileged-to-unprivileged.sh") - -} - show_container_status() { - show_proxmenux_logo msg_info "$(translate 'Gathering container privilege information...')" @@ -74,6 +70,7 @@ show_container_status() { echo "$(translate 'LXC Container Privilege Status')" > "$TEMP_FILE" echo "=================================" >> "$TEMP_FILE" echo "" >> "$TEMP_FILE" + pct list | awk 'NR>1 {print $1, $3}' | while read id name; do if pct config "$id" | grep -q "^unprivileged: 1"; then @@ -87,17 +84,21 @@ show_container_status() { printf "ID: %-4s | %-20s | %-12s | %s\n" "$id" "$name" "$status" "$running_status" >> "$TEMP_FILE" done + echo "" >> "$TEMP_FILE" + echo "$(translate 'Legend:')" >> "$TEMP_FILE" + echo "$(translate 'Privileged: Full host access (less secure)')" >> "$TEMP_FILE" + echo "$(translate 'Unprivileged: Limited access (more secure)')" >> "$TEMP_FILE" cleanup - dialog --backtitle "ProxMenux" --title "$(translate 'Container Status')" --textbox "$TEMP_FILE" 25 80 + dialog --title "$(translate 'Container Status')" --textbox "$TEMP_FILE" 25 80 rm -f "$TEMP_FILE" - show_main_menu + + show_main_menu } - - show_main_menu + show_main_menu