Merge branch 'community-scripts:main' into wanderer

This commit is contained in:
rrole 2025-11-25 12:44:16 +01:00 committed by GitHub
commit 80a8beb2df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 4513 additions and 343 deletions

View File

@ -1,6 +0,0 @@
___ __ _ __
/ | _____/ /____ _____(_)____/ /__
/ /| | / ___/ __/ _ \/ ___/ / ___/ //_/
/ ___ |(__ ) /_/ __/ / / (__ ) ,<
/_/ |_/____/\__/\___/_/ /_/____/_/|_|

View File

@ -1,6 +0,0 @@
____ _ __ __
/ __ \____ ____ ___ ____ _(_)___ / / ____ _____/ /_____ _____
/ / / / __ \/ __ `__ \/ __ `/ / __ \______/ / / __ \/ ___/ //_/ _ \/ ___/
/ /_/ / /_/ / / / / / / /_/ / / / / /_____/ /___/ /_/ / /__/ ,< / __/ /
/_____/\____/_/ /_/ /_/\__,_/_/_/ /_/ /_____/\____/\___/_/|_|\___/_/

6
ct/headers/joplin-server Normal file
View File

@ -0,0 +1,6 @@
__ ___ _____
/ /___ ____ / (_)___ / ___/___ ______ _____ _____
__ / / __ \/ __ \/ / / __ \______\__ \/ _ \/ ___/ | / / _ \/ ___/
/ /_/ / /_/ / /_/ / / / / / /_____/__/ / __/ / | |/ / __/ /
\____/\____/ .___/_/_/_/ /_/ /____/\___/_/ |___/\___/_/
/_/

View File

@ -1,6 +0,0 @@
__ __ __
/ //_/___ _____ / /_ ____ _
/ ,< / __ `/ __ \/ __ \/ __ `/
/ /| / /_/ / / / / /_/ / /_/ /
/_/ |_\__,_/_/ /_/_.___/\__,_/

View File

@ -1,6 +0,0 @@
__ _ __
/ / (_) /_ ________ ____ ____ ___ _____
/ / / / __ \/ ___/ _ \/ __ \/ __ `__ \/ ___/
/ /___/ / /_/ / / / __/ / / / / / / / (__ )
/_____/_/_.___/_/ \___/_/ /_/_/ /_/ /_/____/

6
ct/headers/mealie Normal file
View File

@ -0,0 +1,6 @@
__ ___ ___
/ |/ /__ ____ _/ (_)__
/ /|_/ / _ \/ __ `/ / / _ \
/ / / / __/ /_/ / / / __/
/_/ /_/\___/\__,_/_/_/\___/

View File

@ -1,6 +0,0 @@
____ __
/ __ \____ ___ ____ _____/ /___ _
/ / / / __ `__ \/ __ `/ __ / __ `/
/ /_/ / / / / / / /_/ / /_/ / /_/ /
\____/_/ /_/ /_/\__,_/\__,_/\__,_/

View File

@ -1,6 +0,0 @@
____ __ ____
/ __ \____ ___________/ /_ ____ / / /_
/ /_/ / __ `/ ___/ ___/ __ \/ __ \/ / __/
/ ____/ /_/ (__ |__ ) /_/ / /_/ / / /_
/_/ \__,_/____/____/_.___/\____/_/\__/

6
ct/headers/qdrant Normal file
View File

@ -0,0 +1,6 @@
____ __ __
/ __ \____/ /________ _____ / /_
/ / / / __ / ___/ __ `/ __ \/ __/
/ /_/ / /_/ / / / /_/ / / / / /_
\___\_\__,_/_/ \__,_/_/ /_/\__/

View File

@ -1,6 +0,0 @@
__ __ __
/ / / /___ ____ _____ ____ / /_ ___ _____
/ / / / __ \/ __ `/ __ \/ __ \/ __ \/ _ \/ ___/
/ /_/ / /_/ / /_/ / /_/ / /_/ / / / / __/ /
\____/ .___/\__, /\____/ .___/_/ /_/\___/_/
/_/ /____/ /_/

61
ct/joplin-server.sh Normal file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
# Copyright (c) 2021-2025 community-scripts ORG
# Author: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://joplinapp.org/
APP="Joplin-Server"
var_tags="${var_tags:-notes}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-20}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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/joplin-server ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "joplin-server" "laurent22/joplin"; then
msg_info "Stopping Services"
systemctl stop joplin-server
msg_ok "Stopped Services"
fetch_and_deploy_gh_release "joplin-server" "laurent22/joplin" "tarball" "latest"
msg_info "Updating Joplin-Server"
cd /opt/joplin-server
sed -i "/onenote-converter/d" packages/lib/package.json
$STD yarn config set --home enableTelemetry 0
export BUILD_SEQUENCIAL=1
$STD yarn install --inline-builds
msg_ok "Updated Joplin-Server"
msg_info "Starting Services"
systemctl start joplin-server
msg_ok "Started Services"
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}:22300${CL}"

