Proxmox install scripts for ipxe-buildweb, rom-o-matic and ipxe-simple (ipxe firmware build manager web UI)

shodan

Active Member
Sep 1, 2022
139
38
33
Hi,

As I experiment with iPXE, an open source network bootloader firmware, I have to rebuild it with HTTPS support that is missing from the official releases.

https://boot.ipxe.org/

These scripts are meant to be directly pasted into the proxmox console and will create an LXC container ready to use

ipxe-buildweb
https://github.com/xbgmsharp/ipxe-buildweb
1735872578002.png
Code:
#----------------------------------------
# stop in case of errors
#set -e # this breaks on or soon after pct create
# shell function to create --net variable
addnet() { CT_net_count=${CT_net_count:-0}; local net_name=$1; shift; local _CT_new_config="--net$CT_net_count name=$net_name"; local valid_params=("bridge" "firewall" "gw" "gw6" "hwaddr" "ip" "ip6" "link_down" "mtu" "rate" "tag" "trunks" "type"); while [ $# -gt 0 ]; do key=$1; value=$2; if [[ " ${valid_params[*]} " =~ " $key " ]]; then _CT_new_config="$_CT_new_config,$key=$value"; shift 2; else shift 1; fi; done; _CT_net_config="$_CT_net_config $_CT_new_config"; echo "Interface added: $_CT_new_config"; CT_net_count=$((CT_net_count + 1)); }
# shell function to create user variables
adduser() { user_ubound=$((user_ubound + 1)); local user_and_group=$1; IFS=':' read -r username group <<< "$user_and_group"; eval "user_name_${user_ubound}=\"$username\""; [ -n "$group" ] && eval "user_group_${user_ubound}=\"$group\""; shift 1; while [ $# -gt 0 ]; do case $1 in nologin) eval "user_shell_${user_ubound}='/usr/sbin/nologin'" ;; shell) shift 1; eval "user_shell_${user_ubound}=\"$1\"" ;; groups) shift 1; eval "user_groups_${user_ubound}=\"$1\"" ;; nopassword) eval "user_password_${user_ubound}=$(printf '%s' '!')" ;; password) shift 1; eval "user_password_${user_ubound}=\"$1\"" ;; lock) eval "user_lock_${user_ubound}=true" ;; *) echo "Warning: Unrecognized option '$1'" ;; esac; shift 1; done; }
createuser() { local i=$1; local username=$(eval echo "\$user_name_${i}"); local group=$(eval echo "\$user_group_${i}"); local shell=$(eval echo "\$user_shell_${i}"); local password=$(eval echo "\$user_password_${i}"); local groups=$(eval echo "\$user_groups_${i}"); local lock=$(eval echo "\$user_lock_${i}"); [ -n "$shell" ] && shell_option="-s $shell" || shell_option="-s /bin/bash"; [ -n "$group" ] && group_option="-g $group" || group_option=""; pct_exec useradd $shell_option $group_option "$username"; [ -n "$password" ] && pct_set_password "$username:$password"; [ "$password" = "!" ] && pct_exec usermod -L "$username"; [ "$lock" = "true" ] && pct_exec usermod -L "$username"; pct_exec mkdir -p "/home/$username"; [ -n "$group" ] && pct_exec chown "$username:$group" "/home/$username" || pct_exec chown "$username" "/home/$username"; [ -n "$groups" ] && pct_exec usermod -aG "$groups" "$username"; unset username group shell password groups lock; }
# shell function for create each file line variables
addline() { file_line_ubound=$((file_line_ubound + 1)); eval "file_line_${file_line_ubound}_${file_ubound}=\"$1\""; eval "file_line_count_${file_ubound}=$file_line_ubound"; }
addfile() { file_ubound=$((file_ubound + 1)); eval "file_name_${file_ubound}=\"$1\""; [ -n "$2" ] && [[ "$2" =~ ^[0-9]+$ ]] && eval "filepermission_${file_ubound}=\"$2\""; [ -n "$3" ] && eval "fileowner_${file_ubound}=\"$3\""; unset file_line_ubound; }
pct_append_text() { local file=$1; local text_or_var=$2; if [ -n "${!text_or_var}" ]; then local text=${!text_or_var}; elif [[ "$text_or_var" == file_line* ]]; then local text=$(eval echo \${$text_or_var}); else local text="$text_or_var"; fi; local command="echo \"$text\" >> \"$file\""; [ "$VERBOSE" -gt 0 ] && echo "pct exec $CT_ID -- /bin/sh -c \"$command\""; pct exec $CT_ID -- /bin/sh -c "$command"; }
writefile() { local file_index=$1; local file_name=$(eval echo \${file_name_${file_index}}); local file_permission=$(eval echo \${filepermission_${file_index}}); local file_owner=$(eval echo \${fileowner_${file_index}}); local file_line_count=$(eval echo \${file_line_count_${file_index}}); pct_exec mkdir -p "$(dirname "$file_name")"; for i in $(seq 1 $file_line_count); do local file_line_var="file_line_${i}_${file_index}"; pct_append_text "$file_name" "$file_line_var"; done; [ -n "$file_permission" ] && pct_exec "chmod $file_permission $file_name"; [ -n "$file_owner" ] && pct_exec "chown $file_owner $file_name"; }
# shell functions for user port binding permissions using authbind
add_port_bind() { port_bind_ubound=$((port_bind_ubound + 1)); eval "port_bind_number_${port_bind_ubound}=\"${1%%:*}\""; eval "port_bind_username_${port_bind_ubound}=\"${1##*:}\""; }
create_port_bind() { [ -z "$authbind_installed" ] && pct_install_package authbind && authbind_installed=1; local i=$1; local port_number=$(eval echo "\$port_bind_number_${i}"); local portbind_username=$(eval echo "\$port_bind_username_${i}"); [ -z "$portbind_username" ] && { echo "Error: Username is empty for port $port_number. Skipping."; return 1; }; pct_exec touch "/etc/authbind/byport/${port_number}"; pct_exec chmod 500 "/etc/authbind/byport/${port_number}"; pct_exec chown "$portbind_username" "/etc/authbind/byport/${port_number}"; unset portbind_username; }
# shell function to type pct exec commands
pct_exec() { [ "$VERBOSE" -gt 0 ] && echo "pct exec $CT_ID -- /bin/sh -c \"$*\""; pct exec $CT_ID -- /bin/sh -c "$*"; }
pct_install_package() { local packages="$*"; case "$CT_os_type" in centos|almalinux|amazonlinux|openeuler|oracle|rockylinux|springdalelinux) install_command="yum install -y" ;; debian|devuan|kali|ubuntu|mint) install_command="apt -qq install -y" ;; alpine) install_command="apk add --quiet" ;; archlinux) install_command="pacman --noconfirm -S" ;; fedora) install_command="dnf install -y" ;; gentoo|funtoo) install_command="emerge --quiet" ;; opensuse) install_command="zypper --quiet install -y" ;; nixos) install_command="nix-env -i" ;; openwrt|busybox) install_command="opkg install" ;; voidlinux) install_command="xbps-install -y" ;; slackware) install_command="slackpkg install" ;; plamo) install_command="pkginstall" ;; alt) install_command="apt-get install -y" ;; *) echo "Error: Unknown or unsupported OS type '$CT_os_type'."; return 1 ;; esac; [ -n "$install_command" ] && pct_exec "$install_command $packages"; }
pct_update_package_manager() { case "$CT_os_type" in centos|almalinux|amazonlinux|openeuler|oracle|rockylinux|springdalelinux) pct_exec "yum -q -y update" ;; debian|devuan|kali|ubuntu|mint) pct_exec "apt -qq update" ;; alpine) pct_exec "apk update" ;; archlinux) pct_exec "pacman -Sy --noconfirm" ;; fedora) pct_exec "dnf -q -y update" ;; gentoo|funtoo) pct_exec "emerge --sync" ;; opensuse) pct_exec "zypper --gpg-auto-import-keys refresh" ;; nixos) pct_exec "nix-channel --update && nix-env -u '*'" ;; openwrt|busybox) pct_exec "opkg update" ;; voidlinux) pct_exec "xbps-install -Sy" ;; slackware) pct_exec "slackpkg update" ;; plamo) pct_exec "pkginstall --update" ;; alt) pct_exec "apt-get update" ;; *) echo "Error: Unknown or unsupported OS type '$CT_os_type'. Cannot update package manager."; return 1 ;; esac; }
pct_set_password() { for user_pass in "$@"; do user=$(echo "$user_pass" | cut -d':' -f1); pass=$(echo "$user_pass" | cut -d':' -f2); pct_exec bash -c "'printf \"%s\n\" \"${user}:${pass}\" | chpasswd'"; done; }
addcommand() { pct_command_ubound=$((pct_command_ubound + 1)); eval "pct_command_${pct_command_ubound}=\"\$*\""; }
runcommand() { local i=$1; eval "pct_exec \${pct_command_${i}}"; }

