diff --git a/scripts/core/alpine-install.func b/scripts/core/alpine-install.func new file mode 100644 index 0000000..cc09f88 --- /dev/null +++ b/scripts/core/alpine-install.func @@ -0,0 +1,163 @@ +# Copyright (c) 2021-2025 community-scripts ORG +# Author: tteck (tteckster) +# Co-Author: MickLesk +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE + +if ! command -v curl >/dev/null 2>&1; then + apk update && apk add curl >/dev/null 2>&1 +fi + +load_functions + +# This function enables IPv6 if it's not disabled and sets verbose mode +verb_ip6() { + set_std_mode # Set STD mode based on VERBOSE + + if [ "$DISABLEIPV6" == "yes" ]; then + $STD sysctl -w net.ipv6.conf.all.disable_ipv6=1 + echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf + $STD rc-update add sysctl default + fi +} + +# This function catches errors and handles them with the error handler function +catch_errors() { + set -Eeuo pipefail + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR +} + +# This function handles errors +error_handler() { + local exit_code="$?" + local line_number="$1" + local command="$2" + local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}" + echo -e "\n$error_message\n" +} + +# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection +setting_up_container() { + msg_info "Setting up Container OS" + while [ $i -gt 0 ]; do + if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then + break + fi + echo 1>&2 -en "${CROSS}${RD} No Network! " + sleep $RETRY_EVERY + i=$((i - 1)) + done + + if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then + echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}" + echo -e "${NETWORK}Check Network Settings" + exit 1 + fi + msg_ok "Set up Container OS" + msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}" +} + +# This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected +network_check() { + set +e + trap - ERR + 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 "Internet Connected" + else + msg_error "Internet NOT Connected" + read -r -p "Would you like to continue anyway? " 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 + RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }') + if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to ${BL}$RESOLVEDIP${CL}"; fi + set -e + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR +} + +# This function updates the Container OS by running apt-get update and upgrade +update_os() { + msg_info "Updating Container OS" + $STD apk -U upgrade + #source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func) + msg_ok "Updated Container OS" +} + +# This function modifies the message of the day (motd) and SSH settings +motd_ssh() { + echo "export TERM='xterm-256color'" >>/root/.bashrc + IP=$(ip -4 addr show eth0 | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1) + + 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 '"') + else + OS_NAME="Alpine Linux" + OS_VERSION="Unknown" + fi + + PROFILE_FILE="/etc/profile.d/00_lxc-details.sh" + echo "echo -e \"\"" >"$PROFILE_FILE" + echo -e "echo -e \"${BOLD}${APPLICATION} LXC Container${CL}"\" >>"$PROFILE_FILE" + echo -e "echo -e \"${TAB}${GATEWAY}${YW} Provided by: ${GN}community-scripts ORG ${YW}| GitHub: ${GN}https://github.com/community-scripts/ProxmoxVE${CL}\"" >>"$PROFILE_FILE" + echo "echo \"\"" >>"$PROFILE_FILE" + echo -e "echo -e \"${TAB}${OS}${YW} OS: ${GN}${OS_NAME} - Version: ${OS_VERSION}${CL}\"" >>"$PROFILE_FILE" + echo -e "echo -e \"${TAB}${HOSTNAME}${YW} Hostname: ${GN}\$(hostname)${CL}\"" >>"$PROFILE_FILE" + echo -e "echo -e \"${TAB}${INFO}${YW} IP Address: ${GN}\$(ip -4 addr show eth0 | awk '/inet / {print \$2}' | cut -d/ -f1 | head -n 1)${CL}\"" >>"$PROFILE_FILE" + + # Configure SSH if enabled + if [[ "${SSH_ROOT}" == "yes" ]]; then + # Enable sshd service + $STD rc-update add sshd + # Allow root login via SSH + sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config + # Start the sshd service + $STD /etc/init.d/sshd start + fi +} + +# Validate Timezone for some LXC's +validate_tz() { + [[ -f "/usr/share/zoneinfo/$1" ]] +} + +# This function customizes the container and enables passwordless login for the root user +customize() { + if [[ "$PASSWORD" == "" ]]; then + msg_info "Customizing Container" + passwd -d root >/dev/null 2>&1 + + # Ensure agetty is available + apk add --no-cache --force-broken-world util-linux >/dev/null 2>&1 + + # Create persistent autologin boot script + mkdir -p /etc/local.d + cat <<'EOF' >/etc/local.d/autologin.start +#!/bin/sh +sed -i 's|^tty1::respawn:.*|tty1::respawn:/sbin/agetty --autologin root --noclear tty1 38400 linux|' /etc/inittab +kill -HUP 1 +EOF + touch /root/.hushlogin + + chmod +x /etc/local.d/autologin.start + rc-update add local >/dev/null 2>&1 + + # Apply autologin immediately for current session + /etc/local.d/autologin.start + + msg_ok "Customized Container" + fi + + echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update + chmod +x /usr/bin/update + + 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 +} \ No newline at end of file diff --git a/scripts/core/build.func b/scripts/core/build.func index 508d4bd..7fb98b4 100755 --- a/scripts/core/build.func +++ b/scripts/core/build.func @@ -972,7 +972,7 @@ install_script() { header_info echo -e "${INFO}${HOLD} ${GN}Using Config File on node $PVEHOST_NAME${CL}" METHOD="config_file" - source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/config-file.func) + source "$(dirname "${BASH_SOURCE[0]}")/config-file.func" config_file break ;; @@ -1046,7 +1046,7 @@ start() { source "$(dirname "${BASH_SOURCE[0]}")/tools.func" if command -v pveversion >/dev/null 2>&1; then install_script - echo "TEST!!!" + else CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "${APP} LXC Update/Setting" --menu \ "Support/Update functions for ${APP} LXC. Choose an option:" \ @@ -1076,7 +1076,7 @@ start() { # This function collects user settings and integrates all the collected information. build_container() { - echo "TEST" + # if [ "$VERBOSE" == "yes" ]; then set -x; fi NET_STRING="-net0 name=eth0,bridge=$BRG$MAC,ip=$NET$GATE$VLAN$MTU" @@ -1106,9 +1106,9 @@ build_container() { TEMP_DIR=$(mktemp -d) pushd "$TEMP_DIR" >/dev/null if [ "$var_os" == "alpine" ]; then - export FUNCTIONS_FILE_PATH="$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/alpine-install.func)" + export FUNCTIONS_FILE_PATH="$(cat "$(dirname "${BASH_SOURCE[0]}")/core.func" && echo && cat "$(dirname "${BASH_SOURCE[0]}")/tools.func" && echo && cat "$(dirname "${BASH_SOURCE[0]}")/alpine-install.func")" else - export FUNCTIONS_FILE_PATH="$(dirname "${BASH_SOURCE[0]}")/install.func" + export FUNCTIONS_FILE_PATH="$(cat "$(dirname "${BASH_SOURCE[0]}")/core.func" && echo && cat "$(dirname "${BASH_SOURCE[0]}")/tools.func" && echo && cat "$(dirname "${BASH_SOURCE[0]}")/install.func")" fi export DIAGNOSTICS="$DIAGNOSTICS" @@ -1336,9 +1336,8 @@ EOF' fi msg_ok "Customized LXC Container" - # Copy the install script into the container and execute it - pct push "$CTID" "$(dirname "${BASH_SOURCE[0]}")/../install/${var_install}.sh" "/tmp/${var_install}.sh" - lxc-attach -n "$CTID" -- bash "/tmp/${var_install}.sh" + + lxc-attach -n "$CTID" -- bash -c "$(cat "$(dirname "${BASH_SOURCE[0]}")/../install/${var_install}.sh")" } # This function sets the description of the container. diff --git a/scripts/core/config-file.func b/scripts/core/config-file.func new file mode 100644 index 0000000..0a37834 --- /dev/null +++ b/scripts/core/config-file.func @@ -0,0 +1,699 @@ +config_file() { + CONFIG_FILE="/opt/community-scripts/.settings" + + if [[ -f "/opt/community-scripts/${NSAPP}.conf" ]]; then + CONFIG_FILE="/opt/community-scripts/${NSAPP}.conf" + fi + + if CONFIG_FILE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set absolute path to config file" 8 58 "$CONFIG_FILE" --title "CONFIG FILE" 3>&1 1>&2 2>&3); then + if [[ ! -f "$CONFIG_FILE" ]]; then + echo -e "${CROSS}${RD}Config file not found, exiting script!.${CL}" + exit + else + echo -e "${INFO}${BOLD}${DGN}Using config File: ${BGN}$CONFIG_FILE${CL}" + source "$CONFIG_FILE" + fi + fi + if [[ -n "${CT_ID-}" ]]; then + if [[ "$CT_ID" =~ ^([0-9]{3,4})-([0-9]{3,4})$ ]]; then + MIN_ID=${BASH_REMATCH[1]} + MAX_ID=${BASH_REMATCH[2]} + if ((MIN_ID >= MAX_ID)); then + msg_error "Invalid Container ID range. The first number must be smaller than the second number, was ${CT_ID}" + exit + fi + + LIST_OF_IDS=$(pvesh get /cluster/resources --type vm --output-format json 2>/dev/null | grep -oP '"vmid":\s*\K\d+') || true + if [[ -n "$LIST_OF_IDS" ]]; then + for ((ID = MIN_ID; ID <= MAX_ID; ID++)); do + if ! grep -q "^$ID$" <<<"$LIST_OF_IDS"; then + CT_ID=$ID + break + fi + done + fi + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + + elif [[ "$CT_ID" =~ ^[0-9]+$ ]]; then + LIST_OF_IDS=$(pvesh get /cluster/resources --type vm --output-format json 2>/dev/null | grep -oP '"vmid":\s*\K\d+') || true + if [[ -n "$LIST_OF_IDS" ]]; then + + if ! grep -q "^$CT_ID$" <<<"$LIST_OF_IDS"; then + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + else + msg_error "Container ID $CT_ID already exists" + exit + fi + else + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + fi + else + msg_error "Invalid Container ID format. Needs to be 0000-9999 or 0-9999, was ${CT_ID}" + exit + fi + else + if CT_ID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Container ID" 8 58 "$NEXTID" --title "CONTAINER ID" 3>&1 1>&2 2>&3); then + if [ -z "$CT_ID" ]; then + CT_ID="$NEXTID" + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + else + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + fi + else + exit_script + fi + + fi + if [[ -n "${CT_TYPE-}" ]]; then + if [[ "$CT_TYPE" -eq 0 ]]; then + CT_TYPE_DESC="Privileged" + elif [[ "$CT_TYPE" -eq 1 ]]; then + CT_TYPE_DESC="Unprivileged" + else + msg_error "Unknown setting for CT_TYPE, should be 1 or 0, was ${CT_TYPE}" + exit + fi + echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}" + else + if CT_TYPE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CONTAINER TYPE" --radiolist "Choose Type" 10 58 2 \ + "1" "Unprivileged" ON \ + "0" "Privileged" OFF \ + 3>&1 1>&2 2>&3); then + if [ -n "$CT_TYPE" ]; then + CT_TYPE_DESC="Unprivileged" + if [ "$CT_TYPE" -eq 0 ]; then + CT_TYPE_DESC="Privileged" + fi + echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}" + fi + else + exit_script + fi + fi + + if [[ -n "${PW-}" ]]; then + if [[ "$PW" == "none" ]]; then + PW="" + else + if [[ "$PW" == *" "* ]]; then + msg_error "Password cannot be empty" + exit + elif [[ ${#PW} -lt 5 ]]; then + msg_error "Password must be at least 5 characters long" + exit + else + echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}" + fi + PW="-password $PW" + fi + else + while true; do + if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nSet Root Password (needed for root ssh access)" 9 58 --title "PASSWORD (leave blank for automatic login)" 3>&1 1>&2 2>&3); then + if [[ -n "$PW1" ]]; then + if [[ "$PW1" == *" "* ]]; then + whiptail --msgbox "Password cannot contain spaces. Please try again." 8 58 + elif [ ${#PW1} -lt 5 ]; then + whiptail --msgbox "Password must be at least 5 characters long. Please try again." 8 58 + else + if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then + if [[ "$PW1" == "$PW2" ]]; then + PW="-password $PW1" + echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}" + break + else + whiptail --msgbox "Passwords do not match. Please try again." 8 58 + fi + else + exit_script + fi + fi + else + PW1="Automatic Login" + PW="" + echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}$PW1${CL}" + break + fi + else + exit_script + fi + done + fi + + if [[ -n "${HN-}" ]]; then + echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}" + else + if CT_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$NSAPP" --title "HOSTNAME" 3>&1 1>&2 2>&3); then + if [ -z "$CT_NAME" ]; then + HN="$NSAPP" + else + HN=$(echo "${CT_NAME,,}" | tr -d ' ') + fi + echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}" + else + exit_script + fi + fi + + if [[ -n "${DISK_SIZE-}" ]]; then + if [[ "$DISK_SIZE" =~ ^-?[0-9]+$ ]]; then + echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}" + else + msg_error "DISK_SIZE must be an integer, was ${DISK_SIZE}" + exit + fi + else + if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GB" 8 58 "$var_disk" --title "DISK SIZE" 3>&1 1>&2 2>&3); then + if [ -z "$DISK_SIZE" ]; then + DISK_SIZE="$var_disk" + echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}" + else + if ! [[ $DISK_SIZE =~ $INTEGER ]]; then + echo -e "{INFO}${HOLD}${RD} DISK SIZE MUST BE AN INTEGER NUMBER!${CL}" + advanced_settings + fi + echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}" + fi + else + exit_script + fi + fi + + if [[ -n "${CORE_COUNT-}" ]]; then + if [[ "$CORE_COUNT" =~ ^-?[0-9]+$ ]]; then + echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}" + else + msg_error "CORE_COUNT must be an integer, was ${CORE_COUNT}" + exit + fi + else + if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 "$var_cpu" --title "CORE COUNT" 3>&1 1>&2 2>&3); then + if [ -z "$CORE_COUNT" ]; then + CORE_COUNT="$var_cpu" + echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}" + else + echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}" + fi + else + exit_script + fi + fi + + if [[ -n "${RAM_SIZE-}" ]]; then + if [[ "$RAM_SIZE" =~ ^-?[0-9]+$ ]]; then + echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" + else + msg_error "RAM_SIZE must be an integer, was ${RAM_SIZE}" + exit + fi + else + if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 "$var_ram" --title "RAM" 3>&1 1>&2 2>&3); then + if [ -z "$RAM_SIZE" ]; then + RAM_SIZE="$var_ram" + echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" + else + echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" + fi + else + exit_script + fi + fi + + IFACE_FILEPATH_LIST="/etc/network/interfaces"$'\n'$(find "/etc/network/interfaces.d/" -type f) + BRIDGES="" + OLD_IFS=$IFS + IFS=$'\n' + + for iface_filepath in ${IFACE_FILEPATH_LIST}; do + + iface_indexes_tmpfile=$(mktemp -q -u '.iface-XXXX') + (grep -Pn '^\s*iface' "${iface_filepath}" | cut -d':' -f1 && wc -l "${iface_filepath}" | cut -d' ' -f1) | awk 'FNR==1 {line=$0; next} {print line":"$0-1; line=$0}' >"${iface_indexes_tmpfile}" || true + + if [ -f "${iface_indexes_tmpfile}" ]; then + + while read -r pair; do + start=$(echo "${pair}" | cut -d':' -f1) + end=$(echo "${pair}" | cut -d':' -f2) + if awk "NR >= ${start} && NR <= ${end}" "${iface_filepath}" | grep -qP '^\s*(bridge[-_](ports|stp|fd|vlan-aware|vids)|ovs_type\s+OVSBridge)\b'; then + iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}') + BRIDGES="${iface_name}"$'\n'"${BRIDGES}" + fi + + done <"${iface_indexes_tmpfile}" + rm -f "${iface_indexes_tmpfile}" + fi + + done + IFS=$OLD_IFS + BRIDGES=$(echo "$BRIDGES" | grep -v '^\s*$' | sort | uniq) + + if [[ -n "${BRG-}" ]]; then + if echo "$BRIDGES" | grep -q "${BRG}"; then + echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}" + else + msg_error "Bridge '${BRG}' does not exist in /etc/network/interfaces or /etc/network/interfaces.d/sdn" + exit + fi + else + BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu "Select network bridge:" 15 40 6 $(echo "$BRIDGES" | awk '{print $0, "Bridge"}') 3>&1 1>&2 2>&3) + if [ -z "$BRG" ]; then + exit_script + else + echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}" + fi + fi + + local ip_cidr_regex='^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/([0-9]{1,2})$' + local ip_regex='^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$' + + if [[ -n ${NET-} ]]; then + if [ "$NET" == "dhcp" ]; then + echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}DHCP${CL}" + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}Default${CL}" + GATE="" + elif [[ "$NET" =~ $ip_cidr_regex ]]; then + echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}" + if [[ -n "$GATE" ]]; then + [[ "$GATE" =~ ",gw=" ]] && GATE="${GATE##,gw=}" + if [[ "$GATE" =~ $ip_regex ]]; then + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE${CL}" + GATE=",gw=$GATE" + else + msg_error "Invalid IP Address format for Gateway. Needs to be 0.0.0.0, was ${GATE}" + exit + fi + + else + while true; do + GATE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Enter gateway IP address" 8 58 --title "Gateway IP" 3>&1 1>&2 2>&3) + if [ -z "$GATE1" ]; then + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Gateway IP address cannot be empty" 8 58 + elif [[ ! "$GATE1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Invalid IP address format" 8 58 + else + GATE=",gw=$GATE1" + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE1${CL}" + break + fi + done + fi + elif [[ "$NET" == *-* ]]; then + IFS="-" read -r ip_start ip_end <<<"$NET" + + if [[ ! "$ip_start" =~ $ip_cidr_regex ]] || [[ ! "$ip_end" =~ $ip_cidr_regex ]]; then + msg_error "Invalid IP range format, was $NET should be 0.0.0.0/0-0.0.0.0/0" + exit 1 + fi + + ip1="${ip_start%%/*}" + ip2="${ip_end%%/*}" + cidr="${ip_start##*/}" + + ip_to_int() { + local IFS=. + read -r i1 i2 i3 i4 <<<"$1" + echo $(((i1 << 24) + (i2 << 16) + (i3 << 8) + i4)) + } + + int_to_ip() { + local ip=$1 + echo "$(((ip >> 24) & 0xFF)).$(((ip >> 16) & 0xFF)).$(((ip >> 8) & 0xFF)).$((ip & 0xFF))" + } + + start_int=$(ip_to_int "$ip1") + end_int=$(ip_to_int "$ip2") + + for ((ip_int = start_int; ip_int <= end_int; ip_int++)); do + ip=$(int_to_ip $ip_int) + msg_info "Checking IP: $ip" + if ! ping -c 2 -W 1 "$ip" >/dev/null 2>&1; then + NET="$ip/$cidr" + msg_ok "Using free IP Address: ${BGN}$NET${CL}" + sleep 3 + break + fi + done + if [[ "$NET" == *-* ]]; then + msg_error "No free IP found in range" + exit 1 + fi + if [ -n "$GATE" ]; then + if [[ "$GATE" =~ $ip_regex ]]; then + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE${CL}" + GATE=",gw=$GATE" + else + msg_error "Invalid IP Address format for Gateway. Needs to be 0.0.0.0, was ${GATE}" + exit + fi + else + while true; do + GATE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Enter gateway IP address" 8 58 --title "Gateway IP" 3>&1 1>&2 2>&3) + if [ -z "$GATE1" ]; then + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Gateway IP address cannot be empty" 8 58 + elif [[ ! "$GATE1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Invalid IP address format" 8 58 + else + GATE=",gw=$GATE1" + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE1${CL}" + break + fi + done + fi + else + msg_error "Invalid IP Address format. Needs to be 0.0.0.0/0 or a range like 10.0.0.1/24-10.0.0.10/24, was ${NET}" + exit + fi + else + while true; do + NET=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Static IPv4 CIDR Address (/24)" 8 58 dhcp --title "IP ADDRESS" 3>&1 1>&2 2>&3) + exit_status=$? + if [ $exit_status -eq 0 ]; then + if [ "$NET" = "dhcp" ]; then + echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}" + break + else + if [[ "$NET" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$ ]]; then + echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}" + break + else + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "$NET is an invalid IPv4 CIDR address. Please enter a valid IPv4 CIDR address or 'dhcp'" 8 58 + fi + fi + else + exit_script + fi + done + if [ "$NET" != "dhcp" ]; then + while true; do + GATE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Enter gateway IP address" 8 58 --title "Gateway IP" 3>&1 1>&2 2>&3) + if [ -z "$GATE1" ]; then + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Gateway IP address cannot be empty" 8 58 + elif [[ ! "$GATE1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Invalid IP address format" 8 58 + else + GATE=",gw=$GATE1" + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE1${CL}" + break + fi + done + else + GATE="" + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}Default${CL}" + fi + fi + + if [ "$var_os" == "alpine" ]; then + APT_CACHER="" + APT_CACHER_IP="" + else + if [[ -n "${APT_CACHER_IP-}" ]]; then + if [[ ! $APT_CACHER_IP == "none" ]]; then + APT_CACHER="yes" + echo -e "${NETWORK}${BOLD}${DGN}APT-CACHER IP Address: ${BGN}$APT_CACHER_IP${CL}" + else + APT_CACHER="" + echo -e "${NETWORK}${BOLD}${DGN}APT-Cacher IP Address: ${BGN}No${CL}" + fi + else + if APT_CACHER_IP=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set APT-Cacher IP (leave blank for none)" 8 58 --title "APT-Cacher IP" 3>&1 1>&2 2>&3); then + APT_CACHER="${APT_CACHER_IP:+yes}" + echo -e "${NETWORK}${BOLD}${DGN}APT-Cacher IP Address: ${BGN}${APT_CACHER_IP:-Default}${CL}" + if [[ -n $APT_CACHER_IP ]]; then + APT_CACHER_IP="none" + fi + else + exit_script + fi + fi + fi + + if [[ -n "${MTU-}" ]]; then + if [[ "$MTU" =~ ^-?[0-9]+$ ]]; then + echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU${CL}" + MTU=",mtu=$MTU" + else + msg_error "MTU must be an integer, was ${MTU}" + exit + fi + else + if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default [The MTU of your selected vmbr, default is 1500])" 8 58 --title "MTU SIZE" 3>&1 1>&2 2>&3); then + if [ -z "$MTU1" ]; then + MTU1="Default" + MTU="" + else + MTU=",mtu=$MTU1" + fi + echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}" + else + exit_script + fi + fi + + if [[ "$IPV6_METHOD" == "static" ]]; then + if [[ -n "$IPV6STATIC" ]]; then + IP6=",ip6=${IPV6STATIC}" + echo -e "${NETWORK}${BOLD}${DGN}IPv6 Address: ${BGN}${IPV6STATIC}${CL}" + else + msg_error "IPV6_METHOD is set to static but IPV6STATIC is empty" + exit + fi + elif [[ "$IPV6_METHOD" == "auto" ]]; then + IP6=",ip6=auto" + echo -e "${NETWORK}${BOLD}${DGN}IPv6 Address: ${BGN}auto${CL}" + else + IP6="" + echo -e "${NETWORK}${BOLD}${DGN}IPv6 Address: ${BGN}none${CL}" + fi + + if [[ -n "${SD-}" ]]; then + if [[ "$SD" == "none" ]]; then + SD="" + echo -e "${SEARCH}${BOLD}${DGN}DNS Search Domain: ${BGN}Host${CL}" + else + # Strip prefix if present for config file storage + local SD_VALUE="$SD" + [[ "$SD" =~ ^-searchdomain= ]] && SD_VALUE="${SD#-searchdomain=}" + echo -e "${SEARCH}${BOLD}${DGN}DNS Search Domain: ${BGN}$SD_VALUE${CL}" + SD="-searchdomain=$SD_VALUE" + fi + else + if SD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a DNS Search Domain (leave blank for HOST)" 8 58 --title "DNS Search Domain" 3>&1 1>&2 2>&3); then + if [ -z "$SD" ]; then + SX=Host + SD="" + else + SX=$SD + SD="-searchdomain=$SD" + fi + echo -e "${SEARCH}${BOLD}${DGN}DNS Search Domain: ${BGN}$SX${CL}" + else + exit_script + fi + fi + + if [[ -n "${NS-}" ]]; then + if [[ $NS == "none" ]]; then + NS="" + echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}Host${CL}" + else + # Strip prefix if present for config file storage + local NS_VALUE="$NS" + [[ "$NS" =~ ^-nameserver= ]] && NS_VALUE="${NS#-nameserver=}" + if [[ "$NS_VALUE" =~ $ip_regex ]]; then + echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}$NS_VALUE${CL}" + NS="-nameserver=$NS_VALUE" + else + msg_error "Invalid IP Address format for DNS Server. Needs to be 0.0.0.0, was ${NS_VALUE}" + exit + fi + fi + else + if NX=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a DNS Server IP (leave blank for HOST)" 8 58 --title "DNS SERVER IP" 3>&1 1>&2 2>&3); then + if [ -z "$NX" ]; then + NX=Host + NS="" + else + NS="-nameserver=$NX" + fi + echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}$NX${CL}" + else + exit_script + fi + fi + + if [[ -n "${MAC-}" ]]; then + if [[ "$MAC" == "none" ]]; then + MAC="" + echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}Host${CL}" + else + # Strip prefix if present for config file storage + local MAC_VALUE="$MAC" + [[ "$MAC" =~ ^,hwaddr= ]] && MAC_VALUE="${MAC#,hwaddr=}" + if [[ "$MAC_VALUE" =~ ^([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}$ ]]; then + echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC_VALUE${CL}" + MAC=",hwaddr=$MAC_VALUE" + else + msg_error "MAC Address must be in the format xx:xx:xx:xx:xx:xx, was ${MAC_VALUE}" + exit + fi + fi + else + if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address(leave blank for generated MAC)" 8 58 --title "MAC ADDRESS" 3>&1 1>&2 2>&3); then + if [ -z "$MAC1" ]; then + MAC1="Default" + MAC="" + else + MAC=",hwaddr=$MAC1" + echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC1${CL}" + fi + else + exit_script + fi + fi + + if [[ -n "${VLAN-}" ]]; then + if [[ "$VLAN" == "none" ]]; then + VLAN="" + echo -e "${VLANTAG}${BOLD}${DGN}Vlan: ${BGN}Host${CL}" + else + # Strip prefix if present for config file storage + local VLAN_VALUE="$VLAN" + [[ "$VLAN" =~ ^,tag= ]] && VLAN_VALUE="${VLAN#,tag=}" + if [[ "$VLAN_VALUE" =~ ^-?[0-9]+$ ]]; then + echo -e "${VLANTAG}${BOLD}${DGN}Vlan: ${BGN}$VLAN_VALUE${CL}" + VLAN=",tag=$VLAN_VALUE" + else + msg_error "VLAN must be an integer, was ${VLAN_VALUE}" + exit + fi + fi + else + if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for no VLAN)" 8 58 --title "VLAN" 3>&1 1>&2 2>&3); then + if [ -z "$VLAN1" ]; then + VLAN1="Default" + VLAN="" + else + VLAN=",tag=$VLAN1" + fi + echo -e "${VLANTAG}${BOLD}${DGN}Vlan: ${BGN}$VLAN1${CL}" + else + exit_script + fi + fi + + if [[ -n "${TAGS-}" ]]; then + if [[ "$TAGS" == *"DEFAULT"* ]]; then + TAGS="${TAGS//DEFAULT/}" + TAGS="${TAGS//;/}" + TAGS="$TAGS;${var_tags:-}" + echo -e "${NETWORK}${BOLD}${DGN}Tags: ${BGN}$TAGS${CL}" + fi + else + TAGS="community-scripts;" + if ADV_TAGS=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Custom Tags?[If you remove all, there will be no tags!]" 8 58 "${TAGS}" --title "Advanced Tags" 3>&1 1>&2 2>&3); then + if [ -n "${ADV_TAGS}" ]; then + ADV_TAGS=$(echo "$ADV_TAGS" | tr -d '[:space:]') + TAGS="${ADV_TAGS}" + else + TAGS=";" + fi + echo -e "${NETWORK}${BOLD}${DGN}Tags: ${BGN}$TAGS${CL}" + else + exit_script + fi + fi + + if [[ -n "${SSH-}" ]]; then + if [[ "$SSH" == "yes" ]]; then + echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" + if [[ ! -z "$SSH_AUTHORIZED_KEY" ]]; then + echo -e "${ROOTSSH}${BOLD}${DGN}SSH Authorized Key: ${BGN}********************${CL}" + else + echo -e "${ROOTSSH}${BOLD}${DGN}SSH Authorized Key: ${BGN}None${CL}" + fi + elif [[ "$SSH" == "no" ]]; then + echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" + else + msg_error "SSH needs to be 'yes' or 'no', was ${SSH}" + exit + fi + else + SSH_AUTHORIZED_KEY="$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "SSH Authorized key for root (leave empty for none)" 8 58 --title "SSH Key" 3>&1 1>&2 2>&3)" + if [[ -z "${SSH_AUTHORIZED_KEY}" ]]; then + SSH_AUTHORIZED_KEY="" + fi + if [[ "$PW" == -password* || -n "$SSH_AUTHORIZED_KEY" ]]; then + if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable Root SSH Access?" 10 58); then + SSH="yes" + else + SSH="no" + fi + echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" + else + SSH="no" + echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" + fi + fi + + if [[ -n "$ENABLE_FUSE" ]]; then + if [[ "$ENABLE_FUSE" == "yes" ]]; then + echo -e "${FUSE}${BOLD}${DGN}Enable FUSE: ${BGN}Yes${CL}" + elif [[ "$ENABLE_FUSE" == "no" ]]; then + echo -e "${FUSE}${BOLD}${DGN}Enable FUSE: ${BGN}No${CL}" + else + msg_error "Enable FUSE needs to be 'yes' or 'no', was ${ENABLE_FUSE}" + exit + fi + else + if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE" --yesno "Enable FUSE?" 10 58); then + ENABLE_FUSE="yes" + else + ENABLE_FUSE="no" + fi + echo -e "${FUSE}${BOLD}${DGN}Enable FUSE: ${BGN}$ENABLE_FUSE${CL}" + fi + + if [[ -n "$ENABLE_TUN" ]]; then + if [[ "$ENABLE_TUN" == "yes" ]]; then + echo -e "${FUSE}${BOLD}${DGN}Enable TUN: ${BGN}Yes${CL}" + elif [[ "$ENABLE_TUN" == "no" ]]; then + echo -e "${FUSE}${BOLD}${DGN}Enable TUN: ${BGN}No${CL}" + else + msg_error "Enable TUN needs to be 'yes' or 'no', was ${ENABLE_TUN}" + exit + fi + else + if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "TUN" --yesno "Enable TUN?" 10 58); then + ENABLE_TUN="yes" + else + ENABLE_TUN="no" + fi + echo -e "${FUSE}${BOLD}${DGN}Enable TUN: ${BGN}$ENABLE_TUN${CL}" + fi + + if [[ -n "${VERBOSE-}" ]]; then + if [[ "$VERBOSE" == "yes" ]]; then + echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERBOSE${CL}" + elif [[ "$VERBOSE" == "no" ]]; then + echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}No${CL}" + else + msg_error "Verbose Mode needs to be 'yes' or 'no', was ${VERBOSE}" + exit + fi + else + if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then + VERBOSE="yes" + else + VERBOSE="no" + fi + echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERBOSE${CL}" + fi + + if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS WITH CONFIG FILE COMPLETE" --yesno "Ready to create ${APP} LXC?" 10 58); then + echo -e "${CREATING}${BOLD}${RD}Creating a ${APP} LXC using the above settings${CL}" + else + clear + header_info + echo -e "${INFO}${HOLD} ${GN}Using Config File on node $PVEHOST_NAME${CL}" + config_file + fi +} \ No newline at end of file diff --git a/scripts/core/install.func b/scripts/core/install.func index 7758b17..0fd7c59 100755 --- a/scripts/core/install.func +++ b/scripts/core/install.func @@ -8,7 +8,7 @@ if ! command -v curl >/dev/null 2>&1; then apt-get update >/dev/null 2>&1 apt-get install -y curl >/dev/null 2>&1 fi -source "$(dirname "${BASH_SOURCE[0]}")/core.func" +# core.func is included in FUNCTIONS_FILE_PATH load_functions # This function enables IPv6 if it's not disabled and sets verbose mode verb_ip6() { @@ -145,7 +145,7 @@ EOF rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED msg_ok "Updated Container OS" - source "$(dirname "${BASH_SOURCE[0]}")/tools.func") + # tools.func is included in FUNCTIONS_FILE_PATH } # This function modifies the message of the day (motd) and SSH settings diff --git a/scripts/ct/2fauth.sh b/scripts/ct/2fauth.sh new file mode 100644 index 0000000..ea78683 --- /dev/null +++ b/scripts/ct/2fauth.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +SCRIPT_DIR="$(dirname "$0")" +source "$SCRIPT_DIR/../core/build.func" +# Copyright (c) 2021-2025 community-scripts ORG +# Author: jkrgr0 +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://docs.2fauth.app/ + +APP="2FAuth" +var_tags="${var_tags:-2fa;authenticator}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-512}" +var_disk="${var_disk:-2}" +var_os="${var_os:-debian}" +var_version="${var_version:-12}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d "/opt/2fauth" ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + if check_for_gh_release "2fauth" "Bubka/2FAuth"; then + $STD apt-get update + $STD apt-get -y upgrade + + msg_info "Creating Backup" + mv "/opt/2fauth" "/opt/2fauth-backup" + if ! dpkg -l | grep -q 'php8.3'; then + cp /etc/nginx/conf.d/2fauth.conf /etc/nginx/conf.d/2fauth.conf.bak + fi + msg_ok "Backup Created" + + if ! dpkg -l | grep -q 'php8.3'; then + $STD apt-get install -y \ + lsb-release \ + gnupg2 + PHP_VERSION="8.3" PHP_MODULE="common,ctype,fileinfo,mysql,cli" PHP_FPM="YES" setup_php + sed -i 's/php8.2/php8.3/g' /etc/nginx/conf.d/2fauth.conf + fi + fetch_and_deploy_gh_release "2fauth" "Bubka/2FAuth" + setup_composer + mv "/opt/2fauth-backup/.env" "/opt/2fauth/.env" + mv "/opt/2fauth-backup/storage" "/opt/2fauth/storage" + cd "/opt/2fauth" || return + chown -R www-data: "/opt/2fauth" + chmod -R 755 "/opt/2fauth" + export COMPOSER_ALLOW_SUPERUSER=1 + $STD composer install --no-dev --prefer-source + php artisan 2fauth:install + $STD systemctl restart nginx + + msg_info "Cleaning Up" + if dpkg -l | grep -q 'php8.2'; then + $STD apt-get remove --purge -y php8.2* + fi + $STD apt-get -y autoremove + $STD apt-get -y autoclean + msg_ok "Cleanup Completed" + msg_ok "Updated Successfully" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:80${CL}" diff --git a/scripts/ct/alpine.sh b/scripts/ct/alpine.sh new file mode 100644 index 0000000..3d697d8 --- /dev/null +++ b/scripts/ct/alpine.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +SCRIPT_DIR="$(dirname "$0")" +source "$SCRIPT_DIR/../core/build.func" +# Copyright (c) 2021-2025 tteck +# Author: tteck (tteckster) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://alpinelinux.org/ + +APP="Alpine" +var_tags="${var_tags:-os;alpine}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-512}" +var_disk="${var_disk:-1}" +var_os="${var_os:-alpine}" +var_version="${var_version:-3.22}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + UPD=$( + whiptail --backtitle "Proxmox VE Helper Scripts" --title "SUPPORT" --radiolist --cancel-button Exit-Script "Spacebar = Select" 11 58 1 \ + "1" "Check for Alpine Updates" ON \ + 3>&1 1>&2 2>&3 + ) + + header_info + if [ "$UPD" == "1" ]; then + $STD apk -U upgrade + exit + fi +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" diff --git a/scripts/install/2fauth-install.sh b/scripts/install/2fauth-install.sh new file mode 100644 index 0000000..294f5ff --- /dev/null +++ b/scripts/install/2fauth-install.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2025 community-scripts ORG +# Author: jkrgr0 +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://docs.2fauth.app/ + +echo "TEST" + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt-get install -y \ + lsb-release \ + nginx +msg_ok "Installed Dependencies" + +PHP_VERSION="8.3" PHP_MODULE="common,ctype,fileinfo,mysql,cli" PHP_FPM="YES" setup_php +setup_composer +setup_mariadb + +msg_info "Setting up Database" +DB_NAME=2fauth_db +DB_USER=2fauth +DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) +$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;" +$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';" +$STD mariadb -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;" +{ + echo "2FAuth Credentials" + echo "Database User: $DB_USER" + echo "Database Password: $DB_PASS" + echo "Database Name: $DB_NAME" +} >>~/2FAuth.creds +msg_ok "Set up Database" + +fetch_and_deploy_gh_release "2fauth" "Bubka/2FAuth" + +msg_info "Setup 2FAuth" +cd /opt/2fauth +cp .env.example .env +IPADDRESS=$(hostname -I | awk '{print $1}') +sed -i -e "s|^APP_URL=.*|APP_URL=http://$IPADDRESS|" \ + -e "s|^DB_CONNECTION=$|DB_CONNECTION=mysql|" \ + -e "s|^DB_DATABASE=$|DB_DATABASE=$DB_NAME|" \ + -e "s|^DB_HOST=$|DB_HOST=127.0.0.1|" \ + -e "s|^DB_PORT=$|DB_PORT=3306|" \ + -e "s|^DB_USERNAME=$|DB_USERNAME=$DB_USER|" \ + -e "s|^DB_PASSWORD=$|DB_PASSWORD=$DB_PASS|" .env +export COMPOSER_ALLOW_SUPERUSER=1 +$STD composer update --no-plugins --no-scripts +$STD composer install --no-dev --prefer-source --no-plugins --no-scripts +$STD php artisan key:generate --force +$STD php artisan migrate:refresh +$STD php artisan passport:install -q -n +$STD php artisan storage:link +$STD php artisan config:cache +chown -R www-data: /opt/2fauth +chmod -R 755 /opt/2fauth +msg_ok "Setup 2fauth" + +msg_info "Configure Service" +cat </etc/nginx/conf.d/2fauth.conf +server { + listen 80; + root /opt/2fauth/public; + server_name $IPADDRESS; + index index.php; + charset utf-8; + + location / { + try_files \$uri \$uri/ /index.php?\$query_string; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + error_page 404 /index.php; + + location ~ \.php\$ { + fastcgi_pass unix:/var/run/php/php8.3-fpm.sock; + fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name; + include fastcgi_params; + } + + location ~ /\.(?!well-known).* { + deny all; + } +} +EOF +systemctl reload nginx +msg_ok "Configured Service" + +motd_ssh +customize + +msg_info "Cleaning up" +$STD apt-get -y autoremove +$STD apt-get -y autoclean +msg_ok "Cleaned" diff --git a/scripts/install/alpine-install.sh b/scripts/install/alpine-install.sh new file mode 100644 index 0000000..1c01e01 --- /dev/null +++ b/scripts/install/alpine-install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2025 tteck +# Author: tteck (tteckster) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://alpinelinux.org/ + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apk add sudo +msg_ok "Installed Dependencies" + +motd_ssh +customize