45
ct/qdrant.sh Normal file
View File

@ -0,0 +1,45 @@
#!/usr/bin/env bash
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# Source: https://github.com/qdrant/qdrant
APP="Qdrant"
var_tags="${var_tags:-}"
var_cpu="${var_cpu:-4}"
var_ram="${var_ram:-8192}"
var_disk="${var_disk:-20}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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 /var/lib/qdrant ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "qdrant" "qdrant/qdrant"; then
fetch_and_deploy_gh_release "qdrant" "qdrant/qdrant" "binary" "latest" "/usr/bin/qdrant"
chown -R root:root /var/lib/qdrant
chmod -R 755 /var/lib/qdrant
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}:6333${CL}"

View File

@ -0,0 +1,48 @@
{
"name": "Ente",
"slug": "ente",
"categories": [
20
],
"date_created": "2025-11-22",
"type": "ct",
"updateable": false,
"privileged": false,
"config_path": "/opt",
"interface_port": 3000,
"documentation": "https://github.com/ente-io/ente",
"website": "https://ente.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/ente-photos.svg",
"description": "Ente is a service that provides a fully open source, end-to-end encrypted platform for you to store your data in the cloud without needing to trust the service provider. On top of this platform, we have built two apps so far: Ente Photos (an alternative to Apple and Google Photos) and Ente Auth (a 2FA alternative to the deprecated Authy).",
"install_methods": [
{
"type": "default",
"script": "ct/ente.sh",
"resources": {
"cpu": 4,
"ram": 4096,
"hdd": 10,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Please use `journalctl -u ente-museum.service -n 10` to read logs for the signup verification code",
"type": "info"
},
{
"text": "If you want to use the Ente CLI to add/whitelist admins, please follow the instructions at https://ente.io/help/self-hosting/administration/cli",
"type": "info"
},
{
"text": "To see Museium config: `cat /opt/ente/server/museum.yaml`",
"type": "info"
}
]
}

View File

@ -0,0 +1,35 @@
{
"name": "Qdrant",
"slug": "qdrant",
"categories": [
20
],
"date_created": "2025-11-25",
"type": "ct",
"updateable": false,
"privileged": false,
"config_path": "/etc/qdrant/config.yaml",
"interface_port": 6333,
"documentation": "https://github.com/qdrant/qdrant",
"website": "https://qdrant.tech/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/qdrant.webp",
"description": "Qdrant is a vector search engine and vector database that allows you to store, search, and manage high-dimensional vectors efficiently.",
"install_methods": [
{
"type": "default",
"script": "ct/qdrant.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 5,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@ -28,8 +28,22 @@ PG_VERSION="17" setup_postgresql
setup_go
NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs
ENTE_CLI_VERSION=$(curl -s https://api.github.com/repos/ente-io/ente/releases | jq -r '[.[] | select(.tag_name | startswith("cli-v"))][0].tag_name')
fetch_and_deploy_gh_release "ente" "ente-io/ente" "tarball" "latest" "/opt/ente"
fetch_and_deploy_gh_release "ente" "ente-io/ente" "tarball" "$ENTE_CLI_VERSION" "/usr/local/bin/ente" "ente-cli-$ENTE_CLI_VERSION-linux-amd64.tar.gz"
fetch_and_deploy_gh_release "ente-server" "ente-io/ente" "tarball" "latest" "/opt/ente"
fetch_and_deploy_gh_release "ente-cli" "ente-io/ente" "prebuild" "$ENTE_CLI_VERSION" "/usr/local/bin" "ente-$ENTE_CLI_VERSION-linux-amd64.tar.gz"
$STD mkdir -p /opt/ente/cli
msg_info "Configuring Ente CLI"
cat <<EOF >>~/.bashrc
export ENTE_CLI_SECRETS_PATH=/opt/ente/cli/secrets.txt
export PATH="/usr/local/bin:$PATH"
EOF
$STD source ~/.bashrc
$STD mkdir -p ~/.ente
cat <<EOF >~/.ente/config.yaml
endpoint:
api: http://localhost:8080
EOF
msg_ok "Configured Ente CLI"
msg_info "Setting up PostgreSQL"
DB_NAME="ente_db"
@ -133,13 +147,37 @@ jwt:
EOF
msg_ok "Created museum.yaml"
read -r -p "Enter the public URL for Ente backend (e.g., https://api.ente.yourdomain.com or http://192.168.1.100:8080) leave empty to use container IP: " backend_url
if [[ -z "$backend_url" ]]; then
LOCAL_IP=$(hostname -I | awk '{print $1}')
ENTE_BACKEND_URL="http://$LOCAL_IP:8080"
msg_info "No URL provided"
msg_ok "using local IP: $ENTE_BACKEND_URL\n"
else
ENTE_BACKEND_URL="$backend_url"
msg_info "URL provided"
msg_ok "Using provided URL: $ENTE_BACKEND_URL\n"
fi
read -r -p "Enter the public URL for Ente albums (e.g., https://albums.ente.yourdomain.com or http://192.168.1.100:3002) leave empty to use container IP: " albums_url
if [[ -z "$albums_url" ]]; then
LOCAL_IP=$(hostname -I | awk '{print $1}')
ENTE_ALBUMS_URL="http://$LOCAL_IP:3002"
msg_info "No URL provided"
msg_ok "using local IP: $ENTE_ALBUMS_URL\n"
else
ENTE_ALBUMS_URL="$albums_url"
msg_info "URL provided"
msg_ok "Using provided URL: $ENTE_ALBUMS_URL\n"
fi
export NEXT_PUBLIC_ENTE_ENDPOINT=$ENTE_BACKEND_URL
export NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=$ENTE_ALBUMS_URL
msg_info "Building Web Applications"
# Get container IP address
CONTAINER_IP=$(hostname -I | awk '{print $1}')
cd /opt/ente/web
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
$STD yarn install
export NEXT_PUBLIC_ENTE_ENDPOINT=http://${CONTAINER_IP}:8080
export NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=http://${CONTAINER_IP}:3002
$STD yarn build
$STD yarn build:accounts
$STD yarn build:auth
@ -153,12 +191,35 @@ cp -r apps/cast/out /var/www/ente/apps/cast
# Save build configuration for future rebuilds
cat <<REBUILD_EOF >/opt/ente/rebuild-frontend.sh
#!/usr/bin/env bash
# Rebuild Ente frontend with current IP
CONTAINER_IP=\$(hostname -I | awk '{print \$1}')
echo "Building frontend with IP: \$CONTAINER_IP"
# Rebuild Ente frontend
# Prompt for backend URL
read -r -p "Enter the public URL for Ente backend (e.g., https://api.ente.yourdomain.com or http://192.168.1.100:8080) leave empty to use container IP: " backend_url
if [[ -z "\$backend_url" ]]; then
LOCAL_IP=$(hostname -I | awk '{print $1}')
ENTE_BACKEND_URL="http://\$LOCAL_IP:8080"
echo "No URL provided, using local IP: \$ENTE_BACKEND_URL\n"
else
ENTE_BACKEND_URL="\$backend_url"
echo "Using provided URL: \$ENTE_BACKEND_URL\n"
fi
# Prompt for albums URL
read -r -p "Enter the public URL for Ente albums (e.g., https://albums.ente.yourdomain.com or http://192.168.1.100:3002) leave empty to use container IP: " albums_url
if [[ -z "\$albums_url" ]]; then
LOCAL_IP=\$(hostname -I | awk '{print $1}')
ENTE_ALBUMS_URL="http://\$LOCAL_IP:3002"
echo "No URL provided, using local IP: \$ENTE_ALBUMS_URL\n"
else
ENTE_ALBUMS_URL="\$albums_url"
echo "Using provided URL: \$ENTE_ALBUMS_URL\n"
fi
export NEXT_PUBLIC_ENTE_ENDPOINT=\$ENTE_BACKEND_URL
export NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=\$ENTE_ALBUMS_URL
echo "Building Web Applications\n"
cd /opt/ente/web
export NEXT_PUBLIC_ENTE_ENDPOINT=http://\${CONTAINER_IP}:8080
export NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=http://\${CONTAINER_IP}:3002
yarn build
yarn build:accounts
yarn build:auth
@ -312,8 +373,9 @@ echo -e "━━━━━━━━━━━━━━━━━━━━━━━
echo -e "\n${BL}Access URLs:${CL}"
echo -e " Photos: http://${CONTAINER_IP}:3000"
echo -e " Accounts: http://${CONTAINER_IP}:3001"
echo -e " Albums: ${ENTE_ALBUMS_URL}"
echo -e " Auth: http://${CONTAINER_IP}:3003"
echo -e " API: http://${CONTAINER_IP}:8080"
echo -e " API: ${ENTE_BACKEND_URL}"
echo -e "\n${YW}⚠️ Important Post-Installation Steps:${CL}"
echo -e "\n${BL}1. Create your first account:${CL}"
echo -e " • Open http://${CONTAINER_IP}:3000 in your browser"

View File

@ -0,0 +1,94 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://joplinapp.org/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y \
git \
rsync
msg_ok "Installed Dependencies"
PG_VERSION="17" setup_postgresql
NODE_VERSION=24 NODE_MODULE="yarn,npm,pm2" setup_nodejs
mkdir -p /opt/pm2
export PM2_HOME=/opt/pm2
$STD pm2 install pm2-logrotate
$STD pm2 set pm2-logrotate:max_size 100MB
$STD pm2 set pm2-logrotate:retain 5
$STD pm2 set pm2-logrotate:compress tr
msg_info "Setting up PostgreSQL Database"
DB_NAME=joplin
DB_USER=joplin
DB_PASS="$(openssl rand -base64 18 | cut -c1-13)"
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCODING 'UTF8' TEMPLATE template0;"
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC'"
{
echo "Joplin-Credentials"
echo "Joplin Database User: $DB_USER"
echo "Joplin Database Password: $DB_PASS"
echo "Joplin Database Name: $DB_NAME"
} >>~/joplin.creds
msg_ok "Set up PostgreSQL Database"
fetch_and_deploy_gh_release "joplin-server" "laurent22/joplin" "tarball" "latest"
msg_info "Setting up Joplin Server (Patience)"
LOCAL_IP=$(hostname -I | awk '{print $1}')
cd /opt/joplin-server
sed -i "/onenote-converter/d" packages/lib/package.json
$STD yarn config set --home enableTelemetry 0
export BUILD_SEQUENCIAL=1
$STD yarn install --inline-builds
cat <<EOF >/opt/joplin-server/.env
PM2_HOME=/opt/pm2
NODE_ENV=production
APP_BASE_URL=http://$LOCAL_IP:22300
APP_PORT=22300
DB_CLIENT=pg
POSTGRES_PASSWORD=$DB_PASS
POSTGRES_DATABASE=$DB_NAME
POSTGRES_USER=$DB_USER
POSTGRES_PORT=5432
POSTGRES_HOST=localhost
EOF
msg_ok "Setup Joplin Server"
msg_info "Setting up Service"
cat <<EOF >/etc/systemd/system/joplin-server.service
[Unit]
Description=Joplin Server Service
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/joplin-server/packages/server
EnvironmentFile=/opt/joplin-server/.env
ExecStart=/usr/bin/yarn start-prod
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now joplin-server
msg_ok "Service Setup"
motd_ssh
customize
cleanup_lxc

64
install/qdrant-install.sh Normal file
View File

@ -0,0 +1,64 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# Source: https://github.com/qdrant/qdrant
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
fetch_and_deploy_gh_release "qdrant" "qdrant/qdrant" "binary" "latest" "/usr/bin/qdrant"
msg_info "Creating Qdrant Configuration"
mkdir -p /var/lib/qdrant/storage
mkdir -p /var/lib/qdrant/snapshots
mkdir -p /etc/qdrant
chown -R root:root /var/lib/qdrant
chmod -R 755 /var/lib/qdrant
cat >/etc/qdrant/config.yaml <<EOF
log_level: INFO
storage:
storage_path: /var/lib/qdrant/storage
snapshots_path: /var/lib/qdrant/snapshots
service:
host: 0.0.0.0
http_port: 6333
grpc_port: 6334
enable_cors: true
EOF
msg_ok "Created Qdrant Configuration"
msg_info "Creating Qdrant Service"
cat >/etc/systemd/system/qdrant.service <<EOF
[Unit]
Description=Qdrant Vector Search Engine
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/qdrant --config-path /etc/qdrant/config.yaml
WorkingDirectory=/var/lib/qdrant
Restart=on-failure
RestartSec=5
User=root
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now qdrant
msg_ok "Created Qdrant Service"
motd_ssh
customize
cleanup_lxc

3549
misc/build copy 2.func Normal file

File diff suppressed because it is too large Load Diff

View File

@ -535,35 +535,6 @@ base_settings() {
TAGS="community-script,${var_tags:-}"
ENABLE_FUSE=${var_fuse:-"${1:-no}"}
ENABLE_TUN=${var_tun:-"${1:-no}"}
ENABLE_NESTING=${var_nesting:-"${1:-1}"}
ENABLE_KEYCTL=${var_keyctl:-"${1:-0}"}
ALLOW_MOUNT_FS=${var_mount_fs:-""}
ENABLE_MKNOD=${var_mknod:-"${1:-0}"}
PROTECT_CT=${var_protection:-"${1:-no}"}
CT_TIMEZONE=${var_timezone:-""}
# Normalize feature flags to 0/1 immediately (pct requires numeric values, not yes/no)
# This must happen here before any usage of these variables
case "${ENABLE_NESTING,,}" in
yes | true) ENABLE_NESTING="1" ;;
no | false) ENABLE_NESTING="0" ;;
esac
case "${ENABLE_KEYCTL,,}" in
yes | true) ENABLE_KEYCTL="1" ;;
no | false) ENABLE_KEYCTL="0" ;;
esac
case "${ENABLE_MKNOD,,}" in
yes | true) ENABLE_MKNOD="1" ;;
no | false) ENABLE_MKNOD="0" ;;
esac
case "${ENABLE_FUSE,,}" in
yes | true) ENABLE_FUSE="1" ;;
no | false) ENABLE_FUSE="0" ;;
esac
case "${PROTECT_CT,,}" in
yes | true) PROTECT_CT="1" ;;
no | false) PROTECT_CT="0" ;;
esac
# Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts
if [ -z "$var_os" ]; then
@ -2298,35 +2269,19 @@ build_container() {
none) ;;
esac
# Build FEATURES array with advanced settings
# Note: All feature flags are already normalized to 0/1 in default_settings()
# Proxmox requires each feature as a separate parameter, not comma-separated string
FEATURES_ARRAY=()
FEATURES_ARRAY+=("nesting=${ENABLE_NESTING}")
# keyctl: needed for Docker inside containers (systemd-networkd workaround)
# Typically needed for unprivileged containers with Docker
if [ "$CT_TYPE" == "1" ] || [ "$ENABLE_KEYCTL" == "1" ]; then
FEATURES_ARRAY+=("keyctl=1")
# Build FEATURES string (simple working version)
if [ "$CT_TYPE" == "1" ]; then
FEATURES="keyctl=1,nesting=1"
else
FEATURES="nesting=1"
fi
# mknod: allow device node creation (requires kernel 5.3+, experimental)
if [ "$ENABLE_MKNOD" == "1" ]; then
FEATURES_ARRAY+=("mknod=1")
if [ "$ENABLE_FUSE" == "yes" ]; then
FEATURES="$FEATURES,fuse=1"
fi
# FUSE: required for rclone, mergerfs, AppImage, etc.
if [ "$ENABLE_FUSE" == "1" ]; then
FEATURES_ARRAY+=("fuse=1")
fi
# mount: allow specific filesystems (e.g., nfs, ext4, etc.)
# Format: mount=fstype1;fstype2;fstype3 (semicolon-separated, not comma!)
if [ -n "$ALLOW_MOUNT_FS" ]; then
# Replace commas with semicolons for proper pct syntax
ALLOW_MOUNT_FS_FORMATTED="${ALLOW_MOUNT_FS//,/;}"
FEATURES_ARRAY+=("mount=$ALLOW_MOUNT_FS_FORMATTED")
fi
# NEW IMPLEMENTATION (Fixed): Build PCT_OPTIONS properly
# Key insight: Bash cannot export arrays, so we build the options as a string
TEMP_DIR=$(mktemp -d)
pushd "$TEMP_DIR" >/dev/null
@ -2335,19 +2290,11 @@ build_container() {
else
export FUNCTIONS_FILE_PATH="$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/install.func)"
fi
# Core exports for install.func
export DIAGNOSTICS="$DIAGNOSTICS"
export RANDOM_UUID="$RANDOM_UUID"
export SESSION_ID="$SESSION_ID"
export BUILD_LOG="$BUILD_LOG"
export INSTALL_LOG="/root/.install-${SESSION_ID}.log"
export dev_mode="${dev_mode:-}"
export DEV_MODE_MOTD="${DEV_MODE_MOTD:-false}"
export DEV_MODE_KEEP="${DEV_MODE_KEEP:-false}"
export DEV_MODE_TRACE="${DEV_MODE_TRACE:-false}"
export DEV_MODE_PAUSE="${DEV_MODE_PAUSE:-false}"
export DEV_MODE_BREAKPOINT="${DEV_MODE_BREAKPOINT:-false}"
export DEV_MODE_LOGS="${DEV_MODE_LOGS:-false}"
export DEV_MODE_DRYRUN="${DEV_MODE_DRYRUN:-false}"
export CACHER="$APT_CACHER"
export CACHER_IP="$APT_CACHER_IP"
export tz="$timezone"
@ -2361,61 +2308,75 @@ build_container() {
export CTTYPE="$CT_TYPE"
export ENABLE_FUSE="$ENABLE_FUSE"
export ENABLE_TUN="$ENABLE_TUN"
export ENABLE_NESTING="$ENABLE_NESTING"
export ENABLE_KEYCTL="$ENABLE_KEYCTL"
export ENABLE_MKNOD="$ENABLE_MKNOD"
export ALLOW_MOUNT_FS="$ALLOW_MOUNT_FS"
export PROTECT_CT="$PROTECT_CT"
export CT_TIMEZONE="$CT_TIMEZONE"
export PCT_OSTYPE="$var_os"
export PCT_OSVERSION="$var_version"
export PCT_DISK_SIZE="$DISK_SIZE"
# Build PCT_OPTIONS array (not string) for proper parameter handling
PCT_OPTIONS=()
# DEV_MODE exports (optional, for debugging)
export BUILD_LOG="$BUILD_LOG"
export INSTALL_LOG="/root/.install-${SESSION_ID}.log"
export dev_mode="${dev_mode:-}"
export DEV_MODE_MOTD="${DEV_MODE_MOTD:-false}"
export DEV_MODE_KEEP="${DEV_MODE_KEEP:-false}"
export DEV_MODE_TRACE="${DEV_MODE_TRACE:-false}"
export DEV_MODE_PAUSE="${DEV_MODE_PAUSE:-false}"
export DEV_MODE_BREAKPOINT="${DEV_MODE_BREAKPOINT:-false}"
export DEV_MODE_LOGS="${DEV_MODE_LOGS:-false}"
export DEV_MODE_DRYRUN="${DEV_MODE_DRYRUN:-false}"
# Add features - each as separate -features parameter
for feature in "${FEATURES_ARRAY[@]}"; do
PCT_OPTIONS+=("-features" "$feature")
done
PCT_OPTIONS+=("-hostname" "$HN")
PCT_OPTIONS+=("-tags" "$TAGS")
# Build PCT_OPTIONS as multi-line string
PCT_OPTIONS_STRING=" -features $FEATURES
-hostname $HN
-tags $TAGS"
# Add storage if specified
if [ -n "$SD" ]; then
PCT_OPTIONS+=($SD) # Storage device flags (already formatted)
PCT_OPTIONS_STRING="$PCT_OPTIONS_STRING
$SD"
fi
# Add nameserver if specified
if [ -n "$NS" ]; then
PCT_OPTIONS+=($NS) # Nameserver flags (already formatted)
PCT_OPTIONS_STRING="$PCT_OPTIONS_STRING
$NS"
fi
# Network configuration (single string with all network parameters)
PCT_OPTIONS+=($NET_STRING)
# Network configuration
PCT_OPTIONS_STRING="$PCT_OPTIONS_STRING
$NET_STRING
-onboot 1
-cores $CORE_COUNT
-memory $RAM_SIZE
-unprivileged $CT_TYPE"
PCT_OPTIONS+=("-onboot" "1")
PCT_OPTIONS+=("-cores" "$CORE_COUNT")
PCT_OPTIONS+=("-memory" "$RAM_SIZE")
PCT_OPTIONS+=("-unprivileged" "$CT_TYPE")
# Protection flag
if [ "$PROTECT_CT" == "1" ]; then
PCT_OPTIONS+=("-protection" "1")
# Protection flag (if var_protection was set)
if [ "${PROTECT_CT:-}" == "1" ] || [ "${PROTECT_CT:-}" == "yes" ]; then
PCT_OPTIONS_STRING="$PCT_OPTIONS_STRING
-protection 1"
fi
# Timezone flag
if [ -n "$CT_TIMEZONE" ]; then
PCT_OPTIONS+=("-timezone" "$CT_TIMEZONE")
# Timezone flag (if var_timezone was set)
if [ -n "${CT_TIMEZONE:-}" ]; then
PCT_OPTIONS_STRING="$PCT_OPTIONS_STRING
-timezone $CT_TIMEZONE"
fi
# Password flag (already formatted as "-password xxx")
# Password (already formatted)
if [ -n "$PW" ]; then
PCT_OPTIONS+=($PW)
PCT_OPTIONS_STRING="$PCT_OPTIONS_STRING
$PW"
fi
export PCT_OPTIONS
# Export as string (this works, unlike arrays!)
export PCT_OPTIONS="$PCT_OPTIONS_STRING"
export TEMPLATE_STORAGE="${var_template_storage:-}"
export CONTAINER_STORAGE="${var_container_storage:-}"
# # DEBUG: Show final PCT_OPTIONS being exported
# echo "[DEBUG] PCT_OPTIONS to be exported:"
# echo "$PCT_OPTIONS" | sed 's/^/ /'
# echo "[DEBUG] Calling create_lxc_container..."
create_lxc_container || exit $?
LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
@ -2557,7 +2518,7 @@ EOF
if [[ $gpu_count -eq 1 ]]; then
# Automatic selection for single GPU
selected_gpu="${available_gpus[0]}"
msg_custom "⚙️" "${GN}" "Automatically configuring ${selected_gpu} GPU passthrough"
msg_ok "Automatically configuring ${selected_gpu} GPU passthrough"
else
# Multiple GPUs - ask user
echo -e "\n${INFO} Multiple GPU types detected:"
@ -2934,7 +2895,7 @@ fix_gpu_gids() {
return 0
fi
msg_custom "🔧" "${BL}" "Detecting and setting correct GPU group IDs"
msg_info "Detecting and setting correct GPU group IDs"
# Get actual GIDs from container
local video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3")
@ -3137,7 +3098,7 @@ create_lxc_container() {
msg_ok "LXC stack upgraded."
if [[ "$do_retry" == "yes" ]]; then
msg_info "Retrying container creation after upgrade"
if pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
if pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
msg_ok "Container created successfully after upgrade."
return 0
else
@ -3563,9 +3524,12 @@ create_lxc_container() {
grep -q "root:100000:65536" /etc/subuid || echo "root:100000:65536" >>/etc/subuid
grep -q "root:100000:65536" /etc/subgid || echo "root:100000:65536" >>/etc/subgid
# Assemble pct options
PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}})
[[ " ${PCT_OPTIONS[*]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "$CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}")
# PCT_OPTIONS is now a string (exported from build_container)
# Add rootfs if not already specified
if [[ ! "$PCT_OPTIONS" =~ "-rootfs" ]]; then
PCT_OPTIONS="$PCT_OPTIONS
-rootfs $CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}"
fi
# Lock by template file (avoid concurrent downloads/creates)
lockfile="/tmp/template.${TEMPLATE}.lock"
@ -3579,11 +3543,22 @@ create_lxc_container() {
}
LOGFILE="/tmp/pct_create_${CTID}_$(date +%Y%m%d_%H%M%S)_${SESSION_ID}.log"
msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}"
# # DEBUG: Show the actual command that will be executed
# echo "[DEBUG] ===== PCT CREATE COMMAND DETAILS ====="
# echo "[DEBUG] CTID: $CTID"
# echo "[DEBUG] Template: ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}"
# echo "[DEBUG] PCT_OPTIONS (will be word-split):"
# echo "$PCT_OPTIONS" | sed 's/^/ /'
# echo "[DEBUG] Full command line:"
# echo " pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} $PCT_OPTIONS"
# echo "[DEBUG] ========================================"
msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} $PCT_OPTIONS"
msg_debug "Logfile: $LOGFILE"
# First attempt
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >"$LOGFILE" 2>&1; then
# First attempt (PCT_OPTIONS is a multi-line string, use it directly)
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >"$LOGFILE" 2>&1; then
msg_debug "Container creation failed on ${TEMPLATE_STORAGE}. Validating template..."
# Validate template file
@ -3602,7 +3577,7 @@ create_lxc_container() {
fi
# Retry after repair
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
# Fallback to local storage if not already on local
if [[ "$TEMPLATE_STORAGE" != "local" ]]; then
msg_info "Retrying container creation with fallback to local storage..."
@ -3611,7 +3586,7 @@ create_lxc_container() {
msg_info "Downloading template to local..."
pveam download local "$TEMPLATE" >/dev/null 2>&1
fi
if ! pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
if ! pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
# Local fallback also failed - check for LXC stack version issue
if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo
@ -3635,7 +3610,7 @@ create_lxc_container() {
msg_error "Container creation failed. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x
pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" 2>&1 | tee -a "$LOGFILE"
pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS 2>&1 | tee -a "$LOGFILE"
set +x
fi
exit 209
@ -3667,7 +3642,7 @@ create_lxc_container() {
msg_error "Container creation failed. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x
pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" 2>&1 | tee -a "$LOGFILE"
pct create "$CTID" "local:vztmpl/${TEMPLATE}" $PCT_OPTIONS 2>&1 | tee -a "$LOGFILE"
set +x
fi
exit 209

277
misc/install copy.func Normal file
View File

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

View File

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

View File

@ -29,7 +29,7 @@ var_os="debian"
var_version="13"
DISK_SIZE="10G"
USE_CLOUD_INIT="no"
INSTALL_PORTAINER="no"
# INSTALL_PORTAINER="no"
OS_TYPE=""
OS_VERSION=""
@ -284,16 +284,16 @@ function select_cloud_init() {
fi
}
function select_portainer() {
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "PORTAINER" \
--yesno "Install Portainer for Docker management?\n\nPortainer is a lightweight management UI for Docker.\n\nAccess after installation:\n• HTTP: http://<VM-IP>:9000\n• HTTPS: https://<VM-IP>:9443" 14 68); then
INSTALL_PORTAINER="yes"
echo -e "${ADVANCED}${BOLD}${DGN}Portainer: ${BGN}yes${CL}"
else
INSTALL_PORTAINER="no"
echo -e "${ADVANCED}${BOLD}${DGN}Portainer: ${BGN}no${CL}"
fi
}
# function select_portainer() {
# if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "PORTAINER" \
# --yesno "Install Portainer for Docker management?\n\nPortainer is a lightweight management UI for Docker.\n\nAccess after installation:\n• HTTP: http://<VM-IP>:9000\n• HTTPS: https://<VM-IP>:9443" 14 68); then
# INSTALL_PORTAINER="yes"
# echo -e "${ADVANCED}${BOLD}${DGN}Portainer: ${BGN}yes${CL}"
# else
# INSTALL_PORTAINER="no"
# echo -e "${ADVANCED}${BOLD}${DGN}Portainer: ${BGN}no${CL}"
# fi
# }
function get_image_url() {
local arch=$(dpkg --print-architecture)
@ -323,7 +323,7 @@ function default_settings() {
select_cloud_init
# Portainer Selection - ALWAYS ask
select_portainer
# select_portainer
# Set defaults for other settings
VMID=$(get_valid_nextid)
@ -367,7 +367,7 @@ function advanced_settings() {
select_cloud_init
# Portainer Selection - ALWAYS ask (at the beginning)
select_portainer
# select_portainer
METHOD="advanced"
[ -z "${VMID:-}" ] && VMID=$(get_valid_nextid)
@ -703,7 +703,7 @@ for i in {1..10}; do
done
# Install Portainer if requested
INSTALL_PORTAINER_PLACEHOLDER
# INSTALL_PORTAINER_PLACEHOLDER
# Create completion flag
echo \"[\\$(date)] Docker installation completed successfully\"
@ -711,20 +711,20 @@ touch /root/.docker-installed
INSTALLEOF" >/dev/null
# Add Portainer installation script if requested
if [ "$INSTALL_PORTAINER" = "yes" ]; then
virt-customize -q -a "${FILE}" --run-command "cat > /root/install-portainer.sh << 'PORTAINEREOF'
#!/bin/bash
exec >> /var/log/install-docker.log 2>&1
echo \"[\\$(date)] Installing Portainer\"
docker volume create portainer_data
docker run -d -p 9000:9000 -p 9443:9443 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
echo \"[\\$(date)] Portainer installed and started\"
PORTAINEREOF" >/dev/null
virt-customize -q -a "${FILE}" --run-command "chmod +x /root/install-portainer.sh" >/dev/null
virt-customize -q -a "${FILE}" --run-command "sed -i 's|INSTALL_PORTAINER_PLACEHOLDER|/root/install-portainer.sh|' /root/install-docker.sh" >/dev/null
else
virt-customize -q -a "${FILE}" --run-command "sed -i 's|INSTALL_PORTAINER_PLACEHOLDER|echo \"[\\\\\\$(date)] Skipping Portainer installation\"|' /root/install-docker.sh" >/dev/null
fi
# if [ "$INSTALL_PORTAINER" = "yes" ]; then
# virt-customize -q -a "${FILE}" --run-command "cat > /root/install-portainer.sh << 'PORTAINEREOF'
# #!/bin/bash
# exec >> /var/log/install-docker.log 2>&1
# echo \"[\\$(date)] Installing Portainer\"
# docker volume create portainer_data
# docker run -d -p 9000:9000 -p 9443:9443 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
# echo \"[\\$(date)] Portainer installed and started\"
# PORTAINEREOF" >/dev/null
# virt-customize -q -a "${FILE}" --run-command "chmod +x /root/install-portainer.sh" >/dev/null
# virt-customize -q -a "${FILE}" --run-command "sed -i 's|INSTALL_PORTAINER_PLACEHOLDER|/root/install-portainer.sh|' /root/install-docker.sh" >/dev/null
# else
# virt-customize -q -a "${FILE}" --run-command "sed -i 's|INSTALL_PORTAINER_PLACEHOLDER|echo \"[\\\\\\$(date)] Skipping Portainer installation\"|' /root/install-docker.sh" >/dev/null
# fi
virt-customize -q -a "${FILE}" --run-command "chmod +x /root/install-docker.sh" >/dev/null
@ -899,15 +899,15 @@ else
echo -e "${TAB}${DGN}Docker: ${BGN}Latest (via get.docker.com)${CL}"
fi
if [ "$INSTALL_PORTAINER" = "yes" ]; then
if [ -n "$VM_IP" ]; then
echo -e "${TAB}${DGN}Portainer: ${BGN}https://${VM_IP}:9443${CL}"
else
echo -e "${TAB}${DGN}Portainer: ${BGN}Will be accessible at https://<VM-IP>:9443${CL}"
echo -e "${TAB}${YW}⚠️ Wait 2-3 minutes after boot for installation to complete${CL}"
echo -e "${TAB}${YW}⚠️ Get IP with: ${BL}qm guest cmd ${VMID} network-get-interfaces${CL}"
fi
fi
# if [ "$INSTALL_PORTAINER" = "yes" ]; then
# if [ -n "$VM_IP" ]; then
# echo -e "${TAB}${DGN}Portainer: ${BGN}https://${VM_IP}:9443${CL}"
# else
# echo -e "${TAB}${DGN}Portainer: ${BGN}Will be accessible at https://<VM-IP>:9443${CL}"
# echo -e "${TAB}${YW}⚠️ Wait 2-3 minutes after boot for installation to complete${CL}"
# echo -e "${TAB}${YW}⚠️ Get IP with: ${BL}qm guest cmd ${VMID} network-get-interfaces${CL}"
# fi
# fi
if [ "$USE_CLOUD_INIT" = "yes" ]; then
display_cloud_init_info "$VMID" "$HN"
fi