VERBOSE=1  # Enable verbose mode
[ "$VERBOSE" -gt 0 ] && echo "------------------------------ Creation of debian LXC container ------------------------------"
CT_ID="2010"  # Adjust the container ID, doesn't have to be set
CT_hostname="ipxe-buildweb"
CT_network_suffix=".lan"
CT_root_password="qwerty"
CT_memory="2000"
CT_cores="4"
CT_rootfs_size="16"

CT_install_packages="sudo screen wget htop docker-compose"

CT_enable_root_login="true"
CT_template_download="http://download.proxmox.com/images/system/debian-12-standard_12.7-1_amd64.tar.zst"
CT_template_filename="debian-12-standard_12.7-1_amd64.tar.zst"
CT_template_file="local:vztmpl/$CT_template_filename"
CT_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8Eg5xSbsyLySMCH5K1eb8ZzLTLwPrXDmgyGh9OAi/kofhR6UrTtuVzViAxBV8i+52pgMkRFoX2q/wDKkX7bJk0HXGzs26Npz40BCOEO6hf8MlTc/Kdu288sxVKPhnMofJ1UGy4vZjy2AHoAEe0NbazoEiBNZNO+EpXAGnaxnSM2KQFDDidZydeFMaGKWPb0wYXnGeKbnjxA2rASbX2Rd515FC5ZkYVAK0KFjRV41q+xJebBDhGhgLpHynusmFINM/RdoUswD+c2lwRpdIL+yU+DIPt4J7pM6h0Tj8hTFlqIzemwKKFi4UkzL53oQFYpCK2qAHiBTHAfOdL8gcF5Kv rsa-key-20240131"
CT_key_file="/ssh_key.$CT_hostname.pub"

addnet eth0 hwaddr "DE:AD:BE:EF:43:70" ip dhcp ip6 manual firewall 0 bridge vmbr0 #link_down 1 # LAN interface (eth0)

adduser user nopassword nologin lock groups docker


add_port_bind "80:user"
add_port_bind "443:user"

addcommand mkdir -p /opt/ipxe-buildweb

addfile "/opt/ipxe-buildweb/docker-compose.yml" "644" "root:root"
addline "services:"
addline "  ipxe-buildweb:"
addline "    image: xbgmsharp/ipxe-buildweb"
addline "    container_name: ipxe-buildweb"
addline "    ports:"
addline "      - '80:80'"
#addline "      - '22:22'"
addline "    restart: unless-stopped"

