Hello,
I don't know where else to post this.
But I just created a proxmox install script to create a Vaultwarden server in an LXC container, inside of a debian LXC template
I don't know where else to post this.
But I just created a proxmox install script to create a Vaultwarden server in an LXC container, inside of a debian LXC template
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="900" # Adjust the container ID, doesn't have to be set
CT_hostname="vaultwarden"
CT_network_suffix=".lan"
CT_root_password="qwerty"
CT_memory="1024"
CT_cores="4"
CT_rootfs_size="2"
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:99:55" ip dhcp ip6 manual firewall 0 bridge vmbr0 #link_down 1 # LAN interface (eth0)
adduser user nopassword nologin lock groups docker
add_port_bind "443:user"
addfile "/opt/vaultwarden/docker-compose.yml" "644" "root:root"
addline "version: '3.7'"
addline "services:"
addline " vaultwarden:"
addline " image: vaultwarden/server:latest"
addline " container_name: vaultwarden"
addline " environment:"
addline " DOMAIN: 'https://$CT_hostname$CT_network_suffix'"
addline " ROCKET_PORT: 443"
addline " ENABLE_SSL: 'true'"
addline " SIGNUPS_ALLOWED: 'true'"
addline " ROCKET_TLS: '{certs=/certs/fullchain.pem,key=/certs/privkey.pem}'"
addline " volumes:"
addline " - /opt/vaultwarden-data/:/data/"
addline " - /opt/vaultwarden-certs/:/certs/:ro"
addline " ports:"
addline " - 443:443"
addline " restart: unless-stopped"
addcommand mkdir -p /opt/vaultwarden/ /opt/vaultwarden-certs/ /opt/vaultwarden-data/
addcommand openssl req -x509 -newkey rsa:4096 -keyout /opt/vaultwarden-certs/privkey.pem -out /opt/vaultwarden-certs/fullchain.pem -sha256 -days 36500 -nodes -subj '/CN=$CT_hostname$CT_network_suffix'
addcommand sudo -u user docker-compose -f /opt/vaultwarden/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: