Update 1.2.4

This commit is contained in:
MacRimi
2026-07-21 18:26:11 +02:00
parent c81230b0f3
commit b2c6a6c536
16 changed files with 967 additions and 342 deletions

View File

@@ -497,7 +497,7 @@ force_apt_ipv4() {
# ==========================================================
apply_network_optimizations() {
local FUNC_VERSION="1.0"
local FUNC_VERSION="1.1"
# description: Tune TCP buffers, somaxconn, IPv4 hardening and disable rp_filter on fw bridges (PVE 9 compatible).
msg_info "$(translate "Optimizing network settings...")"
NECESSARY_REBOOT=1
@@ -548,8 +548,38 @@ EOF
sysctl --system > /dev/null 2>&1
cat > /usr/local/sbin/proxmenux-fwbr-tune <<'EOF'
#!/usr/bin/env bash
# Set rp_filter=0 and log_martians=0 on Proxmox fw bridge interfaces.
# No arg → sweep every interface currently under /proc/sys/net/ipv4/conf/.
# One arg → tune only that interface (used by the udev rule).
set -u
cat >/etc/systemd/system/proxmenux-fwbr-tune.service <<'EOF'
tune_interface() {
local iface="$1"
local sysctl_path="/proc/sys/net/ipv4/conf/${iface}"
case "$iface" in
fwbr*|fwln*|fwpr*|tap*)
[[ -d "$sysctl_path" ]] || return 0
[[ -w "$sysctl_path/rp_filter" ]] && printf '0\n' > "$sysctl_path/rp_filter"
[[ -w "$sysctl_path/log_martians" ]] && printf '0\n' > "$sysctl_path/log_martians"
;;
esac
}
if [[ $# -gt 0 ]]; then
tune_interface "$1"
else
for sysctl_path in /proc/sys/net/ipv4/conf/*; do
[[ -d "$sysctl_path" ]] || continue
tune_interface "${sysctl_path##*/}"
done
fi
EOF
chmod 0755 /usr/local/sbin/proxmenux-fwbr-tune
chown root:root /usr/local/sbin/proxmenux-fwbr-tune
cat > /etc/systemd/system/proxmenux-fwbr-tune.service <<'EOF'
[Unit]
Description=ProxMenux - Tune rp_filter/log_martians on virtual fw bridges
After=network-online.target
@@ -557,14 +587,26 @@ Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'for i in /proc/sys/net/ipv4/conf/*; do n=${i##*/}; case "$n" in fwbr*|fwln*|fwpr*|tap*) echo 0 > /proc/sys/net/ipv4/conf/$n/rp_filter; echo 0 > /proc/sys/net/ipv4/conf/$n/log_martians; esac; done'
ExecStart=/usr/local/sbin/proxmenux-fwbr-tune
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
cat > /etc/udev/rules.d/99-proxmenux-fwbr-tune.rules <<'EOF'
ACTION=="add", SUBSYSTEM=="net", KERNEL=="fwbr*", RUN+="/usr/local/sbin/proxmenux-fwbr-tune %k"
ACTION=="add", SUBSYSTEM=="net", KERNEL=="fwln*", RUN+="/usr/local/sbin/proxmenux-fwbr-tune %k"
ACTION=="add", SUBSYSTEM=="net", KERNEL=="fwpr*", RUN+="/usr/local/sbin/proxmenux-fwbr-tune %k"
ACTION=="add", SUBSYSTEM=="net", KERNEL=="tap*", RUN+="/usr/local/sbin/proxmenux-fwbr-tune %k"
EOF
chmod 0644 /etc/udev/rules.d/99-proxmenux-fwbr-tune.rules
chown root:root /etc/udev/rules.d/99-proxmenux-fwbr-tune.rules
systemctl daemon-reload >/dev/null 2>&1 || true
udevadm control --reload-rules >/dev/null 2>&1 || true
systemctl enable --now proxmenux-fwbr-tune.service >/dev/null 2>&1 || true
/usr/local/sbin/proxmenux-fwbr-tune >/dev/null 2>&1 || true
local interfaces_file="/etc/network/interfaces"
@@ -638,7 +680,7 @@ EOF
install_log2ram_auto() {
local FUNC_VERSION="1.2"
local FUNC_VERSION="1.3"
# description: Install Log2RAM with size auto-tuned to host RAM (128M/256M/512M); SSD/M.2 detection skips on rotational disks.
@@ -727,6 +769,52 @@ install_log2ram_auto() {
return 1
fi
# Drop ACL preservation from the upstream rsync call: some
# /var/log.hdd filesystems reject POSIX ACLs and log2ram write
# exits 23 with `set_acl: Operation not supported`. xattrs stay.
local _l2r_bin
for _l2r_bin in \
"$(command -v log2ram 2>/dev/null)" \
/usr/local/bin/log2ram \
/usr/sbin/log2ram \
/usr/bin/log2ram
do
[[ -n "$_l2r_bin" && -f "$_l2r_bin" ]] || continue
if grep -q 'rsync -aAXv ' "$_l2r_bin" 2>/dev/null; then
cp -a "$_l2r_bin" "${_l2r_bin}.proxmenux.bak"
sed -i 's/rsync -aAXv /rsync -aXv --no-acls /g' "$_l2r_bin"
fi
break
done
# Size-based rotation for the PBS API logs — the upstream package
# ships no logrotate rule and pvestatd's local-datastore poll fills
# them fast enough to saturate a tmpfs /var/log.
if dpkg-query -W -f='${Status}' proxmox-backup-server 2>/dev/null \
| grep -q 'install ok installed'; then
mkdir -p /var/log/proxmox-backup/api 2>/dev/null || true
cat > /etc/logrotate.d/proxmox-backup-api <<'EOF'
/var/log/proxmox-backup/api/access.log /var/log/proxmox-backup/api/auth.log {
size 20M
rotate 3
compress
delaycompress
missingok
notifempty
copytruncate
}
EOF
chmod 0644 /etc/logrotate.d/proxmox-backup-api
chown root:root /etc/logrotate.d/proxmox-backup-api
cat > /etc/cron.hourly/proxmox-backup-logrotate <<'EOF'
#!/bin/sh
/usr/sbin/logrotate /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1
EOF
chmod 0755 /etc/cron.hourly/proxmox-backup-logrotate
chown root:root /etc/cron.hourly/proxmox-backup-logrotate
msg_ok "$(translate "PBS API log rotation configured (hourly, size-based)")"
fi
systemctl enable --now log2ram >/dev/null 2>&1 || true
systemctl daemon-reload >/dev/null 2>&1 || true
@@ -766,13 +854,10 @@ EOF
cat > /usr/local/bin/log2ram-check.sh <<'EOF'
#!/usr/bin/env bash
# v1.2 — `log2ram write` only copies tmpfs→disk; it does NOT shrink
# the tmpfs. When journald or pveproxy/access.log grow past their
# limits the tmpfs hit 100% and PVE crashed with "No space left on
# device" on Shell open (community-reported: JC Miñarro, Nicolás P.
# de A., 17-18/05). We now vacuum the journal and truncate the
# non-rotating logs that actually consume the tmpfs before calling
# `log2ram write`.
# Watch /var/log usage on Log2RAM's tmpfs and act at two thresholds:
# > 80% → vacuum journald down to ~30% of SIZE, then log2ram write
# > 92% → aggressive: journal to ~5%, rotate PBS API logs if present,
# truncate pveproxy/pveam, then log2ram write
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
CONF_FILE="/etc/log2ram.conf"
@@ -793,15 +878,13 @@ LOCK="/run/log2ram-check.lock"
exec 9>"$LOCK" 2>/dev/null || exit 0
flock -n 9 || exit 0
# `log2ram write` alone leaves the tmpfs full. Real recovery requires:
# (a) journal vacuum — journald respects --vacuum-size unconditionally,
# unlike SystemMaxUse which only enforces on rotation boundaries;
# (b) truncating logs that aren't rotated by logrotate (pveproxy, pveam);
# (c) THEN syncing to disk so the persistent copy reflects reality.
if (( USED_BYTES > EMERGENCY_BYTES )); then
SAFE_JOURNAL_MB=$(( SIZE_MiB * 5 / 100 ))
[[ "$SAFE_JOURNAL_MB" -lt 16 ]] && SAFE_JOURNAL_MB=16
journalctl --vacuum-size="${SAFE_JOURNAL_MB}M" >/dev/null 2>&1 || true
if [[ -x /usr/sbin/logrotate && -f /etc/logrotate.d/proxmox-backup-api ]]; then
/usr/sbin/logrotate -f /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1 || true
fi
: > /var/log/pveproxy/access.log 2>/dev/null || true
: > /var/log/pveproxy/error.log 2>/dev/null || true
: > /var/log/pveam.log 2>/dev/null || true
@@ -820,8 +903,7 @@ EOF
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
# Runs every 10 min starting at :03 to avoid overlap with debian-sa1 (:00/:10/:20...)
# nice -n 19 + ionice -c 3 ensures minimum CPU/IO priority (no visible spikes)
# nice/ionice keep the check off the priority queue for scheduled tasks.
3-59/10 * * * * root nice -n 19 ionice -c 3 /usr/local/bin/log2ram-check.sh >/dev/null 2>&1
EOF
chmod 0644 /etc/cron.d/log2ram-auto-sync
@@ -1011,57 +1093,37 @@ enable_zfs_autotrim() {
setup_persistent_network() {
local FUNC_VERSION="1.0"
local FUNC_VERSION="1.1"
# description: Pin NIC names to MAC addresses via systemd .link files so kernel updates don't shuffle interface names.
local LINK_DIR="/etc/systemd/network"
local BACKUP_DIR="/etc/systemd/network/backup-$(date +%Y%m%d-%H%M%S)"
local pve_version
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
msg_info "$(translate "Setting up persistent network interfaces")"
sleep 2
# Same legacy-conflict warning as in customizable_post_install.sh.
if [[ -f /etc/network/interfaces ]]; then
if grep -qE '^[[:space:]]*allow-hotplug[[:space:]]' /etc/network/interfaces 2>/dev/null; then
msg_warn "$(translate '/etc/network/interfaces uses allow-hotplug. Renaming interfaces via systemd .link can break that flow — review the file after reboot.')"
fi
fi
mkdir -p "$LINK_DIR"
local count=0 removed_stale=0 removed_legacy=0
while IFS='=' read -r key value; do
case "$key" in
COUNT) count="$value" ;;
REMOVED_STALE) removed_stale="$value" ;;
REMOVED_LEGACY) removed_legacy="$value" ;;
esac
done < <(pmx_setup_persistent_network)
if ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
mkdir -p "$BACKUP_DIR"
cp "$LINK_DIR"/*.link "$BACKUP_DIR"/ 2>/dev/null || true
if (( removed_legacy > 0 )); then
msg_ok "$(translate "Migrated") $removed_legacy $(translate "legacy .link file(s) to the ProxMenux-managed format")"
fi
local count=0
for iface in $(ls /sys/class/net/ | grep -vE "lo|docker|veth|br-|vmbr|tap|fwpr|fwln|virbr|bond|cilium|zt|wg"); do
if [[ -e "/sys/class/net/$iface/device" ]] || [[ -e "/sys/class/net/$iface/phy80211" ]]; then
local MAC=$(cat /sys/class/net/$iface/address 2>/dev/null)
if [[ "$MAC" =~ ^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$ ]]; then
local LINK_FILE="$LINK_DIR/10-$iface.link"
cat > "$LINK_FILE" <<EOF
[Match]
MACAddress=$MAC
[Link]
Name=$iface
EOF
chmod 644 "$LINK_FILE"
((count++))
fi
fi
done
if [[ $count -gt 0 ]]; then
if (( removed_stale > 0 )); then
msg_ok "$(translate "Reconciled") $removed_stale $(translate "stale entry/entries for interfaces no longer present")"
fi
if (( count > 0 )); then
msg_ok "$(translate "Created persistent names for") $count $(translate "interfaces")"
# In PVE9, systemd-networkd is the native network backend and udev processes
# .link files directly. Reloading udev rules makes the new .link files effective
# immediately for any interface added later (hotplug, new NICs) without waiting
# for a full reboot. On PVE8 (ifupdown2), names are resolved at boot anyway.
if [[ "$pve_version" -ge 9 ]]; then
udevadm control --reload-rules 2>/dev/null || true
msg_ok "$(translate "PVE9: udev rules reloaded — new interfaces will get correct names without reboot")"

View File

@@ -778,7 +778,7 @@ force_apt_ipv4() {
apply_network_optimizations() {
local FUNC_VERSION="1.0"
local FUNC_VERSION="1.1"
# description: Tune TCP buffers, somaxconn, IPv4 hardening and disable rp_filter on fw bridges (PVE 9 compatible).
msg_info "$(translate "Optimizing network settings...")"
NECESSARY_REBOOT=1
@@ -839,6 +839,66 @@ EOF
sysctl --system > /dev/null 2>&1
cat > /usr/local/sbin/proxmenux-fwbr-tune <<'EOF'
#!/usr/bin/env bash
# Set rp_filter=0 and log_martians=0 on Proxmox fw bridge interfaces.
# No arg → sweep every interface currently under /proc/sys/net/ipv4/conf/.
# One arg → tune only that interface (used by the udev rule).
set -u
tune_interface() {
local iface="$1"
local sysctl_path="/proc/sys/net/ipv4/conf/${iface}"
case "$iface" in
fwbr*|fwln*|fwpr*|tap*)
[[ -d "$sysctl_path" ]] || return 0
[[ -w "$sysctl_path/rp_filter" ]] && printf '0\n' > "$sysctl_path/rp_filter"
[[ -w "$sysctl_path/log_martians" ]] && printf '0\n' > "$sysctl_path/log_martians"
;;
esac
}
if [[ $# -gt 0 ]]; then
tune_interface "$1"
else
for sysctl_path in /proc/sys/net/ipv4/conf/*; do
[[ -d "$sysctl_path" ]] || continue
tune_interface "${sysctl_path##*/}"
done
fi
EOF
chmod 0755 /usr/local/sbin/proxmenux-fwbr-tune
chown root:root /usr/local/sbin/proxmenux-fwbr-tune
cat > /etc/systemd/system/proxmenux-fwbr-tune.service <<'EOF'
[Unit]
Description=ProxMenux - Tune rp_filter/log_martians on virtual fw bridges
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/proxmenux-fwbr-tune
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/udev/rules.d/99-proxmenux-fwbr-tune.rules <<'EOF'
ACTION=="add", SUBSYSTEM=="net", KERNEL=="fwbr*", RUN+="/usr/local/sbin/proxmenux-fwbr-tune %k"
ACTION=="add", SUBSYSTEM=="net", KERNEL=="fwln*", RUN+="/usr/local/sbin/proxmenux-fwbr-tune %k"
ACTION=="add", SUBSYSTEM=="net", KERNEL=="fwpr*", RUN+="/usr/local/sbin/proxmenux-fwbr-tune %k"
ACTION=="add", SUBSYSTEM=="net", KERNEL=="tap*", RUN+="/usr/local/sbin/proxmenux-fwbr-tune %k"
EOF
chmod 0644 /etc/udev/rules.d/99-proxmenux-fwbr-tune.rules
chown root:root /etc/udev/rules.d/99-proxmenux-fwbr-tune.rules
systemctl daemon-reload >/dev/null 2>&1 || true
udevadm control --reload-rules >/dev/null 2>&1 || true
systemctl enable --now proxmenux-fwbr-tune.service >/dev/null 2>&1 || true
/usr/local/sbin/proxmenux-fwbr-tune >/dev/null 2>&1 || true
local interfaces_file="/etc/network/interfaces"
if ! grep -q 'source /etc/network/interfaces.d/*' "$interfaces_file"; then
@@ -1147,86 +1207,58 @@ EOF
optimize_zfs_arc() {
local FUNC_VERSION="1.0"
# description: Cap ZFS ARC to a sensible fraction of host RAM so VMs don't fight the kernel for memory.
msg_info2 "$(translate "Optimizing ZFS ARC size according to available memory...")"
local FUNC_VERSION="1.1"
# description: Cap ZFS ARC max to a sensible fraction of host RAM so VMs don't fight the kernel for memory. Only sets zfs_arc_max; other OpenZFS tunables stay at their defaults.
local zfs_conf="/etc/modprobe.d/99-zfsarc.conf"
local ram_bytes arc_max
# Check if ZFS is installed
if ! command -v zfs > /dev/null; then
msg_info2 "$(translate "Optimizing ZFS ARC maximum size...")"
if ! command -v zpool >/dev/null 2>&1; then
msg_warn "$(translate "ZFS not detected. Skipping ZFS ARC optimization.")"
return 0
fi
# Ensure RAM_SIZE_GB is set
if [ -z "$RAM_SIZE_GB" ]; then
RAM_SIZE_GB=$(free -g | awk '/^Mem:/{print $2}')
if [ -z "$RAM_SIZE_GB" ] || [ "$RAM_SIZE_GB" -eq 0 ]; then
msg_warn "$(translate "Failed to detect RAM size. Using default value of 16GB for ZFS ARC optimization.")"
RAM_SIZE_GB=16 # Default to 16GB if detection fails
fi
if ! zpool list -H -o name 2>/dev/null | grep -q .; then
msg_warn "$(translate "No ZFS pools detected. Skipping ZFS ARC optimization.")"
return 0
fi
msg_ok "$(translate "Detected RAM size: ${RAM_SIZE_GB} GB")"
ram_bytes=$(awk '/MemTotal:/ { print $2 * 1024 }' /proc/meminfo)
if [[ -z "$ram_bytes" || "$ram_bytes" -le 0 ]]; then
msg_error "$(translate "Unable to determine the installed memory.")"
return 1
fi
# Calculate ZFS ARC sizes
if [[ "$RAM_SIZE_GB" -le 16 ]]; then
MY_ZFS_ARC_MIN=536870911 # 512MB
MY_ZFS_ARC_MAX=536870912 # 512MB
elif [[ "$RAM_SIZE_GB" -le 32 ]]; then
MY_ZFS_ARC_MIN=1073741823 # 1GB
MY_ZFS_ARC_MAX=1073741824 # 1GB
if (( ram_bytes <= 16 * 1024 * 1024 * 1024 )); then
arc_max=$((512 * 1024 * 1024))
elif (( ram_bytes <= 32 * 1024 * 1024 * 1024 )); then
arc_max=$((1024 * 1024 * 1024))
else
# Use 1/16 of RAM for min and 1/8 for max
MY_ZFS_ARC_MIN=$((RAM_SIZE_GB * 1073741824 / 16))
MY_ZFS_ARC_MAX=$((RAM_SIZE_GB * 1073741824 / 8))
arc_max=$((ram_bytes / 8))
fi
(( arc_max < 512 * 1024 * 1024 )) && arc_max=$((512 * 1024 * 1024))
if [[ -f "$zfs_conf" && ! -f "${zfs_conf}.bak" ]]; then
cp -p "$zfs_conf" "${zfs_conf}.bak"
fi
# Enforce the minimum values
MY_ZFS_ARC_MIN=$((MY_ZFS_ARC_MIN > 536870911 ? MY_ZFS_ARC_MIN : 536870911))
MY_ZFS_ARC_MAX=$((MY_ZFS_ARC_MAX > 536870912 ? MY_ZFS_ARC_MAX : 536870912))
# Apply ZFS tuning parameters
local zfs_conf="/etc/modprobe.d/99-zfsarc.conf"
local config_changed=false
if [ -f "$zfs_conf" ]; then
msg_info "$(translate "Checking existing ZFS ARC configuration...")"
if ! grep -q "zfs_arc_min=$MY_ZFS_ARC_MIN" "$zfs_conf" || \
! grep -q "zfs_arc_max=$MY_ZFS_ARC_MAX" "$zfs_conf"; then
msg_ok "$(translate "Changes detected. Updating ZFS ARC configuration...")"
cp "$zfs_conf" "${zfs_conf}.bak"
config_changed=true
else
msg_ok "$(translate "ZFS ARC configuration is up to date")"
fi
else
msg_info "$(translate "Creating new ZFS ARC configuration...")"
config_changed=true
fi
if $config_changed; then
cat <<EOF > "$zfs_conf"
# ZFS tuning
# Use 1/8 RAM for MAX cache, 1/16 RAM for MIN cache, or 512MB/1GB for systems with <= 32GB RAM
options zfs zfs_arc_min=$MY_ZFS_ARC_MIN
options zfs zfs_arc_max=$MY_ZFS_ARC_MAX
# Enable prefetch method
options zfs l2arc_noprefetch=0
# Set max write speed to L2ARC (500MB)
options zfs l2arc_write_max=524288000
options zfs zfs_txg_timeout=60
cat > "$zfs_conf" <<EOF
# ProxMenux ZFS ARC configuration
# Only zfs_arc_max is set; zfs_arc_min stays at the OpenZFS default (auto).
options zfs zfs_arc_max=$arc_max
EOF
if [ $? -eq 0 ]; then
msg_ok "$(translate "ZFS ARC configuration file created/updated successfully")"
NECESSARY_REBOOT=1
else
msg_error "$(translate "Failed to create/update ZFS ARC configuration file")"
fi
msg_info "$(translate "Updating initramfs so the ARC cap applies at next boot...")"
if ! update-initramfs -u -k all >/dev/null 2>&1; then
msg_error "$(translate "Failed to update initramfs.")"
return 1
fi
if command -v proxmox-boot-tool >/dev/null 2>&1; then
proxmox-boot-tool refresh >/dev/null 2>&1 || true
fi
NECESSARY_REBOOT=1
msg_ok "$(translate "ZFS ARC maximum configured:") $arc_max $(translate "bytes")"
msg_success "$(translate "ZFS ARC optimization completed")"
register_tool "zfs_arc" true "$FUNC_VERSION"
}
@@ -2493,7 +2525,7 @@ update_pve_appliance_manager() {
configure_log2ram() {
local FUNC_VERSION="1.2"
local FUNC_VERSION="1.3"
# description: Install Log2RAM with user-chosen RAM size; prompts for size and SSD/M.2 awareness before applying.
msg_info2 "$(translate "Preparing Log2RAM configuration")"
sleep 1
@@ -2591,6 +2623,52 @@ configure_log2ram() {
return 1
fi
# Drop ACL preservation from the upstream rsync call: some
# /var/log.hdd filesystems reject POSIX ACLs and log2ram write
# exits 23 with `set_acl: Operation not supported`. xattrs stay.
local _l2r_bin
for _l2r_bin in \
"$(command -v log2ram 2>/dev/null)" \
/usr/local/bin/log2ram \
/usr/sbin/log2ram \
/usr/bin/log2ram
do
[[ -n "$_l2r_bin" && -f "$_l2r_bin" ]] || continue
if grep -q 'rsync -aAXv ' "$_l2r_bin" 2>/dev/null; then
cp -a "$_l2r_bin" "${_l2r_bin}.proxmenux.bak"
sed -i 's/rsync -aAXv /rsync -aXv --no-acls /g' "$_l2r_bin"
fi
break
done
# Size-based rotation for the PBS API logs — the upstream package
# ships no logrotate rule and pvestatd's local-datastore poll fills
# them fast enough to saturate a tmpfs /var/log.
if dpkg-query -W -f='${Status}' proxmox-backup-server 2>/dev/null \
| grep -q 'install ok installed'; then
mkdir -p /var/log/proxmox-backup/api 2>/dev/null || true
cat > /etc/logrotate.d/proxmox-backup-api <<'EOF'
/var/log/proxmox-backup/api/access.log /var/log/proxmox-backup/api/auth.log {
size 20M
rotate 3
compress
delaycompress
missingok
notifempty
copytruncate
}
EOF
chmod 0644 /etc/logrotate.d/proxmox-backup-api
chown root:root /etc/logrotate.d/proxmox-backup-api
cat > /etc/cron.hourly/proxmox-backup-logrotate <<'EOF'
#!/bin/sh
/usr/sbin/logrotate /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1
EOF
chmod 0755 /etc/cron.hourly/proxmox-backup-logrotate
chown root:root /etc/cron.hourly/proxmox-backup-logrotate
msg_ok "$(translate "PBS API log rotation configured (hourly, size-based)")"
fi
systemctl daemon-reload >/dev/null 2>&1 || true
systemctl enable --now log2ram >/dev/null 2>&1 || true
@@ -2620,13 +2698,10 @@ EOF
if [[ "$ENABLE_AUTOSYNC" == true ]]; then
cat > /usr/local/bin/log2ram-check.sh <<'EOF'
#!/usr/bin/env bash
# v1.2 — `log2ram write` only copies tmpfs→disk; it does NOT shrink
# the tmpfs. When journald or pveproxy/access.log grow past their
# limits the tmpfs hit 100% and PVE crashed with "No space left on
# device" on Shell open (community-reported: JC Miñarro, Nicolás P.
# de A., 17-18/05). We now vacuum the journal and truncate the
# non-rotating logs that actually consume the tmpfs before calling
# `log2ram write`.
# Watch /var/log usage on Log2RAM's tmpfs and act at two thresholds:
# > 80% → vacuum journald down to ~30% of SIZE, then log2ram write
# > 92% → aggressive: journal to ~5%, rotate PBS API logs if present,
# truncate pveproxy/pveam, then log2ram write
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
CONF_FILE="/etc/log2ram.conf"
L2R_BIN="$(command -v log2ram || true)"
@@ -2646,15 +2721,13 @@ LOCK="/run/log2ram-check.lock"
exec 9>"$LOCK" 2>/dev/null || exit 0
flock -n 9 || exit 0
# `log2ram write` alone leaves the tmpfs full. Real recovery requires:
# (a) journal vacuum — journald respects --vacuum-size unconditionally,
# unlike SystemMaxUse which only enforces on rotation boundaries;
# (b) truncating logs that aren't rotated by logrotate (pveproxy, pveam);
# (c) THEN syncing to disk so the persistent copy reflects reality.
if (( USED_BYTES > EMERGENCY_BYTES )); then
SAFE_JOURNAL_MB=$(( SIZE_MiB * 5 / 100 ))
[[ "$SAFE_JOURNAL_MB" -lt 16 ]] && SAFE_JOURNAL_MB=16
journalctl --vacuum-size="${SAFE_JOURNAL_MB}M" >/dev/null 2>&1 || true
if [[ -x /usr/sbin/logrotate && -f /etc/logrotate.d/proxmox-backup-api ]]; then
/usr/sbin/logrotate -f /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1 || true
fi
: > /var/log/pveproxy/access.log 2>/dev/null || true
: > /var/log/pveproxy/error.log 2>/dev/null || true
: > /var/log/pveam.log 2>/dev/null || true
@@ -2763,64 +2836,37 @@ EOF
setup_persistent_network() {
local FUNC_VERSION="1.0"
local FUNC_VERSION="1.1"
# description: Pin NIC names to MAC addresses via systemd .link files so kernel updates don't shuffle interface names.
local LINK_DIR="/etc/systemd/network"
local BACKUP_DIR="/etc/systemd/network/backup-$(date +%Y%m%d-%H%M%S)"
local pve_version
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
msg_info "$(translate "Setting up persistent network interfaces")"
sleep 2
# Detect legacy `/etc/network/interfaces` setups that depend on the
# default udev naming. If the file references `allow-hotplug` rules
# or uses physical interface names directly, the .link rules below
# could rename interfaces and break network on reboot. Warn loudly so
# the user can review before continuing. Audit Tier 6 —
# `setup_persistent_network` no detecta conflicto con legacy.
if [[ -f /etc/network/interfaces ]]; then
if grep -qE '^[[:space:]]*allow-hotplug[[:space:]]' /etc/network/interfaces 2>/dev/null; then
msg_warn "$(translate '/etc/network/interfaces uses allow-hotplug. Renaming interfaces via systemd .link can break that flow — review the file after reboot.')"
fi
fi
mkdir -p "$LINK_DIR"
local count=0 removed_stale=0 removed_legacy=0
while IFS='=' read -r key value; do
case "$key" in
COUNT) count="$value" ;;
REMOVED_STALE) removed_stale="$value" ;;
REMOVED_LEGACY) removed_legacy="$value" ;;
esac
done < <(pmx_setup_persistent_network)
if ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
mkdir -p "$BACKUP_DIR"
cp "$LINK_DIR"/*.link "$BACKUP_DIR"/ 2>/dev/null || true
if (( removed_legacy > 0 )); then
msg_ok "$(translate "Migrated") $removed_legacy $(translate "legacy .link file(s) to the ProxMenux-managed format")"
fi
# Process physical interfaces
local count=0
for iface in $(ls /sys/class/net/ | grep -vE "lo|docker|veth|br-|vmbr|tap|fwpr|fwln|virbr|bond|cilium|zt|wg"); do
if [[ -e "/sys/class/net/$iface/device" ]] || [[ -e "/sys/class/net/$iface/phy80211" ]]; then
local MAC=$(cat /sys/class/net/$iface/address 2>/dev/null)
if [[ "$MAC" =~ ^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$ ]]; then
local LINK_FILE="$LINK_DIR/10-$iface.link"
cat > "$LINK_FILE" <<EOF
[Match]
MACAddress=$MAC
[Link]
Name=$iface
EOF
chmod 644 "$LINK_FILE"
((count++))
fi
fi
done
if [[ $count -gt 0 ]]; then
if (( removed_stale > 0 )); then
msg_ok "$(translate "Reconciled") $removed_stale $(translate "stale entry/entries for interfaces no longer present")"
fi
if (( count > 0 )); then
msg_ok "$(translate "Created persistent names for") $count $(translate "interfaces")"
# In PVE9, systemd-networkd is the native network backend and udev processes
# .link files directly. Reloading udev rules makes the new .link files effective
# immediately for any interface added later (hotplug, new NICs) without waiting
# for a full reboot. On PVE8 (ifupdown2), names are resolved at boot anyway.
if [[ "$pve_version" -ge 9 ]]; then
udevadm control --reload-rules 2>/dev/null || true
msg_ok "$(translate "PVE9: udev rules reloaded — new interfaces will get correct names without reboot")"

View File

@@ -455,11 +455,14 @@ uninstall_network_optimization() {
systemctl disable --now proxmenux-fwbr-tune.service >/dev/null 2>&1 || true
rm -f /etc/systemd/system/proxmenux-fwbr-tune.service
rm -f /usr/local/sbin/proxmenux-fwbr-tune
rm -f /etc/udev/rules.d/99-proxmenux-fwbr-tune.rules
udevadm control --reload-rules >/dev/null 2>&1 || true
systemctl daemon-reload >/dev/null 2>&1 || true
sysctl --system >/dev/null 2>&1 || true
msg_ok "$(translate "Network optimizations removed")"
register_tool "network_optimization" false
}
@@ -573,22 +576,28 @@ uninstall_log2ram() {
################################################################
uninstall_persistent_network() {
local LINK_DIR="/etc/systemd/network"
msg_info "$(translate "Removing all .link files from") $LINK_DIR"
sleep 2
if ! ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
msg_warn "$(translate "No .link files found in") $LINK_DIR"
return 0
msg_info "$(translate "Removing ProxMenux persistent NIC .link files...")"
sleep 1
if ! type pmx_uninstall_persistent_network &>/dev/null; then
if [[ -f "$LOCAL_SCRIPTS/global/utils-install-functions.sh" ]]; then
source "$LOCAL_SCRIPTS/global/utils-install-functions.sh"
fi
fi
rm -f "$LINK_DIR"/*.link
local removed=0
while IFS='=' read -r key value; do
[[ "$key" == "REMOVED" ]] && removed="$value"
done < <(pmx_uninstall_persistent_network)
msg_ok "$(translate "Removed all .link files from") $LINK_DIR"
msg_info "$(translate "Interface names will return to default systemd behavior.")"
if (( removed > 0 )); then
msg_ok "$(translate "Removed") $removed $(translate "ProxMenux-managed .link file(s). User-authored .link files were left in place.")"
msg_info "$(translate "Interface names will return to default systemd behavior.")"
NECESSARY_REBOOT=1
else
msg_warn "$(translate "No ProxMenux-managed .link files found — nothing to remove.")"
fi
register_tool "persistent_network" false
NECESSARY_REBOOT=1
}
@@ -906,6 +915,10 @@ uninstall_zfs_arc() {
rm -f /etc/modprobe.d/99-zfsarc.conf
msg_ok "$(translate 'ZFS ARC config removed (kernel defaults will apply on reboot)')"
fi
update-initramfs -u -k all >/dev/null 2>&1 || true
if command -v proxmox-boot-tool >/dev/null 2>&1; then
proxmox-boot-tool refresh >/dev/null 2>&1 || true
fi
register_tool "zfs_arc" false
}