addcommand sudo -u user docker-compose -f /opt/ipxe-buildweb/docker-compose.yml up -d

# Only download template file if it is not already present
[ ! -f /var/lib/vz/template/cache/$CT_template_filename ] && wget "$CT_template_download" -O /var/lib/vz/template/cache/$CT_template_filename
# Set the right OS Type
case "$CT_template_filename" in *almalinux*|*amazonlinux*|*centos*|*openeuler*|*oracle*|*rockylinux*|*springdalelinux*) CT_os_type="centos" ;; *alpine*) CT_os_type="alpine" ;; *alt*|*busybox*|*plamo*|*slackware*|*voidlinux*|*openwrt*) CT_os_type="unmanaged" ;; *archlinux*) CT_os_type="archlinux" ;; *debian*|*devuan*|*kali*) CT_os_type="debian" ;; *fedora*) CT_os_type="fedora" ;; *funtoo*|*gentoo*) CT_os_type="gentoo" ;; *mint*) CT_os_type="ubuntu" ;; *nixos*) CT_os_type="nixos" ;; *opensuse*) CT_os_type="opensuse" ;; *ubuntu*) CT_os_type="ubuntu" ;; *) CT_os_type="unmanaged" ;; esac
# Obtain the next CT_ID if not already set
: ${CT_ID:=100}; CT_ID=$((CT_ID < 100 ? 100 : CT_ID)); existing_ids=$(pct list | awk 'NR>1 {print $1}' | sort -n); while echo "$existing_ids" | grep -qw "$CT_ID"; do CT_ID=$((CT_ID + 1)); done
# Writing the public key to a file, as pct requires
echo "$CT_key" > $CT_key_file

# Create the container
echo ""; echo Creating LXC Container for $CT_template_filename
[ "$VERBOSE" -gt 0 ] && echo "pct create $CT_ID $CT_template_file --arch amd64 --cores $CT_cores --memory $CT_memory --hostname $CT_hostname $_CT_net_config --rootfs local-lvm:$CT_rootfs_size --features nesting=1 --unprivileged 1 --ostype $CT_os_type"
pct create $CT_ID $CT_template_file --arch amd64 --cores $CT_cores --memory $CT_memory --hostname $CT_hostname $_CT_net_config --rootfs local-lvm:$CT_rootfs_size --features nesting=1 --unprivileged 1 --ostype $CT_os_type

# delete key file
rm $CT_key_file

# Define the LXC configuration file path
LXC_CONF_FILE="/etc/pve/nodes/proxmox/lxc/$CT_ID.conf"

# to set console to shell mode
echo "cmode: shell" >> "$LXC_CONF_FILE"

# to add the mount points
#for i in $(seq 1 $mount_point_ubound); do create_mount_point $i; done

# Start the container
pct start $CT_ID

#Wait until container is finished booting
while [[ $(pct status $CT_ID) != *"running"* ]]; do echo "Waiting for container $CT_ID to start..."; sleep 2; done; echo "Container $CT_ID is running."

sleep 5

# Enable root login via ssh
[ "$CT_enable_root_login" = "true" ] && pct_exec "sed -i 's/^#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config"
# Enable login with password
[ -n "$CT_root_password" ] && pct_exec "sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config"
[ -n "$CT_root_password" ] && pct_set_password "root:$CT_root_password"
pct_exec systemctl restart sshd

pct_update_package_manager

# Install additional packages if specified
[ -n "$CT_install_packages" ] && pct_install_package $CT_install_packages

# create extra users
[ -n "$user_ubound" ] && for i in $(seq 1 $user_ubound); do createuser $i; done

# write all the files into the container
[ -n "$file_ubound" ] && for i in $(seq 1 $file_ubound); do writefile $i; done

# allow port binding by users if needed
[ -n "$port_bind_ubound" ] && for i in $(seq 1 $port_bind_ubound); do create_port_bind $i; done

# run the commands specified with addcommand
[ -n "$pct_command_ubound" ] && for i in $(seq 1 $pct_command_ubound); do runcommand $i; done
 
Last edited:
rom-o-matic
https://github.com/lps-rocks/rom-o-matic

1735872548931.png

Code:
#----------------------------------------
# stop in case of errors
#set -e # this breaks on or soon after pct create
# shell function to create --net variable
addnet() { CT_net_count=${CT_net_count:-0}; local net_name=$1; shift; local _CT_new_config="--net$CT_net_count name=$net_name"; local valid_params=("bridge" "firewall" "gw" "gw6" "hwaddr" "ip" "ip6" "link_down" "mtu" "rate" "tag" "trunks" "type"); while [ $# -gt 0 ]; do key=$1; value=$2; if [[ " ${valid_params[*]} " =~ " $key " ]]; then _CT_new_config="$_CT_new_config,$key=$value"; shift 2; else shift 1; fi; done; _CT_net_config="$_CT_net_config $_CT_new_config"; echo "Interface added: $_CT_new_config"; CT_net_count=$((CT_net_count + 1)); }
# shell function to create user variables
adduser() { user_ubound=$((user_ubound + 1)); local user_and_group=$1; IFS=':' read -r username group <<< "$user_and_group"; eval "user_name_${user_ubound}=\"$username\""; [ -n "$group" ] && eval "user_group_${user_ubound}=\"$group\""; shift 1; while [ $# -gt 0 ]; do case $1 in nologin) eval "user_shell_${user_ubound}='/usr/sbin/nologin'" ;; shell) shift 1; eval "user_shell_${user_ubound}=\"$1\"" ;; groups) shift 1; eval "user_groups_${user_ubound}=\"$1\"" ;; nopassword) eval "user_password_${user_ubound}=$(printf '%s' '!')" ;; password) shift 1; eval "user_password_${user_ubound}=\"$1\"" ;; lock) eval "user_lock_${user_ubound}=true" ;; *) echo "Warning: Unrecognized option '$1'" ;; esac; shift 1; done; }
createuser() { local i=$1; local username=$(eval echo "\$user_name_${i}"); local group=$(eval echo "\$user_group_${i}"); local shell=$(eval echo "\$user_shell_${i}"); local password=$(eval echo "\$user_password_${i}"); local groups=$(eval echo "\$user_groups_${i}"); local lock=$(eval echo "\$user_lock_${i}"); [ -n "$shell" ] && shell_option="-s $shell" || shell_option="-s /bin/bash"; [ -n "$group" ] && group_option="-g $group" || group_option=""; pct_exec useradd $shell_option $group_option "$username"; [ -n "$password" ] && pct_set_password "$username:$password"; [ "$password" = "!" ] && pct_exec usermod -L "$username"; [ "$lock" = "true" ] && pct_exec usermod -L "$username"; pct_exec mkdir -p "/home/$username"; [ -n "$group" ] && pct_exec chown "$username:$group" "/home/$username" || pct_exec chown "$username" "/home/$username"; [ -n "$groups" ] && pct_exec usermod -aG "$groups" "$username"; unset username group shell password groups lock; }
# shell function for create each file line variables
addline() { file_line_ubound=$((file_line_ubound + 1)); eval "file_line_${file_line_ubound}_${file_ubound}=\"$1\""; eval "file_line_count_${file_ubound}=$file_line_ubound"; }
addfile() { file_ubound=$((file_ubound + 1)); eval "file_name_${file_ubound}=\"$1\""; [ -n "$2" ] && [[ "$2" =~ ^[0-9]+$ ]] && eval "filepermission_${file_ubound}=\"$2\""; [ -n "$3" ] && eval "fileowner_${file_ubound}=\"$3\""; unset file_line_ubound; }
pct_append_text() { local file=$1; local text_or_var=$2; if [ -n "${!text_or_var}" ]; then local text=${!text_or_var}; elif [[ "$text_or_var" == file_line* ]]; then local text=$(eval echo \${$text_or_var}); else local text="$text_or_var"; fi; local command="echo \"$text\" >> \"$file\""; [ "$VERBOSE" -gt 0 ] && echo "pct exec $CT_ID -- /bin/sh -c \"$command\""; pct exec $CT_ID -- /bin/sh -c "$command"; }
writefile() { local file_index=$1; local file_name=$(eval echo \${file_name_${file_index}}); local file_permission=$(eval echo \${filepermission_${file_index}}); local file_owner=$(eval echo \${fileowner_${file_index}}); local file_line_count=$(eval echo \${file_line_count_${file_index}}); pct_exec mkdir -p "$(dirname "$file_name")"; for i in $(seq 1 $file_line_count); do local file_line_var="file_line_${i}_${file_index}"; pct_append_text "$file_name" "$file_line_var"; done; [ -n "$file_permission" ] && pct_exec "chmod $file_permission $file_name"; [ -n "$file_owner" ] && pct_exec "chown $file_owner $file_name"; }
# shell functions for user port binding permissions using authbind
add_port_bind() { port_bind_ubound=$((port_bind_ubound + 1)); eval "port_bind_number_${port_bind_ubound}=\"${1%%:*}\""; eval "port_bind_username_${port_bind_ubound}=\"${1##*:}\""; }
create_port_bind() { [ -z "$authbind_installed" ] && pct_install_package authbind && authbind_installed=1; local i=$1; local port_number=$(eval echo "\$port_bind_number_${i}"); local portbind_username=$(eval echo "\$port_bind_username_${i}"); [ -z "$portbind_username" ] && { echo "Error: Username is empty for port $port_number. Skipping."; return 1; }; pct_exec touch "/etc/authbind/byport/${port_number}"; pct_exec chmod 500 "/etc/authbind/byport/${port_number}"; pct_exec chown "$portbind_username" "/etc/authbind/byport/${port_number}"; unset portbind_username; }
# shell function to type pct exec commands
pct_exec() { [ "$VERBOSE" -gt 0 ] && echo "pct exec $CT_ID -- /bin/sh -c \"$*\""; pct exec $CT_ID -- /bin/sh -c "$*"; }
pct_install_package() { local packages="$*"; case "$CT_os_type" in centos|almalinux|amazonlinux|openeuler|oracle|rockylinux|springdalelinux) install_command="yum install -y" ;; debian|devuan|kali|ubuntu|mint) install_command="apt -qq install -y" ;; alpine) install_command="apk add --quiet" ;; archlinux) install_command="pacman --noconfirm -S" ;; fedora) install_command="dnf install -y" ;; gentoo|funtoo) install_command="emerge --quiet" ;; opensuse) install_command="zypper --quiet install -y" ;; nixos) install_command="nix-env -i" ;; openwrt|busybox) install_command="opkg install" ;; voidlinux) install_command="xbps-install -y" ;; slackware) install_command="slackpkg install" ;; plamo) install_command="pkginstall" ;; alt) install_command="apt-get install -y" ;; *) echo "Error: Unknown or unsupported OS type '$CT_os_type'."; return 1 ;; esac; [ -n "$install_command" ] && pct_exec "$install_command $packages"; }
pct_update_package_manager() { case "$CT_os_type" in centos|almalinux|amazonlinux|openeuler|oracle|rockylinux|springdalelinux) pct_exec "yum -q -y update" ;; debian|devuan|kali|ubuntu|mint) pct_exec "apt -qq update" ;; alpine) pct_exec "apk update" ;; archlinux) pct_exec "pacman -Sy --noconfirm" ;; fedora) pct_exec "dnf -q -y update" ;; gentoo|funtoo) pct_exec "emerge --sync" ;; opensuse) pct_exec "zypper --gpg-auto-import-keys refresh" ;; nixos) pct_exec "nix-channel --update && nix-env -u '*'" ;; openwrt|busybox) pct_exec "opkg update" ;; voidlinux) pct_exec "xbps-install -Sy" ;; slackware) pct_exec "slackpkg update" ;; plamo) pct_exec "pkginstall --update" ;; alt) pct_exec "apt-get update" ;; *) echo "Error: Unknown or unsupported OS type '$CT_os_type'. Cannot update package manager."; return 1 ;; esac; }
pct_set_password() { for user_pass in "$@"; do user=$(echo "$user_pass" | cut -d':' -f1); pass=$(echo "$user_pass" | cut -d':' -f2); pct_exec bash -c "'printf \"%s\n\" \"${user}:${pass}\" | chpasswd'"; done; }
addcommand() { pct_command_ubound=$((pct_command_ubound + 1)); eval "pct_command_${pct_command_ubound}=\"\$*\""; }
runcommand() { local i=$1; eval "pct_exec \${pct_command_${i}}"; }

VERBOSE=1  # Enable verbose mode
[ "$VERBOSE" -gt 0 ] && echo "------------------------------ Creation of debian LXC container ------------------------------"
CT_ID="2020"  # Adjust the container ID, doesn't have to be set
CT_hostname="rom-o-matic"
CT_network_suffix=".lan"
CT_root_password="qwerty"
CT_memory="2000"
CT_cores="4"
CT_rootfs_size="16"

CT_install_packages="sudo screen wget htop docker-compose"

CT_enable_root_login="true"
CT_template_download="http://download.proxmox.com/images/system/debian-12-standard_12.7-1_amd64.tar.zst"
CT_template_filename="debian-12-standard_12.7-1_amd64.tar.zst"
CT_template_file="local:vztmpl/$CT_template_filename"
CT_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8Eg5xSbsyLySMCH5K1eb8ZzLTLwPrXDmgyGh9OAi/kofhR6UrTtuVzViAxBV8i+52pgMkRFoX2q/wDKkX7bJk0HXGzs26Npz40BCOEO6hf8MlTc/Kdu288sxVKPhnMofJ1UGy4vZjy2AHoAEe0NbazoEiBNZNO+EpXAGnaxnSM2KQFDDidZydeFMaGKWPb0wYXnGeKbnjxA2rASbX2Rd515FC5ZkYVAK0KFjRV41q+xJebBDhGhgLpHynusmFINM/RdoUswD+c2lwRpdIL+yU+DIPt4J7pM6h0Tj8hTFlqIzemwKKFi4UkzL53oQFYpCK2qAHiBTHAfOdL8gcF5Kv rsa-key-20240131"
CT_key_file="/ssh_key.$CT_hostname.pub"

addnet eth0 hwaddr "DE:AD:BE:EF:43:71" ip dhcp ip6 manual firewall 0 bridge vmbr0 #link_down 1 # LAN interface (eth0)

adduser user nopassword nologin lock groups docker


add_port_bind "80:user"
add_port_bind "443:user"

addcommand mkdir -p /opt/rom-o-matic

addfile "/opt/rom-o-matic/docker-compose.yml" "644" "root:root"
addline "services:"
addline "  rom-o-matic:"
addline "    image: ghcr.io/lps-rocks/rom-o-matic:master"
addline "    container_name: rom-o-matic"
addline "    ports:"
addline "      - '80:80'"
addline "    restart: unless-stopped"

addcommand sudo -u user docker-compose -f /opt/rom-o-matic/docker-compose.yml up -d

# Only download template file if it is not already present
[ ! -f /var/lib/vz/template/cache/$CT_template_filename ] && wget "$CT_template_download" -O /var/lib/vz/template/cache/$CT_template_filename
# Set the right OS Type
case "$CT_template_filename" in *almalinux*|*amazonlinux*|*centos*|*openeuler*|*oracle*|*rockylinux*|*springdalelinux*) CT_os_type="centos" ;; *alpine*) CT_os_type="alpine" ;; *alt*|*busybox*|*plamo*|*slackware*|*voidlinux*|*openwrt*) CT_os_type="unmanaged" ;; *archlinux*) CT_os_type="archlinux" ;; *debian*|*devuan*|*kali*) CT_os_type="debian" ;; *fedora*) CT_os_type="fedora" ;; *funtoo*|*gentoo*) CT_os_type="gentoo" ;; *mint*) CT_os_type="ubuntu" ;; *nixos*) CT_os_type="nixos" ;; *opensuse*) CT_os_type="opensuse" ;; *ubuntu*) CT_os_type="ubuntu" ;; *) CT_os_type="unmanaged" ;; esac
# Obtain the next CT_ID if not already set
: ${CT_ID:=100}; CT_ID=$((CT_ID < 100 ? 100 : CT_ID)); existing_ids=$(pct list | awk 'NR>1 {print $1}' | sort -n); while echo "$existing_ids" | grep -qw "$CT_ID"; do CT_ID=$((CT_ID + 1)); done
# Writing the public key to a file, as pct requires
echo "$CT_key" > $CT_key_file

# Create the container
echo ""; echo Creating LXC Container for $CT_template_filename
[ "$VERBOSE" -gt 0 ] && echo "pct create $CT_ID $CT_template_file --arch amd64 --cores $CT_cores --memory $CT_memory --hostname $CT_hostname $_CT_net_config --rootfs local-lvm:$CT_rootfs_size --features nesting=1 --unprivileged 1 --ostype $CT_os_type"
pct create $CT_ID $CT_template_file --arch amd64 --cores $CT_cores --memory $CT_memory --hostname $CT_hostname $_CT_net_config --rootfs local-lvm:$CT_rootfs_size --features nesting=1 --unprivileged 1 --ostype $CT_os_type

# delete key file
rm $CT_key_file

# Define the LXC configuration file path
LXC_CONF_FILE="/etc/pve/nodes/proxmox/lxc/$CT_ID.conf"

# to set console to shell mode
echo "cmode: shell" >> "$LXC_CONF_FILE"

# to add the mount points
#for i in $(seq 1 $mount_point_ubound); do create_mount_point $i; done

# Start the container
pct start $CT_ID

#Wait until container is finished booting
while [[ $(pct status $CT_ID) != *"running"* ]]; do echo "Waiting for container $CT_ID to start..."; sleep 2; done; echo "Container $CT_ID is running."

sleep 5

# Enable root login via ssh
[ "$CT_enable_root_login" = "true" ] && pct_exec "sed -i 's/^#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config"
# Enable login with password
[ -n "$CT_root_password" ] && pct_exec "sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config"
[ -n "$CT_root_password" ] && pct_set_password "root:$CT_root_password"
pct_exec systemctl restart sshd

pct_update_package_manager

# Install additional packages if specified
[ -n "$CT_install_packages" ] && pct_install_package $CT_install_packages

# create extra users
[ -n "$user_ubound" ] && for i in $(seq 1 $user_ubound); do createuser $i; done

# write all the files into the container
[ -n "$file_ubound" ] && for i in $(seq 1 $file_ubound); do writefile $i; done

# allow port binding by users if needed
[ -n "$port_bind_ubound" ] && for i in $(seq 1 $port_bind_ubound); do create_port_bind $i; done

# run the commands specified with addcommand
[ -n "$pct_command_ubound" ] && for i in $(seq 1 $pct_command_ubound); do runcommand $i; done
 
ipxe-simple
https://github.com/sebaxakerhtc/ipxe-simple
1735872613028.png

Code:
#----------------------------------------
# stop in case of errors
#set -e # this breaks on or soon after pct create
# shell function to create --net variable
addnet() { CT_net_count=${CT_net_count:-0}; local net_name=$1; shift; local _CT_new_config="--net$CT_net_count name=$net_name"; local valid_params=("bridge" "firewall" "gw" "gw6" "hwaddr" "ip" "ip6" "link_down" "mtu" "rate" "tag" "trunks" "type"); while [ $# -gt 0 ]; do key=$1; value=$2; if [[ " ${valid_params[*]} " =~ " $key " ]]; then _CT_new_config="$_CT_new_config,$key=$value"; shift 2; else shift 1; fi; done; _CT_net_config="$_CT_net_config $_CT_new_config"; echo "Interface added: $_CT_new_config"; CT_net_count=$((CT_net_count + 1)); }
# shell function to create user variables
adduser() { user_ubound=$((user_ubound + 1)); local user_and_group=$1; IFS=':' read -r username group <<< "$user_and_group"; eval "user_name_${user_ubound}=\"$username\""; [ -n "$group" ] && eval "user_group_${user_ubound}=\"$group\""; shift 1; while [ $# -gt 0 ]; do case $1 in nologin) eval "user_shell_${user_ubound}='/usr/sbin/nologin'" ;; shell) shift 1; eval "user_shell_${user_ubound}=\"$1\"" ;; groups) shift 1; eval "user_groups_${user_ubound}=\"$1\"" ;; nopassword) eval "user_password_${user_ubound}=$(printf '%s' '!')" ;; password) shift 1; eval "user_password_${user_ubound}=\"$1\"" ;; lock) eval "user_lock_${user_ubound}=true" ;; *) echo "Warning: Unrecognized option '$1'" ;; esac; shift 1; done; }
createuser() { local i=$1; local username=$(eval echo "\$user_name_${i}"); local group=$(eval echo "\$user_group_${i}"); local shell=$(eval echo "\$user_shell_${i}"); local password=$(eval echo "\$user_password_${i}"); local groups=$(eval echo "\$user_groups_${i}"); local lock=$(eval echo "\$user_lock_${i}"); [ -n "$shell" ] && shell_option="-s $shell" || shell_option="-s /bin/bash"; [ -n "$group" ] && group_option="-g $group" || group_option=""; pct_exec useradd $shell_option $group_option "$username"; [ -n "$password" ] && pct_set_password "$username:$password"; [ "$password" = "!" ] && pct_exec usermod -L "$username"; [ "$lock" = "true" ] && pct_exec usermod -L "$username"; pct_exec mkdir -p "/home/$username"; [ -n "$group" ] && pct_exec chown "$username:$group" "/home/$username" || pct_exec chown "$username" "/home/$username"; [ -n "$groups" ] && pct_exec usermod -aG "$groups" "$username"; unset username group shell password groups lock; }
# shell function for create each file line variables
addline() { file_line_ubound=$((file_line_ubound + 1)); eval "file_line_${file_line_ubound}_${file_ubound}=\"$1\""; eval "file_line_count_${file_ubound}=$file_line_ubound"; }
addfile() { file_ubound=$((file_ubound + 1)); eval "file_name_${file_ubound}=\"$1\""; [ -n "$2" ] && [[ "$2" =~ ^[0-9]+$ ]] && eval "filepermission_${file_ubound}=\"$2\""; [ -n "$3" ] && eval "fileowner_${file_ubound}=\"$3\""; unset file_line_ubound; }
pct_append_text() { local file=$1; local text_or_var=$2; if [ -n "${!text_or_var}" ]; then local text=${!text_or_var}; elif [[ "$text_or_var" == file_line* ]]; then local text=$(eval echo \${$text_or_var}); else local text="$text_or_var"; fi; local command="echo \"$text\" >> \"$file\""; [ "$VERBOSE" -gt 0 ] && echo "pct exec $CT_ID -- /bin/sh -c \"$command\""; pct exec $CT_ID -- /bin/sh -c "$command"; }
writefile() { local file_index=$1; local file_name=$(eval echo \${file_name_${file_index}}); local file_permission=$(eval echo \${filepermission_${file_index}}); local file_owner=$(eval echo \${fileowner_${file_index}}); local file_line_count=$(eval echo \${file_line_count_${file_index}}); pct_exec mkdir -p "$(dirname "$file_name")"; for i in $(seq 1 $file_line_count); do local file_line_var="file_line_${i}_${file_index}"; pct_append_text "$file_name" "$file_line_var"; done; [ -n "$file_permission" ] && pct_exec "chmod $file_permission $file_name"; [ -n "$file_owner" ] && pct_exec "chown $file_owner $file_name"; }
# shell functions for user port binding permissions using authbind
add_port_bind() { port_bind_ubound=$((port_bind_ubound + 1)); eval "port_bind_number_${port_bind_ubound}=\"${1%%:*}\""; eval "port_bind_username_${port_bind_ubound}=\"${1##*:}\""; }
create_port_bind() { [ -z "$authbind_installed" ] && pct_install_package authbind && authbind_installed=1; local i=$1; local port_number=$(eval echo "\$port_bind_number_${i}"); local portbind_username=$(eval echo "\$port_bind_username_${i}"); [ -z "$portbind_username" ] && { echo "Error: Username is empty for port $port_number. Skipping."; return 1; }; pct_exec touch "/etc/authbind/byport/${port_number}"; pct_exec chmod 500 "/etc/authbind/byport/${port_number}"; pct_exec chown "$portbind_username" "/etc/authbind/byport/${port_number}"; unset portbind_username; }
# shell function to type pct exec commands
pct_exec() { [ "$VERBOSE" -gt 0 ] && echo "pct exec $CT_ID -- /bin/sh -c \"$*\""; pct exec $CT_ID -- /bin/sh -c "$*"; }
pct_install_package() { local packages="$*"; case "$CT_os_type" in centos|almalinux|amazonlinux|openeuler|oracle|rockylinux|springdalelinux) install_command="yum install -y" ;; debian|devuan|kali|ubuntu|mint) install_command="apt -qq install -y" ;; alpine) install_command="apk add --quiet" ;; archlinux) install_command="pacman --noconfirm -S" ;; fedora) install_command="dnf install -y" ;; gentoo|funtoo) install_command="emerge --quiet" ;; opensuse) install_command="zypper --quiet install -y" ;; nixos) install_command="nix-env -i" ;; openwrt|busybox) install_command="opkg install" ;; voidlinux) install_command="xbps-install -y" ;; slackware) install_command="slackpkg install" ;; plamo) install_command="pkginstall" ;; alt) install_command="apt-get install -y" ;; *) echo "Error: Unknown or unsupported OS type '$CT_os_type'."; return 1 ;; esac; [ -n "$install_command" ] && pct_exec "$install_command $packages"; }
pct_update_package_manager() { case "$CT_os_type" in centos|almalinux|amazonlinux|openeuler|oracle|rockylinux|springdalelinux) pct_exec "yum -q -y update" ;; debian|devuan|kali|ubuntu|mint) pct_exec "apt -qq update" ;; alpine) pct_exec "apk update" ;; archlinux) pct_exec "pacman -Sy --noconfirm" ;; fedora) pct_exec "dnf -q -y update" ;; gentoo|funtoo) pct_exec "emerge --sync" ;; opensuse) pct_exec "zypper --gpg-auto-import-keys refresh" ;; nixos) pct_exec "nix-channel --update && nix-env -u '*'" ;; openwrt|busybox) pct_exec "opkg update" ;; voidlinux) pct_exec "xbps-install -Sy" ;; slackware) pct_exec "slackpkg update" ;; plamo) pct_exec "pkginstall --update" ;; alt) pct_exec "apt-get update" ;; *) echo "Error: Unknown or unsupported OS type '$CT_os_type'. Cannot update package manager."; return 1 ;; esac; }
pct_set_password() { for user_pass in "$@"; do user=$(echo "$user_pass" | cut -d':' -f1); pass=$(echo "$user_pass" | cut -d':' -f2); pct_exec bash -c "'printf \"%s\n\" \"${user}:${pass}\" | chpasswd'"; done; }
addcommand() { pct_command_ubound=$((pct_command_ubound + 1)); eval "pct_command_${pct_command_ubound}=\"\$*\""; }
runcommand() { local i=$1; eval "pct_exec \${pct_command_${i}}"; }

VERBOSE=1  # Enable verbose mode
[ "$VERBOSE" -gt 0 ] && echo "------------------------------ Creation of debian LXC container ------------------------------"
CT_ID="2030"  # Adjust the container ID, doesn't have to be set
CT_hostname="ipxe-simple"
CT_network_suffix=".lan"
CT_root_password="qwerty"
CT_memory="2000"
CT_cores="4"
CT_rootfs_size="16"

CT_install_packages="sudo screen wget htop docker-compose"

CT_enable_root_login="true"
CT_template_download="http://download.proxmox.com/images/system/debian-12-standard_12.7-1_amd64.tar.zst"
CT_template_filename="debian-12-standard_12.7-1_amd64.tar.zst"
CT_template_file="local:vztmpl/$CT_template_filename"
CT_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8Eg5xSbsyLySMCH5K1eb8ZzLTLwPrXDmgyGh9OAi/kofhR6UrTtuVzViAxBV8i+52pgMkRFoX2q/wDKkX7bJk0HXGzs26Npz40BCOEO6hf8MlTc/Kdu288sxVKPhnMofJ1UGy4vZjy2AHoAEe0NbazoEiBNZNO+EpXAGnaxnSM2KQFDDidZydeFMaGKWPb0wYXnGeKbnjxA2rASbX2Rd515FC5ZkYVAK0KFjRV41q+xJebBDhGhgLpHynusmFINM/RdoUswD+c2lwRpdIL+yU+DIPt4J7pM6h0Tj8hTFlqIzemwKKFi4UkzL53oQFYpCK2qAHiBTHAfOdL8gcF5Kv rsa-key-20240131"
CT_key_file="/ssh_key.$CT_hostname.pub"

addnet eth0 hwaddr "DE:AD:BE:EF:43:72" ip dhcp ip6 manual firewall 0 bridge vmbr0 #link_down 1 # LAN interface (eth0)

adduser user nopassword nologin lock groups docker


add_port_bind "80:user"
add_port_bind "443:user"

addcommand mkdir -p /opt/ipxe-simple

addfile "/opt/ipxe-simple/docker-compose.yml" "644" "root:root"
addline "services:"
addline "  ipxe-simple:"
addline "    image: sebaxakerhtc/ipxe-simple"
addline "    container_name: ipxe-simple"
addline "    ports:"
addline "      - '80:80'"
#addline "      - '22:22'"
addline "    restart: unless-stopped"

addcommand sudo -u user docker-compose -f /opt/ipxe-simple/docker-compose.yml up -d

# Only download template file if it is not already present
[ ! -f /var/lib/vz/template/cache/$CT_template_filename ] && wget "$CT_template_download" -O /var/lib/vz/template/cache/$CT_template_filename
# Set the right OS Type
case "$CT_template_filename" in *almalinux*|*amazonlinux*|*centos*|*openeuler*|*oracle*|*rockylinux*|*springdalelinux*) CT_os_type="centos" ;; *alpine*) CT_os_type="alpine" ;; *alt*|*busybox*|*plamo*|*slackware*|*voidlinux*|*openwrt*) CT_os_type="unmanaged" ;; *archlinux*) CT_os_type="archlinux" ;; *debian*|*devuan*|*kali*) CT_os_type="debian" ;; *fedora*) CT_os_type="fedora" ;; *funtoo*|*gentoo*) CT_os_type="gentoo" ;; *mint*) CT_os_type="ubuntu" ;; *nixos*) CT_os_type="nixos" ;; *opensuse*) CT_os_type="opensuse" ;; *ubuntu*) CT_os_type="ubuntu" ;; *) CT_os_type="unmanaged" ;; esac
# Obtain the next CT_ID if not already set
: ${CT_ID:=100}; CT_ID=$((CT_ID < 100 ? 100 : CT_ID)); existing_ids=$(pct list | awk 'NR>1 {print $1}' | sort -n); while echo "$existing_ids" | grep -qw "$CT_ID"; do CT_ID=$((CT_ID + 1)); done
# Writing the public key to a file, as pct requires
echo "$CT_key" > $CT_key_file

# Create the container
echo ""; echo Creating LXC Container for $CT_template_filename
[ "$VERBOSE" -gt 0 ] && echo "pct create $CT_ID $CT_template_file --arch amd64 --cores $CT_cores --memory $CT_memory --hostname $CT_hostname $_CT_net_config --rootfs local-lvm:$CT_rootfs_size --features nesting=1 --unprivileged 1 --ostype $CT_os_type"
pct create $CT_ID $CT_template_file --arch amd64 --cores $CT_cores --memory $CT_memory --hostname $CT_hostname $_CT_net_config --rootfs local-lvm:$CT_rootfs_size --features nesting=1 --unprivileged 1 --ostype $CT_os_type

# delete key file
rm $CT_key_file

# Define the LXC configuration file path
LXC_CONF_FILE="/etc/pve/nodes/proxmox/lxc/$CT_ID.conf"

# to set console to shell mode
echo "cmode: shell" >> "$LXC_CONF_FILE"

# to add the mount points
#for i in $(seq 1 $mount_point_ubound); do create_mount_point $i; done

# Start the container
pct start $CT_ID

#Wait until container is finished booting
while [[ $(pct status $CT_ID) != *"running"* ]]; do echo "Waiting for container $CT_ID to start..."; sleep 2; done; echo "Container $CT_ID is running."

sleep 5

# Enable root login via ssh
[ "$CT_enable_root_login" = "true" ] && pct_exec "sed -i 's/^#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config"
# Enable login with password
[ -n "$CT_root_password" ] && pct_exec "sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config"
[ -n "$CT_root_password" ] && pct_set_password "root:$CT_root_password"
pct_exec systemctl restart sshd

pct_update_package_manager

# Install additional packages if specified
[ -n "$CT_install_packages" ] && pct_install_package $CT_install_packages

# create extra users
[ -n "$user_ubound" ] && for i in $(seq 1 $user_ubound); do createuser $i; done

# write all the files into the container
[ -n "$file_ubound" ] && for i in $(seq 1 $file_ubound); do writefile $i; done

# allow port binding by users if needed
[ -n "$port_bind_ubound" ] && for i in $(seq 1 $port_bind_ubound); do create_port_bind $i; done

# run the commands specified with addcommand
[ -n "$pct_command_ubound" ] && for i in $(seq 1 $pct_command_ubound); do runcommand $i; done
 

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!